如果你自建过邮件服务器,迟早会撞上这么一堵墙:邮件明明发出去了,日志里显示250 OK,可对方就是收不到。打电话一查,退信躺在对方邮件管理员手里,上面写着550 5.7.1 Message rejected as spam。第一次遇到这种事的反应基本都是——我的服务器是不是被拉黑了?其实大多数情况下,不是你的 IP 在黑名单里,而是对方邮件网关在“验明正身”环节,没验出你的发件身份凭证,直接把你的邮件判定成了伪造邮件地址。
这个场景,凡是跑过 Postfix、Exchange 或任何自建邮件系统的人多少都经历过。今天我想好好聊一聊邮件被拒收这件事背后的完整链路,从原理到配置,从错误码到实测修复,把“自检的邮件服务器发送的邮件可能被拒收”这个现象讲透。这篇文章适合三类人:刚把邮件服务器搭起来、正在为发信进垃圾箱发愁的新手;公司的邮服运维想彻底搞清楚 SPF、DKIM、DMARC 三者关系的半老手;以及单纯想知道“为什么大厂能发进来、我的不行”的普通用户。
1. 被拒收的真相:邮件网关把你当成了伪冒发件人
1.1 你发出的信,源头被“信任层”拦住了
先说结论:自建邮件服务器发信被拒收,九成跟垃圾内容无关,而是因为接收方无法验证“这封邮件真的是你这个域名发出来的”。
邮件系统从诞生那天起就带着一个先天缺陷——SMTP 协议本身不校验发件人身份。你可以在自己的电脑上随便发一封MAIL FROM: ceo@example.com的邮件,对方服务器不会阻止你,因为 SMTP 是纯文本命令,谁都能伪造。为了对抗这种伪造,业界在 2000 年后逐步补上了三层认证:SPF、DKIM、DMARC。现在主流邮件服务商如 Gmail、Outlook、QQ 邮箱、网易、腾讯企业邮,都会对入站邮件执行这三层检查。
问题就出在这里:很多自建服务器只配置了基础的 SMTP 收发,没有同步发布 SPF 记录、没有配置 DKIM 签名、也没有 DMARC 策略。于是当邮件到达 Gmail 或 Outlook 的网关时,网关发现“这个域名声称它发了信,但没有任何凭证能证明”,RFC 里的默认逻辑就是按伪造处理——直接拒收,或者扔进垃圾箱。
这不是偶尔抽风,是每天都在发生的事情。我见过不止一个公司的业务邮件被 QQ 邮箱拒收,用户反馈“你们是不是没给我发?”结果后台日志显示对方服务器返回554 5.7.1 Retry was not successful,原因就是 SPF fail。
1.2 “伪造邮件地址”在技术上是如何被定义的
我们先从报文层面理解伪造。一封邮件有两个发件人概念:一个是信封发件人(MAIL FROM指令里的 Return-Path),一个是信头发件人(From:头字段)。普通用户看到的是后者,而邮件网关检查的是前者与域名的匹配关系。
SPF 检查的是信封发件人。流程是这样的:对方邮件服务器收到你的邮件后,会查你域名在 DNS 里的 TXT 记录,如果写着“允许 IP 1.2.3.4 发送本域名的邮件”,而你这封邮件的来源 IP 恰好是 1.2.3.4,SPF 就 pass;如果不是,那就是 fail。DKIM 检查的则是邮件头部是否带着一个用私钥签名过的DKIM-Signature字段,对方通过 DNS 找到你的公钥来验签,能验过说明这封信确实经过了你的服务器。
这个机制补上了 SMTP 的漏洞,但也把“身份凭证没配齐”的自建服务器推向了对立面。你以为自己在正常发信,但在对方网关眼里,你和他见过的那些垃圾邮件群发 bot 没有任何区别——都在用别人没有授权的域名发信。所以后续所有拦截手段都合理了。搞清楚这一点,后续配置才有方向:不是去跟对方网关注册什么白名单,而是把自己的“身份凭证”补齐。
1.3 常见被误判的三种情况
我总结下来,自建邮件服务器被判定为伪造的典型情况就三种:
- 整个域名没有任何 SPF 记录。接收方查不到 TXT 记录,直接按 fail 处理。这是最普遍也最致命的问题。
- 有 SPF 记录,但漏了发信源的 IP 或子域名。比如公司网站用第三方营销邮件服务发送
news@example.com,SPF 里只列了自建服务器的 IP,漏了营销平台的那段 IP,对方一查就是 fail。 - DKIM 签名配置了,但 DNS 里没有发布公钥,或选择器(selector)对不上。签名无效等于没签,照样 fail。
下面几个章节,我从最基础也最关键的 SPF 开始,逐一讲清楚每条记录怎么写、为什么这么写、以及我踩过的坑。
2. SPF:用一条 TXT 记录圈定“谁有权替你发信”的边界
2.1 SPF 语法拆解:一条记录里到底写了什么
SPF(Sender Policy Framework)本质是一条 DNS TXT 记录,普通得不能再普通,但它的内容决定了所有接收方对你的第一印象。典型的记录长这样:
v=spf1 mx ip4:203.0.113.10 include:_spf.example.net -all我们来拆解一下:
v=spf1:声明这是一条 SPF 记录,版本号必须是这个。mx:允许 MX 记录指向的服务器作为发件源。如果你的域名的邮件收发都走同一台服务器,这个机制很实用。ip4:203.0.113.10:直接指定一个 IPv4 地址段作为合法来源。支持ip4:1.2.3.4/24这样的 CIDR 写法。include:_spf.example.net:把另一个域名的 SPF 记录完整包含进来。如果你用了第三方邮件平台,通常会用它提供的这条 include。-all:兜底规则。意思是“除了上面列的,其余全部判定为失败”。这是最严格也最推荐的方式。
与-all相对的是~all(软失败,标记为可疑但不直接拒收)和+all(全部通过,千万不能这么写,等于敞开大门)。
2.2 写 SPF 最容易翻的车:少了发件源
我见过最典型的翻车场景是:公司有主邮件服务器跑在阿里云 ECS 上,SPF 里只写了v=spf1 ip4:ECS_IP -all。看起来没问题,但后来市场部接了一个线索管理工具,用这个工具以公司域名给客户发跟进邮件,结果大量退信。
退信原因就是 SPF fail——线索工具的服务器 IP 不在允许列表里。这种情况要么让市场工具改用自有域名子域名(比如marketing.example.com),要么在 SPF 里加上对应的include段。很多第三方发送工具都有自己的 SPF 配置说明页,你要做的是打开工具的帮助文档,把它的 include 段复制进自己的 SPF。这里最需要注意的是:每次新增发信源,都去更新 SPF,并且发布后用工具检查一遍,否则“发不出去”的锅永远甩给你。
还有一个容易忽略的点:邮件服务器常常会用本机 hostname 所在域名发 HELLO 命令,但实际发件域名又是另一个。SPF 只关心信封域名(Return-Path 的域名),和 From 头域名无关。如果你用noreply@example.com发信,但服务器的 MX 记录和 hostname 都在mail.example.net,只要 SPF 里没有授权 mail.example.net 的 IP,照样失败。
2.3 SPF 的有效性判断结果
当接收方完成 SPF 检查后,会得到一个结果,常见的有:
| 结果 | 含义 | 接收方通常的处理 |
|---|---|---|
| pass | 来源 IP 匹配,身份验证通过 | 正常投递 |
| fail | 来源 IP 未被授权,明显伪冒 | 拒收或垃圾箱 |
| softfail | ~all场景,不能确定但可疑 | 可能需要额外分析 |
| neutral | 记录存在但没说明是否允许 | 继续其他检查 |
| temperror | DNS 临时故障,查不到记录 | 通常会继续检查,可能延迟 |
| permerror | SPF 记录语法错误 | 按 fail 处理 |
我的建议是,先用dig TXT example.com看看自己的 SPF 记录是否真实存在、语法是否正确。很多自建邮服的问题就出在“根本没人写过这条记录”。
2.4 实操:用 dig 验证并发布 SPF
发布 SPF 不复杂,在 DNS 管理后台给域名加一条 TXT 记录,主机记录填@或留空(取决于面板),记录值填v=spf1 mx ip4:你的IP -all,TTL 可以是 300 或 600,等 DNS 生效后用dig确认:
dig TXT example.com +short输出里应该出现你的记录。接着可以再用nslookup -type=TXT example.com复核。这里有一个容易踩的坑:有些域名注册商的 DNS 面板会自动把 TXT 记录加引号,你复制的时候要确保不要把多余的引号或空格带进去,否则语法解析会出问题。
SPF 记录的总长度不能超过 255 字符,如果 include 太多超过限制,DNS 会因为无法完整解析而导致 SPF permerror。如果你用了多家第三方发信平台,建议尽量让它们改用子域名发送,而不是把所有 include 全塞进主域名的 SPF。
3. DKIM:把“防伪签章”贴进邮件头部
3.1 DKIM 的工作过程和它解决的本质问题
SPF 解决的是“从哪个服务器发出的”,它有一个天然的短板:如果发件域名和服务器 IP 都是被允许的,SPF 只能证明服务器有发送权,不能证明送达过程中邮件内容没有被篡改。你需要 DKIM。
DKIM(DomainKeys Identified Mail)的原理和电子合同签章很像:发件服务器用私钥对邮件内容(包括正文和关键头部)做哈希签名,生成一个DKIM-Signature字段,附加在邮件头部。接收方收到邮件后,通过 DNS 查询到发件域名的公钥,对签名进行验签。如果验签通过,不仅证明邮件确实来源于该域名授权的服务器,还说明内容在传输过程中没有被改动。
对自建邮件服务器来说,DKIM 是花费最少、收益最明显的一项配置:只要密钥对生成好、DNS 记录发布好、服务器签名功能打开,绝大多数主流邮箱就能判定为 pass。
3.2 手把手:用 OpenDKIM 生成和配置签名
以最常见的 Postfix + OpenDKIM 组合为例,步骤如下:
- 安装 OpenDKIM:
apt install opendkim opendkim-tools- 生成密钥对。这里需要先规划一个选择器(selector),它是 DNS 记录里的一个名称,标识“用哪套公钥验证我的签名”。我习惯用域名年份方式,比如
default:
mkdir -p /etc/opendkim/keys/example.com cd /etc/opendkim/keys/example.com opendkim-genkey -s default -d example.com -b 2048-b 2048指密钥长度。以前大家用 1024 位,现在建议至少 2048 位,部分大厂已经开始拒绝验证 1024 位的 DKIM 签名。
- 生成完毕后,目录里会有两个文件:
default.private(私钥)和default.txt(公钥,用于发布到 DNS)。私钥文件权限要收紧:
chown opendkim:opendkim /etc/opendkim/keys/example.com/default.private chmod 600 /etc/opendkim/keys/example.com/default.private- 配置 opendkim.conf,把例子里注释掉的
KeyTable、SigningTable、InternalHosts路径指向你的配置目录。然后在/etc/opendkim/signing.table写上:
* example.com default:example.com:/etc/opendkim/keys/example.com/default.private这样所有来自本服务器的邮件都会用 example.com 的密钥签名。
- 重启服务,再在 Postfix 主配置文件里挂上 milter:
smtpd_milters = inet:localhost:8891 non_smtpd_milters = inet:localhost:8891 milter_default_action = accept需要确认你的 opendkim 监听端口和 socket 类型,默认是inet:8891或local:/var/run/opendkim/opendkim.sock,配置要一致。
3.3 DNS 侧的公钥发布与常见错误
下一步是发布公钥。打开default.txt,你会看到类似这样的内容:
default._domainkey IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC..."在 DNS 管理后台添加一条 TXT 记录,主机名填default._domainkey,记录值填引号里的全部内容(去掉最后一段反引号)。注意这个记录名里有一个下划线,不要漏掉。
DNS 生效后验证:
dig TXT default._domainkey.example.com +short接下来很容易翻车的地方有三个:
- 选择器不一致:签名时代理用的 selector 是
default,DNS 查询必须是default._domainkey.example.com。很多人在 DNS 台上不会填,结果配成了example.com._domainkey.default.example.com,查询不到公钥,验签必然失败。 - TXT 记录长度超出限制:2048 位密钥的公钥字符串很长,DNS 系统会把长 TXT 记录自动拆成多段,复制的时候要确保粘贴完整,最好把引号里的内容整体拷贝,不要只复制第一段。
- DNS 缓存:新发布的 DKIM 记录可能过几个小时才在全球生效。验证完马上发信测,有可能查不到,别急着改配置。
3.4 验证签名是否生效:看邮件头
配置完签名后,发一封测试邮件给一个你能查看原始邮件头的邮箱(Gmail 可以,QQ 邮箱也可以)。在 Gmail 里打开邮件,点击“显示原文”,在邮件头里找Authentication-Results行:
dkim=pass header.i=@example.com header.s=default header.b=xxxxdkim=pass就是验证通过。如果显示dkim=fail或dkim=neutral,优先检查的是记名选择器、公钥发布是否完整,以及服务器时间是否准确——DKIM 验签对时间戳比较敏感,服务器时间偏差超过五分钟就会出问题。
4. DMARC:告诉对方收到可疑邮件时怎么处理
4.1 DMARC 的定位:策略层的一句话
SPF 和 DKIM 分别从“来源 IP”和“签名验签”两个维度证明身份,但接收方拿到的结果是两个孤立的 pass/fail 信号。它还需要一个决策层告诉它:如果两个都失败,该怎么处理?是放行、扔垃圾箱、还是直接拒收?这个决策层就是 DMARC(Domain-based Message Authentication, Reporting & Conformance)。
DMARC 通过 DNS 里的 TXT 记录发布一套策略。它还有一个关键概念叫对齐(alignment):不仅要求 SPF/DKIM 通过,还要求通过后对应的域名和用户看到的From:头域名一致。防止你用一个合法域名的 SPF 来发送另一个域名的邮件。
DMARC 记录典型结构:
v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; pct=100; adkim=s; aspf=s逐项解释:
p:策略。none只观察不处理;quarantine有疑问的邮件进垃圾箱;reject直接拒收。刚开始上线建议用none,观察一段时间再收紧。rua:接收汇总报告(XML 格式)的邮箱,定期收到来自各大邮件服务商的认证数据。ruf:接收失败报告(forensic report)的邮箱,会收到具体某封邮件为什么失败。pct:策略应用比例,100表示全部邮件都执行策略。adkim、aspf:对齐模式。s(strict)要求完全一致,r(relaxed)允许子域名差异。多数场景用r更省心。
4.2 上线 DMARC 的正确姿势:先观察再收紧
我给所有自建邮件服务器的建议都是:不要一上来就写p=reject。虽然reject的防护最强,但如果你自己的 SPF 或 DKIM 还有没覆盖到的场景,比如某个老系统走了第三方 SMTP、某个外包的客户关系管理系统用自己的服务器发信,reject会直接把这些邮件的投递路径切断。
推荐分三步走:
- 第 1~2 周:
p=none。通过rua收报告,看看真实流量里有百分之多少的邮件没有通过 SPF/DKIM。报告可以用dmarcian或者postmark的 DMARC 报告解析工具来看,不用自己解析 XML。 - 第 3~4 周:
p=quarantine。让失败邮件进垃圾箱,观察有没有用户抱怨“正常邮件不见了”。如果有,回头补 SPF/DKIM 配置。 - 一个月后:
p=reject。确认所有合法发信都能通过认证后,才能把策略拉满。
这个过程我走过了无数次。基本上一个大坑是:某部门用了子域名发信,但父域名的 DMARC 只写了p=reject,子域名的aspf=r情况下可能还能放宽,但很多运维不区分,直接把子域名的合法信也拒了。建议及时查看rua报告里 report 中的 hostname 和 source ip,能帮你定位具体是哪个发信源在失败。
4.3 子域名的 DMARC 覆盖规则
一个容易忽略的知识点:DMARC 对子域名有继承策略。如果example.com写了一条p=reject,理论上mail.example.com、newsletter.example.com等子域名如果没有自己的 DMARC 记录,会继承父域名的策略。这导致很多公司的主域名配置收紧后,子域名的合法邮件也跟着遭殃。
解决办法是在子域名单独发布更宽松的 DMARC 记录,比如先把子域名的p设为none:
v=DMARC1; p=none; rua=mailto:dmarc@example.com或者干脆用sp标签(subdomain policy)单独声明子域名策略:父域名记录里写sp=reject; p=none,意思是主域名收紧、子域名单独执行别的策略。这个小标签每次我看配置清单都会重点核对一遍,因为它藏得最深。
5. PTR 与 HELO 主机名:IP 声誉的最后一块拼图
5.1 反向 DNS(PTR)为什么会影响拒收
说完三大认证,还有一个经常被人忽略、却直接影响拒收概率的环节:PTR 记录,也就是反向 DNS。接收方邮件服务器在完成 SPF/DKIM/DMARC 检查后,还会对你的来源 IP 做一次反向解析:拿着你的 IP 去 DNS 里查PTR记录,得到你的反向域名;然后正向解析这个反向域名,看它是否解析回同一个 IP。
为什么这很重要?因为垃圾邮件群发器几乎不会给服务器 IP 配 PTR 记录。如果你有一个干净的 IP 和正确的 PTR,接收方会认为你是“正规经营的邮件服务商”;反之,没有 PTR 或 PTR 和服务器 HELO 主机名不匹配,很可能直接被多家邮件服务商列入低信誉池,连前面辛苦配置的 SPF/DKIM 都来不及起作用。
我在真实排障时遇到过一个典型案例:自建邮服发出的邮件,在 Gmail 那边偶尔正常、偶尔进垃圾箱,查了半天没找到原因,最后用nslookup -type=PTR 你的IP一看,反向记录指向的域名是一个云服务商默认生成的、和他毫无关系的域名。差得不是一星半点。让机房加上一条 PTR,之后进垃圾箱的概率大幅下降。
5.2 HELO/EHLO 主机名必须和 PTR 对齐
SMTP 会话时,你的服务器会在 EHLO 里向对方报一个主机名。这个主机名必须是合法的、和 PTR 记录一致的域名,不能是裸 IP。比如 PTR 是mail.example.com,那 EHLO 就必须是mail.example.com。
对应到 Postfix 配置:
myhostname = mail.example.com smtp_helo_name = mail.example.com如果你用mail.example.com做服务器名和 PTR,但发件信封域名是example.com,也没有关系——SPF 检查的是信封域名,PTR 检查的是服务器 IP 和主机名,两者不是同一个东西。只要各自都配置正确,链路就能通过。
很多自建服务器默认的 myhostname 是类似localhost.localdomain或裸 IP,这就是典型的“身份线索缺失”。你连自己叫什么都没说清楚,对方凭什么信任你?检查一下 Postfix 的myhostname,别让它用默认值。
5.3 IP 纯度和信誉的冷知识
选择自建邮服用的 IP 时,也建议做一下 IP 历史信誉检查。你可以用senderscore.org或者各大服务商提供的工具查 IP 信誉。新买的云服务器 IP 往往是“二手”的,之前可能被别人用来发过垃圾邮件,历史信誉就差。即使你所有技术配置都完美,接收方依然会根据 IP 历史记录降低对你的信任等级。
有一个对自己发件很友好的做法:尽量让邮服使用独立的、干净的 IP,而不是和公司其他业务网站共享同一个 IP。很多第三方营销平台也会建议用户用独立 IP,因为共享 IP 里只要有人信誉差,全池都会被牵连。
6. 从退信错误码到完整修复:一次典型拒收的排查链路
6.1 拒收错误码的解读:550 5.7.1 与 554 的差别
自建邮服的拒收最终会以退信或日志错误的形式反馈到你这里。读懂错误码是排障的第一步。
550 5.7.1 Message rejected as spam:最常见,通常代表 SPF/DKIM/DMARC 有一项或多项 fail。Gmail 和 Outlook 尤其喜欢用这个错误码。554 5.7.1 Retry was not successful:含义比较宽泛,可以直接对应到 SPF fail 或 DMARC reject。很多网关会在邮件正文里附加具体原因,要连着上下文一起看。421 4.7.0:临时性拒绝,可能是 IP 信誉或频率限制,过段时间再试可能就成功。451 4.3.2:服务器内部繁忙或 DNS 查询超时,多数是对方问题,但也有可能是你发送频率过高。
拿到错误码后,第一件事是去翻邮件头的Authentication-Results。这行记录是对方服务器对你的认证判断的“直接口供”。比如:
Authentication-Results: mx.google.com; spf=fail (google.com: domain of no-reply@example.com does not designate 198.51.100.2 as permitted sender) smtp.mailfrom=no-reply@example.com; dkim=pass header.i=@example.com; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=example.com这个信息量已经很大了:SPF fail 了,DKIM pass 了,DMARC 最终 fail(因为 SPF fail 且未对齐)。你要修复的目标很明确:把 SPF 里的 IP 198.51.100.2 加进去,或者调整对齐方式。
6.2 用 mail-tester 做一次全链路体检
排查最有效率的方式是借助在线工具。www.mail-tester.com是我用过最顺手的免费工具——它会给你一个临时测试邮箱地址,你用自建邮服给那个地址发一封测试邮件,它会在页面上呈现出 SPF、DKIM、DMARC、PTR、黑名单、邮件头规范度等一系列评分。每一项都会有明确解释“为什么扣分”“该怎么改”。
我一般把它当成发布配置后的“验收标准”。每次改完 SPF、DKIM 或 DMARC,都发一封测试邮件看评分。从 4 分提高到 9 分以上,才意味着你的邮件基本可以被主流邮箱正常接收。得分低于 6 分时,优先去看看“黑名单”那一项,如果 IP 被列入几个常用的公开黑名单,再完美的认证配置也会大打折扣。
mail-tester的页面下方还会列出具体的邮件头,我习惯直接对比它显示的Authentication-Results和自己预期是否一致,能快速定位是 DNS 没生效还是签名没挂上。
6.3 一个完整的排障案例:从退信到落地的每一步
我拿一个典型的公司场景完整走一遍流程,你可以直接对号入座。
背景:客户新买了台云服务器自建 Postfix,发往公司主邮箱,大约 30% 邮件进入垃圾箱,有时直接退信。错误码是550 5.7.1 Message rejected as spam。
排查步骤:
- 在服务器本机查看日志:
tail -f /var/log/mail.log发现投递过程中对方返回554 5.7.1,说明被网关拦截。
用
dig TXT example.com +short查 SPF,发现根本没有 SPF 记录。这是第一个问题。查 DKIM,
dig TXT default._domainkey.example.com +short返回空,说明即便服务器上配置了 OpenDKIM,公钥也没有发布到 DNS。查 PTR:
dig -x 云服务器IP +short得到的是一个无关域名,显然是机房默认生成的。需要联系云服务商提交反向解析工单,把 PTR 改成mail.example.com。修复:发布 SPF 记录
v=spf1 mx ip4:云服务器IP -all;生成 DKIM 密钥并发布公钥;补上 DMARCv=DMARC1; p=none先观察;提交 PTR 工单。再次测试:用
mail-tester复测,第 1 项 SPF pass,第 2 项 DKIM pass,第 3 项 DMARC pass,总分从 3.5 提到 9.8。退回的比率直接清零。
修完之后你会发现,之前层层叠叠的“发不出去”“进垃圾箱”问题,往往都被这几个基础配置一揽子解决。自建邮件服务器不是一个“搭起来就能用”的软件,它是一个需要持续维护和验证身份的系统工程。
6.4 踩过坑后的几条实操清单
最后分享几条我每次为新邮服上线都会走一遍的检查清单,算是给自己留的规矩:
- 先查 SPF 再配置别的。没有 SPF 记录,后面都白搭。SPF 里务必包含所有发信源的 IP/域名。
- DKIM 选择器统一登记。把各域名的 selector 和 DNS 记录主机名整理成表格,避免配错或忘记发布。
- DMARC 必须和 SPF/DKIM 一起更新。DMARC 的策略生效前提是前两项认证都已经稳定 pass,否则很容易误伤。
- PTR 工单要提前提。很多云厂商自动生成的反向解析记录不满足要求,人工改通常要 1~2 个工作日,别等被拒收才去申请。
- 日志一定要开 verbose。Postfix 的投递日志是排查拒收的第一手材料,配合
mail-tester的邮件头分析,基本五分钟就能定位问题。
还有一点值得单独强调:邮件服务器的认证不是“配一次就永久有效”。你的include可能过期、第三方平台的 SPF 段可能变更、DKIM 私钥可能过期——至少每季度自查一次 DNS 记录,用mail-tester发一封测试邮件看评分趋势,能省掉很多临时救火的时间。
自建邮件服务器这条路,技术栈其实不复杂,真正复杂的反而是这些看不见的“身份细节”。我见过太多人花大力气调反垃圾策略、加内容过滤,最后发现问题居然只是自家 SPF 写少了 IP。先从伪造邮件地址的视角重新审视自己的服务器,你会少走很多弯路。