Exim 报 syntax error in public key record:检查 DKIM TXT 中的分隔符
Exim 验证 DKIM 报公钥记录语法错误时,检查实际 selector、标签分号和同一 TXT 的分段拼接,保留与私钥匹配的公钥并核对发布结果。
邮件带有 DKIM-Signature,DNS 也能查到公钥,Exim 验证却报 syntax error in public key record。如果 TXT 开头写成 k=rsa,p=...,应先修正标签之间的分隔符:DKIM 的 tag=value 列表使用分号,逗号不能替代分号。
这篇针对 Exim 4 与 BIND 9 等 DNS 服务发布的 RSA DKIM 公钥记录。当前 Exim 中,pubkey_syntax 表示公钥记录语法无效;其他验证失败仍需按具体原因处理,不能仅凭邮件有签名就认定公钥已经正确发布。
查询签名实际使用的 selector
从待验证邮件的 DKIM-Signature 中核对 d= 和 s=。例如签名域为 example.com、selector 为 mail2026,公钥查询名是 mail2026._domainkey.example.com.。不要只查询域名根部 TXT,也不要用另一套 selector 的记录判断当前签名。
以下是只读查询示例,服务器与域名均须替换:
dig @ns1.example.com mail2026._domainkey.example.com. TXT +norecurse
dig mail2026._domainkey.example.com. TXT
第一条用于查看选定权威服务器,第二条查看当前递归解析路径。应确认查询确实得到目标区域的权威回答,并核对所有权威服务器。如果权威数据已改而递归仍旧,继续检查缓存有效期;如果查询不到公钥,先处理名称、发布或解析问题。
查看 Exim 中该签名的具体验证原因。pubkey_unavailable 是没有取到公钥,bodyhash_mismatch 与邮件正文变化有关;这些分支不会因为改 TXT 分隔符一并解决。
一条 TXT 可以包含多段字符串
DNS 的单个 character-string 内容最多为 255 字节,一条 TXT 记录可以包含多段。DKIM 会把同一条记录的字符串按顺序拼接,段间不添加空白。因此查询结果出现相邻的多个引号字符串,本身不证明记录损坏。
下面仅展示 BIND 静态区域文件的结构,PUBLIC_KEY_PART_1 和 PUBLIC_KEY_PART_2 是占位文字,不能直接发布:
mail2026._domainkey.example.com. 1800 IN TXT (
"v=DKIM1; k=rsa; p=PUBLIC_KEY_PART_1"
"PUBLIC_KEY_PART_2"
)
拼接后的 p= 必须是实际 RSA 公钥所需的完整 Base64 数据,不能带 PEM 头尾、漏字符或加入占位符。这里的分段并非建立两条 TXT;同一个 selector 下的公钥 TXT 必须唯一,不能把公钥的前半段与后半段各建成一条记录。
如使用 DNS 面板,按面板对引号、自动分段和换行的规定填写,再查实际返回值。BIND 区域文件的括号与引号是文件表示语法,不应整段照搬到所有面板。
先修分隔符,保留原来的公钥
检查拼接后的完整值,标签应以 ; 分隔。v=DKIM1 是推荐的版本标签;若出现,必须位于首个标签。未写版本标签默认按 DKIM1 解释,所以给错误记录加上版本,并不能修复仍存在的逗号。
还要检查重复标签以及 p= 是否完整。空的 p= 表示撤销公钥,不能为了清掉语法错误而把它留空。只修正发布格式时,应保留与签名私钥对应的公钥,不重新生成密钥再期待旧邮件签名通过。
不要为了缩短记录改用弱 RSA 密钥,也不要关闭 DKIM 验证掩盖问题。需要轮换密钥时,另按邮件系统支持的轮换流程管理新旧 selector,不能把格式修正与密钥替换混成一次操作。
发布后验收真正的签名结果
修改前保存现有记录、TTL、区域版本和对应签名配置。静态 BIND 文件按既有流程检查、更新 SOA serial 并加载;动态区域或托管面板则使用其管理入口。区域语法通过,只能说明 DNS 能加载记录,不能替代 DKIM 公钥解析和签名验证。
确认各权威服务器提供完整且唯一的目标 TXT,待实际递归解析路径得到新值后,用正常邮件流程核对对应签名是否通过。如果错误变成签名不匹配,应继续检查公钥与私钥、签名域、selector 和邮件修改情况。
回退时恢复已保存且仍与签名配置匹配的正确记录,并按区域版本与发布流程重新生效。已经缓存的数据不会因回退立即消失,保留变更时间和验证结果,避免在不同 DNS 版本之间反复换钥。


