自建邮件发送服务实战:PTR 反向解析、SPF/DKIM/DMARC 三件套与邮件送达率优化全流程

网站发不出邮件,问题往往不在代码里

几乎所有个人站长都会遇到同一个场景:网站需要发邮件——用户注册验证码、密码重置、评论回复通知、订单确认。你写好了 PHP 的 mail() 或者调用了某个 SMTP 类库,本地测试也通了,可上线之后用户反馈收不到邮件。你去垃圾箱里一看,邮件全在里面;再过几天,连垃圾箱都不进了,直接退信或者石沉大海。

这个问题的根源是:发邮件从来不是"把邮件交给 SMTP 服务器"这么简单,而是一整套关于身份认证和信誉的信任体系。收件方(Gmail、Outlook、QQ 邮箱)在收到你的邮件时,会做一长串检查:这封邮件声称的域名是不是真的?发信 IP 有没有被授权?域名有没有配置反垃圾策略?这个 IP 过去有没有发垃圾邮件的历史?任何一环不过关,邮件就会被拒收或者丢进垃圾箱。这篇文章把自建发信服务的完整流程讲清楚,包括最容易忽略的反向 DNS 和 IP 信誉问题。

第一步:先搞清楚"发送"和"投递"是两回事

新手最大的误区是认为 SMTP 服务器返回 250 OK 就代表邮件发出去了。其实 SMTP 的 250 响应只代表"我接下了这封邮件",至于收件方最终是否接收、是否丢进垃圾箱、是否退信,是后续异步发生的,你的服务器当时根本不知道。

整个流程是这样的:你的服务器把邮件交给你的 SMTP 服务器(比如 Postfix)→ Postfix 去查询收件方域名的 MX 记录 → 连接对方的邮件服务器 → 对方的服务器做一系列验证(SPF、DKIM、DMARC、IP 信誉、反向解析)→ 决定接收、拒收还是标记为垃圾邮件。如果决定接收,还会再发一封投递结果回执给你(延迟退信可能几小时甚至一天后才到)。

所以"排查邮件问题"的正确姿势是:看 Postfix 的日志,找到邮件被哪个环节拦下,而不是只看自己的代码有没有报错。tail -f /var/log/mail.log 是你最该熟悉的命令。

第二步:反向 DNS(PTR)是自建发信的生死线

这是 90% 的人都会忽略、但又是最致命的一环。绝大多数大型邮箱服务商(Gmail、Outlook、QQ 邮箱)会直接拒收没有正确配置反向解析的 IP 发来的邮件,连垃圾箱都不给进,直接回一个 550 拒收。

反向 DNS 是把 IP 地址反查回域名的记录,也就是 PTR 记录。普通 DNS 是"域名 → IP",PTR 是"IP → 域名"。因为你的 VPS 的 IP 是供应商分配的,所以 PTR 记录必须由你的 VPS 供应商来设置,你自己在域名解析后台改不了。这就是为什么很多人明明 SPF、DKIM 都配好了,邮件还是发不出去——他们的 PTR 记录还是供应商默认的 xxx.static.hostingprovider.com 这种,跟你的发信域名对不上。

正确做法是:在你的 VPS 控制面板里找到"设置反向 DNS / rDNS / PTR"的选项,把 IP 的 PTR 记录改成一个你自己的子域名,比如 mail.example.com。然后确保这个 mail.example.com 有一条 A 记录指回你的服务器 IP。这样就形成了"域名 → IP → 域名"的闭环,也叫"完全限定域名一致"。

验证方法很简单,在服务器上执行:

dig -x 你的IP +short
# 应该返回你设置的 mail.example.com
dig mail.example.com +short
# 应该返回你的IP

如果 dig -x 返回的是供应商的默认域名而不是你的,立刻去控制面板改。这一条改对了,邮件送达率往往立刻从"全进垃圾箱"变成"大部分进收件箱"。注意:新申请的 PTR 记录可能需要几小时到一天才能生效,改完别急着测,等一等。

第三步:SPF 记录防止别人冒用你的域名

SPF(Sender Policy Framework)的作用是声明"哪些 IP 有资格用我这个域名发邮件"。收件方收到邮件后,会检查发信 IP 是否在你域名的 SPF 记录里,不在就判定为伪造,直接拒收或丢垃圾箱。

