邮件进了垃圾箱?把 SPF、DKIM、DMARC 三条记录配齐(2026 实操)

站点通知发出去,用户说没收到,你去邮箱一看,全在垃圾箱里。这种事的根源几乎都不在 WordPress,而在域名这边少了三条记录:SPF 告诉收件方「哪些 IP 可以替我发信」,DKIM 给每封信盖一个可验证的签名,DMARC 则要求前两项至少有一项跟 From 里的域名对得上。

三个都没配,Gmail 和 Outlook 对你的域名基本没有信任可言,进垃圾箱算客气的。配齐之后,同样的 postfix、同样的 wp_mail,送达率会明显不一样。

三条记录各管什么

  • SPF:一条 TXT,列出发信 IP 或服务商,收件方用信封发件人(Return-Path)去比对
  • DKIM:发信时用私钥签名,公钥挂在 selector._domainkey.你的域名 上,收件方拿它验签名
  • DMARC:要求 SPF 或 DKIM 的域名跟 From 头里的域名对齐,并告诉你验证失败该怎么处理

很多人只配了 SPF 就去查为什么没用。SPF 只看信封发件人,转发一次就断了;DKIM 跟着邮件正文走,能扛住转发,两个一起配才稳。

前置条件

一台能发信的服务器(本站是 CentOS 7 加 postfix),域名 DNS 有修改权限,root 权限。如果 DNS 托管在 Cloudflare,注意后面「常见坑」里那条代理设置。

第一步:先查现在的状态

别急着加记录,先看清楚已经有什么。

dig +short TXT 你的域名
dig +short TXT default._domainkey.你的域名
dig +short TXT _dmarc.你的域名

三条都空,说明什么都没配。只有第一条有内容,那是 SPF,DKIM 和 DMARC 还缺着。

顺手查一下 SPF 里的 include 数量:

dig +short TXT 你的域名 | grep spf1

一条 SPF 记录里最多允许 10 次 DNS 查询(include、a、mx、redirect 都算一次),超了会返回 permerror,等于白配。用小服务商邮箱、又接了统计和工单系统的时候特别容易踩。

第二步:配 SPF

主机自己发信,最简单的一条:

v=spf1 mx -all

mx 表示域名 MX 指向的机器可以发,-all 表示其余一律不认。如果还在用第三方代发,往里加 include:,比如 include:_spf.google.com。

-all 是硬拒绝,~all 是软失败(标记但不拒)。自己发信、源头清楚就用 -all,还在摸发信链路就先用 ~all 观察几天。

一个域名只能有一条 SPF 记录。看到两三条 TXT 都写着 v=spf1,收件方直接判 permerror,必须合并成一条。

第三步:装 OpenDKIM 并签名

CentOS 7 的软件源里没有 opendkim,要先开 EPEL:

yum install -y epel-release
yum install -y opendkim

生成密钥。selector 用 default 就行,换服务商的时候换个新 selector 便于平滑过渡:

cd /etc/opendkim/keys
opendkim-genkey -b 2048 -d 你的域名 -s default -v

会得到 default.private 和 default.txt,后者就是待发布的公钥。权限收紧:

chown opendkim:opendkim default.private default.txt
chmod 600 default.private

三张表各管一件事。KeyTable 说明私钥在哪:

default._domainkey.你的域名  你的域名:default:/etc/opendkim/keys/default.private

SigningTable 说明哪些发件人用这把钥匙,要注意开头得写 refile: 才支持通配:

*@你的域名  default._domainkey.你的域名

TrustedHosts 列出允许签名的本机地址:

127.0.0.1
::1
mail.你的域名
你的域名

/etc/opendkim.conf 里确认这几行生效:

Mode            sv
Socket          inet:8891@localhost
Selector        default
KeyTable        /etc/opendkim/KeyTable
SigningTable    refile:/etc/opendkim/SigningTable
InternalHosts   refile:/etc/opendkim/TrustedHosts

然后让 postfix 把信交给它:

postconf -e "smtpd_milters = inet:127.0.0.1:8891"
postconf -e "non_smtpd_milters = \$smtpd_milters"
postconf -e "milter_default_action = accept"
systemctl enable --now opendkim
systemctl restart postfix

milter_default_action = accept 这行别省。opendkim 挂了的时候,默认动作是 tempfail,所有信都会被暂时拒收,看起来像是「邮件服务突然全废了」。

公钥发布到 DNS,把 default.txt 里引号内的内容整段贴进去,注意 p= 后面那串 base64 不能有空格和换行:

主机记录:default._domainkey
类型:TXT
值:v=DKIM1; k=rsa; p=MIIBIjANBg...

第四步:上 DMARC,先观察再收紧

第一周一定用 p=none,只收报告不拦信:

主机记录:_dmarc
类型:TXT
值:v=DMARC1; p=none; rua=mailto:dmarc@你的域名

rua 是聚合报告地址,各大邮箱每天会发一份 XML 过来,能看清哪些 IP 在用你的域名发信、哪些验证没过。报告是 gzip 压缩的 XML,不好读,可以先丢进一个单独信箱,或者接一个解析服务看汇总。

观察一两周,确认自己的发信源全在通过列表里,再升级:

v=DMARC1; p=quarantine; rua=mailto:dmarc@你的域名

没问题再上 p=reject。跳过观察期直接 reject,很容易把自己的通知邮件一起拦掉,等到发现的时候已经丢了一批。

pct= 这个字段以前用来按比例灰度,各家执行得并不一致,别指望它精确控制。老实按 none → quarantine → reject 走。

验证是否真的生效

DNS 先确认能查到:

dig +short TXT default._domainkey.你的域名
dig +short TXT _dmarc.你的域名

再发一封测试信到 Gmail,打开「显示原始邮件」,找这几行:

Authentication-Results: mx.google.com;
       spf=pass smtp.mailfrom=你的域名;
       dkim=pass header.d=你的域名;
       dmarc=pass header.from=你的域名

三个 pass 才算通了。dkim 显示 none 是没签上,去 journalctl -u opendkim -n 50 看有没有报错;显示 fail 多半是 DNS 里的公钥贴漏了字符。

服务器本地也能直接确认签名有没有生成:

echo test | mail -s "dkim test" 你的邮箱
grep -i "DKIM-Signature" /var/log/maillog | tail -3

常见坑

  • DNS 在 Cloudflare,mail 子域开了橙云。代理模式会把邮件端口拦掉,mail.你的域名 必须是灰云,只代理网站主域。
  • DKIM 公钥贴错。dig 出来看到 p= 后面断成两段、或者带上了多余的空格引号,签名必然 fail。TXT 超过 2048 字符会被拆包,用 2048 位密钥时确认解析器拼得回去。
  • postfix 在 chroot 里。用 inet socket 而不是 unix socket,能少一类找不到 socket 的报错。
  • 改了 SPF 不生效。DNS 有 TTL,先 dig @8.8.8.8 和 dig @1.1.1.1 分别查,两边不一致就是还在等缓存,跟之前排查域名解析不生效是同一套思路。
  • 发信还是失败。先看wp_mail 报成功但信根本没出去那篇,本地 MTA 都发不出去的话,配 DNS 没有任何意义。

回滚

改动都在配置文件和 DNS,回滚很直接:_dmarc 先降回 p=none,SPF 从 -all 改 ~all,把 postconf 加的三行删掉再 systemctl restart postfix,DKIM 那几条 DNS 记录留着不影响发信,只是签名不再被验证。

出问题时最怕的是分不清「本地发不出去」和「发出去了但被判垃圾」。先看 maillog 有没有 status=sent,有就是后者,问题在域名信誉和认证,不在服务器。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容