Zimbra 的 SPF、DKIM 与 DMARC:自建服务器配置

Zimbra 自建邮件服务器的认证配置:用 zmdkimkeyutil 生成 DKIM、发布 UUID selector、用 opendkim-testkey 验证,以及不会打断内部邮件流的 DMARC 上线节奏。
5 分钟阅读
更新于 2026-11-04
平台专区
zimbra自建spfdkimdmarc

Zimbra 是仍在自己跑 MTA 的开源协作套件里最常见的一个,所以这里的认证不是点面板,是敲命令。好消息是工具都随 Zimbra 一起装了;坏消息是它生成的 selector 是一串没人记得住的 UUID,而真正能证明配置正确的验证步骤,几乎所有教程都跳过了。

以下假设你能以 zimbra 用户登录 shell,并且公网 DNS 已经能正常解析邮件主机的 MX 和 A。

Zimbra:UUID selector 与验证命令
opendkim-testkey 是唯一能证明密钥对匹配的手段。

第一步:SPF

单机部署、MX 同时负责发信时:

v=spf1 mx -all

这授权 MX 记录里的所有主机。写法紧凑,只要 MX 保持最新,换 IP 也不用改 SPF。一旦出现第二个发信源——另一台 IP 上的官网、应用中继、监控服务——就要写明确:

v=spf1 mx ip4:203.0.113.10 ip6:2001:db8::10 -all

出站走 smarthost 而不是直连的,mx 就是错的:要把中继的域 include: 进来,或者列出它的 IP。云主机 PTR 对不上时,常见做法就是走服务商的 SMTP 中继、只授权那一台。

-all 只在你能确定没有别的发信源时用。从别的平台迁过来期间先 ~all:域名上有一个没审计到的发信方,硬失败会静默丢掉客户邮件,而拒收发生在收件方,你的日志里队列还是成功的。

第二步:生成 DKIM

su - zimbra
/opt/zimbra/libexec/zmdkimkeyutil -a -d example.com

输出里有一个 selector(UUID,如 25D766CE-CEAC-11E7-B087-020B6DB9DD9A)和公钥签名。ZCS 8.7 起默认 2048 位。

在 SELECTOR._domainkey.example.com 发布 TXT:

25D766CE-CEAC-11E7-B087-020B6DB9DD9A._domainkey.example.com.  IN TXT (
  "v=DKIM1; k=rsa; "
  "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
)

这种多字符串写法是合法 DNS:解析器会把引号里的片段拼起来。网页面板多数要求一整段不带引号的值——整段贴进一个字段,让面板自己处理分段。唯一不能做的,是只贴第一段。

后面还会用到的几个操作:

/opt/zimbra/libexec/zmdkimkeyutil -u -d example.com   # 轮换密钥
/opt/zimbra/libexec/zmdkimkeyutil -q -d example.com   # 查看当前 selector 与密钥
/opt/zimbra/libexec/zmdkimkeyutil -r -d example.com   # 删除 DKIM 数据

第三步:验证密钥,不能只验证记录

这一步大多数教程跳过,而它恰恰能抓出 LDAP 里的私钥和 DNS 里的公钥不匹配:

dig TXT 25D766CE-CEAC-11E7-B087-020B6DB9DD9A._domainkey.example.com +short @ns1.example.com

/opt/zimbra/common/sbin/opendkim-testkey   -d example.com   -s 25D766CE-CEAC-11E7-B087-020B6DB9DD9A   -x /opt/zimbra/conf/opendkim.conf

opendkim-testkey 没有任何输出就是通过——退出码 0、一声不响。报 opendkim.conf line 0 的错误,说明 opendkim 服务没启用:

zmprov ms $(zmhostname) +zimbraServiceEnabled opendkim
/opt/zimbra/libexec/configrewrite opendkim

再跑一次。ZCS 8.6 及更早版本,二进制在 /opt/zimbra/opendkim/sbin/。

第四步:不留空档地轮换密钥

  1. 用 -a 生成新密钥,此时域名下有两个 selector。
  2. 把新 selector 的 TXT 发出去,等传播。
  3. 让 Zimbra 改用新 selector 签名(-u 或更新域名的 DKIM 设置)。
  4. 旧记录至少保留一周——用旧密钥签的信可能还在队列里、还在灰名单重试中。
  5. 窗口过后再删旧 selector。

立刻删旧记录,会让所有还在队列里的邮件验证失败。症状是很难查的"偶发 DKIM 失败",尤其在群发和延迟投递的邮件上。

第五步:DMARC

_dmarc.example.com.  IN TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com; ruf=mailto:dmarc@example.com; fo=1"

先把 rua 指向的邮箱建出来,并配好清理规则。聚合报告是每天每报告域一封带 XML 附件(常常是 gzip)的邮件,域名有一点年纪就是每月几百封。别手读,交给 DMARC 报告分析器。

Zimbra 本身不收 DMARC 报告,这个循环是纯手工的。p=none 跑 2–4 周,确认所有正常来源都对齐,再 quarantine、最后 reject。

一个 Zimbra 特有的注意点:服务器上托管多个域名时,每个域名都要有自己的 DKIM 密钥、SPF 和 DMARC。虚拟域如果沿用别人的 SPF,它自己 From 域的对齐就会失败。

第六步:从外部测试

发一封到 Gmail 看原始邮件头。再反过来从 Gmail 发给你每个 Zimbra 域,确认入站校验没有把自己的信判为可疑。

Authentication-Results: mx.google.com;
  spf=pass smtp.mailfrom=example.com;
  dkim=pass header.d=example.com header.s=25D766CE...;
  dmarc=pass header.from=example.com

header.s= 那个值必须是你确实发布过的 selector。如果显示的是轮换时删掉的那个,那就是空档期。

常见错误

  • 多段 TXT 只发了第一段。
  • 从不跑 opendkim-testkey,密钥不匹配一直隐形,直到别家拒信才发现。
  • 轮换时立刻删旧 selector。
  • 出站走 smarthost 却在 SPF 里用 mx。
  • 忘了虚拟域。每个域都要有自己那三条记录。

常见问题

selector 能不能改成好记的名字?

zmdkimkeyutil 生成的就是 UUID。改名意味着 LDAP 属性和 DNS 记录要同步改,技术上可行但不值得。selector 的可读性影响运维体验,不影响投递。

Zimbra 会自动给每个域名签名吗?

只要 LDAP 里有该域名的 DKIM 数据、opendkim 服务已启用,就会。没有 DKIM 数据的域名不签名,而且不会有任何提示——对每个托管域跑一次 zmdkimkeyutil -q -d 确认。

2048 位一定更好吗?

安全性上是的,但有个前提:2048 位会产出约 400 字符的 TXT 值。手工编辑 BIND zone 文件时要记得单字符串 255 字符的限制并正确分段,否则记录会静默变成畸形。

这篇指南有帮助吗?