SPF 记录是一条 TXT 记录,加在你的发信域名的 DNS 解析里。举例,假设你用 example.com 作为发信域名,只有你自己这一台 IP 为 203.0.113.10 的服务器发信,那么记录是:

example.com.  TXT  "v=spf1 ip4:203.0.113.10 -all"

如果同时用第三方邮件服务(比如 SendGrid、阿里云邮件推送)辅助发信,就要把它们的授权也加进去:

example.com.  TXT  "v=spf1 ip4:203.0.113.10 include:sendgrid.net -all"

几个必须记住的规则:一个域名只能有一条 SPF 记录,写两条会导致解析冲突、验证失败。SPF 里的 IP 段不能超过查询次数限制(10 次 DNS 查询),include 嵌套太多会超限。最后的 -all 表示"除了上面列出的,其余全部拒绝",比 ~all(软失败)更严格更安全,推荐用 -all。如果你的站用多个子域名发信,还要注意 SPF 记录是挂在具体域名上的,子域名的发信要用子域名自己的 SPF。

第四步:DKIM 给邮件加上数字签名

SPF 只能验证发信 IP,但邮件在传输过程中可能被篡改,而且转发后 SPF 往往失效。DKIM(DomainKeys Identified Mail)通过给邮件加数字签名来解决这个问题:你的服务器用私钥对邮件签名,收件方通过 DNS 里的公钥验证签名,就能确认这封邮件确实是你发的、且内容未被篡改。

配置 DKIM 的步骤:第一步生成一对密钥(公钥 + 私钥);第二步把私钥放到你的邮件服务器;第三步把公钥以 TXT 记录形式发布到 DNS,记录名通常是 selector._domainkey.example.com,其中 selector 是你自己起的名字(比如 mail 或 default)。

mail._domainkey.example.com.  TXT  "v=DKIM1; k=rsa; p=MIGfMA0GCSq...(公钥内容)"

用 OpenDKIM 或 Postfix 自带的 DKIM 支持都可以实现签名。关键点是 selector 要和发布到 DNS 的那个名字完全对应。很多人配完发现不生效,就是 selector 写错了。DKIM 记录有长度限制,公钥特别长时要拆成多段 TXT 记录,DNS 服务商一般会自动处理,但换服务商时容易出问题,迁移时要重新验证。

第五步:DMARC 是统管全局的策略

DMARC(Domain-based Message Authentication, Reporting and Conformance)建立在 SPF 和 DKIM 之上,它告诉收件方:"如果 SPF 和 DKIM 验证都失败了,你该怎么处理我的邮件(拒收 / 隔离 / 放行),并且把结果报告发给我。"

DMARC 记录也是一条 TXT 记录,加在 _dmarc.example.com:

_dmarc.example.com.  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com; pct=100"

这里 p=none 表示只监控不做处理,是上线初期应该用的策略——先观察一段时间,收集报告,确认 SPF 和 DKIM 都配置正确、没有误伤,再把 p 逐步升级到 quarantine(隔离到垃圾箱),最后到 reject(直接拒收)。rua 指定的邮箱会收到聚合报告,里面告诉你每天有多少邮件通过了验证、多少失败了、失败的原因是什么。

DMARC 的正确落地顺序是:先配 SPF 和 DKIM → 用 p=none 上线收集报告 → 分析报告修复问题 → 逐级升级策略。千万不要一上来就 p=reject,很容易把自己正常的业务邮件也拒掉了。

第六步:Postfix 最小可用配置

如果你决定自建 SMTP 服务器,Postfix 是最稳妥的选择。这里给出一份针对"只发不收"场景的最小配置(很多人的网站只需要发信,不需要收信,配置收信复杂度高很多)。

# /etc/postfix/main.cf 关键项
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = loopback-only
mydestination =
mynetworks = 127.0.0.0/8

# 通过受信任的中继或直接投递
smtp_tls_security_level = may
smtpd_tls_security_level = may

# 反向解析(rDNS)不匹配时不要拒绝自己
smtp_helo_name = mail.example.com

几个要点。第一,myhostname 必须是那个设置了正反向解析闭环的域名,不能随便写。第二,inet_interfaces = loopback-only 表示只接受本机(也就是你的 Web 程序)投递,不对外提供 SMTP 服务,这样避免被当成开放中继被人滥用。第三,smtp_helo_name 要设置成你的正规域名,因为很多收件方会检查 HELO 名是否和 PTR 记录一致,helo 名跟 PTR 对不上也会被扣分。

配置完成后,用命令行测试发信:

echo "测试邮件正文" | mail -s "测试主题" your-test@gmail.com
tail -f /var/log/mail.log

看日志里对方服务器的响应。如果看到 250 2.0.0 OK 说明对方接收了;如果看到 550 或 554 开头的拒收,就往上翻,看是哪个验证环节出了问题。常用的诊断命令还有 postqueue -p(查看队列中待发的邮件)和 postsuper -d ALL(清空队列,慎用)。

真实案例:一封验证码邮件为何全进垃圾箱

我帮一个站长排查过他的注册验证码全进垃圾箱的问题。他信誓旦旦地说 SPF、DKIM 都配好了,还给我看了 DNS 记录。我一看确实配了,但邮件还是进垃圾箱。于是我让他把邮件原文(Show Original)导出来,逐项看验证结果,发现问题出在两个地方。

第一,他的 myhostname 填的是 localhost.localdomain,导致发出去的邮件 HELO 名是 localhost.localdomain,跟他的 PTR 记录(供应商默认的一串域名)又不匹配,而且 HELO 名明显不合法,Gmail 直接给了超高的垃圾分。第二,他的 IP 是全新申请的,属于"零信誉 IP",Gmail 对全新 IP 会先观察一段时间,这个阶段邮件大概率进垃圾箱,需要用"预热"策略慢慢提升发送量。

修复动作有两步。第一步,把 myhostname 改成 mail.example.com,并去 VPS 面板把 IP 的 PTR 也改成 mail.example.com,形成正反向闭环。第二步,做 IP 预热:第一周每天只发几十封,第二周发几百封,逐步提升到正常量级,同时密切观察 Gmail Postmaster Tools 里的信誉分。大约三周后,他家邮件就开始稳定进收件箱了。这个案例说明:配置正确只是及格线,IP 信誉是需要时间养的,新 IP 一上来就群发,必进垃圾箱。

第七步:用工具验证和持续监控

配置好后,不要凭感觉,用工具验证。推荐几个免费好用的:一是 mail-tester.com,给它发一封邮件,它会给你的邮件打分(满分 10 分,低于 8 分说明有明显问题),并逐项列出 SPF、DKIM、DMARC、反向 DNS、黑名单检查的结果,非常直观。二是 Google Postmaster Tools,如果你经常给 Gmail 用户发信,可以在里面看到你的域名信誉分和垃圾邮件率,是长期运营的必备工具。三是 MXToolbox 的邮件头分析功能,粘贴邮件原文就能看到每个验证环节的通过情况。

持续监控方面,一定要定期检查自己的 IP 有没有被列入黑名单(Spamhaus、SORBS 等)。黑名单可以通过 MXToolbox 的 Blacklist Check 快速检查。如果被列入,通常是因为网站被入侵后被人利用来发垃圾邮件,或者同一个 IP 段有邻居在发垃圾邮件被连带。发现后要立刻排查服务器安全,找出被利用的漏洞,然后申请从黑名单移除。

总结

自建邮件发信服务,本质上是建立一整套"可信身份"。发出邮件只是最后一公里,前面是 PTR 反向解析、SPF、DKIM、DMARC 四道身份验证,后面是 IP 信誉这道需要时间积累的门槛。个人站长做这件事的价值在于:掌控自己的发信能力,不被第三方邮件服务的额度和价格卡脖子,也不再因为用户收不到验证码而流失注册量。

落地建议:先解决 PTR 反向解析闭环(这一步最多人漏,也最致命),再配 SPF 单条记录,然后用 OpenDKIM 加签名,最后用 DMARC 的 p=none 上线收集报告。服务器层面用 Postfix 的 loopback-only 最小配置,把 myhostname 设对。全部配好之后用 mail-tester 打分,低于 8 分就继续排查。新 IP 一定要预热,别急着群发。这套流程走完,你的网站发的邮件就能稳定进用户的收件箱了。

Last modification:October 8th, 2026 at 08:24 pm

Leave a Comment