特殊事件处理篇

mail server (MTA) 加上 SPF, DKIM, DMARC

寄信到 gmail 一直被档!说是垃圾信!好垃圾...原来是需要修改 DNS 呢!

最近更新时间: 2022/06/03

前阵子鸟嫂一直说,我们 mail server 的信件一直被 gmail 退信!鸟哥想说,这怎么可能!我们又不是垃圾发送站! mail server 里面似乎也没有什么怪异的用户。不过,既然有要求,那当然要设法解决!于是就发现了... 老天爷啊~ mail server 竟然真的被挡住了!而且,问题还不是 mail server!问题在 DNS 设置上! 这也太有趣了!

问题发生的状况说明

鸟哥之前待的实验室,因为信件容量的关系,所以不想要使用 gmail,而是自行搭建 mail server 来收发信件。 之前使用上都没有问题。不过,似乎从前几周开始,实验室伙伴寄信到 gmail 时,该信件会被踢回来! 这让鸟哥觉得怪!因为,没道理我们会被列为黑名单!真是太怪了!于是,跑去找 /var/log/maillog 的内容, 发现到底下的纪录:

to=<xxxx@gmail.com>, relay=gmail-smtp-in.l.google.com[142.250.157.26]:25, delay=4, 
delays=0.25/0.01/0.77/2.9, dsn=5.7.1, status=bounced (host gmail-smtp-in.l.google.com[142.250.157.26] 
said: 550-5.7.1 Our system has detected that this message is 
550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail, 550-5.7.1 
this message has been blocked. Please visit 550-5.7.1  
https://support.google.com/mail/?p=UnsolicitedMessageError 550 5.7.1  for more information.
f23-20020a631017000000b003f5e581cd89si1174487pgl.833 - gsmtp (in reply to end of DATA command))

看看关键字,还真的被当成垃圾邮件发送网站!这让我很不能接受!于是开始搜索 gmail 挡信的原因。 看起来,互联网上这个问题真的很严重!大家都发生过这个状况!鸟哥想说, gmail 是在大头症嘛?干麻挡人家? 后来查了查~似乎也不能怪人家!毕竟垃圾信件真的很多!如果不是很合法的邮件主机,那么抵挡住, 似乎也不是什么错误的事情。好吧!不怪你!怪我啦!

查找处理方案的过程

后来查到几篇写的挺清楚的文档,请到底下的参考数据查找相关网址。总的来说,就是目前的 gmail 以及主要的 mail server 群,为了担心系统被垃圾信件冲爆,所以设置了几个重要的查核点,可以帮助 gmail 验证发信站是否为合法的 mail server 这样。以前的检查很简单,只要有 MX 的 DNS 纪录,那就算是合法的 mail server 了。 但是 DNS 的 MX 设置也太简单!所以,后来就又衍生出许多的机制。大致上如下:(我们以 gmail 为收信站做例子)

  • SPF (Sender Policy Framework):寄件者政策框架

    当 gmail 收到一封信件后,他会检查这封信件的发送者。 然后找到这信件的发信站。SPF 就由 email (例如 userpig@example.com) 找到 example.com 这个 mail server 的来源,然后通过找寻 DNS 当中的 example.com 里面的 TXT 纪录, 当有 spf 的纪录值,而且这封信件是来自 spf 记载的合法的 mail server 寄出的,那就通过验证。

    因为我们经常会收到 email 是 userpig@example.com 的邮件,但是该邮件却是伪装的! 实际可能来自于 somewhere.com 的 mail server!这种情况下,通过 spf 就可以挡掉这种错误的信件问题。

  • DKIM (DomainKeys Identified Mail):网域验证邮件功能

    基本上,如同 ssh 的密钥系统一般,如果发信者/收件者之间,能够通过密钥系统进行加解密, 这样不是让邮件更安全!邮件数据更不容易被窃取与窜改!所以就有了这个 DKIM 的机制。 说穿了,基本上就是,先创建一对密钥,然后,通过 DNS 的设置,将公钥公开出去, 然后,寄件者寄出信件时,需要主动告知收信端的 mail server,要怎么用那一把公钥解密! 然后收信端才有办法用正确的公钥来解密。

    老实说,虽然这样信件的机密性比较好,不过,并非所有的 mail server 都知道怎么应用 DKIM 机制解密, 当然也就可能造成收件者只会看到一堆乱码的情境吧!同时,发信者也要在 MTA 上面设置好自动加密, 否则,发信也是挺麻烦的!除非是 gmail 的信箱寄到 gmail 的信箱,因为某些公司与 gmail 合作啊! 这样用他们家提供的成对密钥,就没啥大问题!不过,这部份你确实可以先略过!

  • DMARC (Domain-based Message Authentication, Reporting & Conformance):以领域名称为主的消息验证、报告与确认机制

    让接收端的邮件主机进行一些政策处理,主要在处理当一封邮件在 SPF 或 DKIM 处理失败后,应该如何应对的处理方式。

最需要知道的其实是 DMARC 这个机制!由 https://dmarc.org 官网的介绍,里面最重要的一张图如下所示,先看看下图,底下我们依序稍微解释一下:

DMARC 流程
DMARC 的运作流程
  • 第一横列与发信端 mail server 有关,用户先制作信件,然后发信时塞入 DKIM 的表头数据 (向收件端告知需要解密), 之后才送到邮件接收端的 mail server 上。
  • 第二横列主要跟收件端 mail server 有关,包括:发现使用 DKIM 的表头,就进行验证 DKIM 的密钥一致性,同时予以解密。 然后通过 SPF 的设置,确认发信端的来源 (一般指 IP) 是正确的,然后就开始带入 DMARC 的规则去处理这封邮件, 包括通过、隔离与退信等。
  • 以上任务确认完毕后,再带入后续的病毒分析、邮件过滤等流程。
  • 关于 DNS 的 TXT 设置

上述的动作几乎都与 MTA 设置无关,只与 DNS 纪录数据有关!相当有趣吧!mail server 的验证竟然是通过 DNS 呢! 而且还是当初我们觉得不是太重要的 TXT 纯文本信息哩!我们先来看一下 gmail.com 与 _dmarc.gmail.com 对于 TXT 的设置是什么在说:

[root@email ~]# dig -t txt gmail.com
;; QUESTION SECTION:
;gmail.com.      IN  TXT

;; ANSWER SECTION:
gmail.com.  300  IN  TXT  "v=spf1 redirect=_spf.google.com"

[root@email ~]# dig -t txt _dmarc.gmail.com
;; QUESTION SECTION:
;_dmarc.gmail.com.      IN  TXT

;; ANSWER SECTION:
_dmarc.gmail.com.  600  IN  TXT  "v=DMARC1; p=none; sp=quarantine; rua=mailto:mailauth-reports@google.com"

[root@email ~]# dig -t txt arc-20160816._domainkey.google.com
;; QUESTION SECTION:
;arc-20160816._domainkey.google.com. IN TXT

;; ANSWER SECTION:
arc-20160816._domainkey.google.com. 3600 IN TXT "k=rsa; p=MIIBI....."

基本上, spf 的设置与本身的邮件领域有关,至于 DMARC 则与『_dmarc.你的领域』有关!而 DKIM 设计比较难找~ 最简单的方法是,到你的 gmail 里面,随便找一封也是 gmail 的信件,然后在更多数据的地方选择『显示原始邮件』的数据, 整个画面流程有点像底下这样:

看 gmail 的原始邮件
看 gmail 的原始邮件
看 gmail 的原始邮件去找出 DKIM 的 selector 与 domain
里面就有可能会有类似底下的字样:

ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
        h=content-transfer-encoding:subject:date:importance:priority:to:from
         :mime-version:message-id;
        bh=tVI7M4hfPvo9bxH8oeJRhV5eTOcWtI6XVBVBDR9/HsE=;
        b=rcrYB6V7ELMApaI14jcsiwISIok/Ao3DabJ0upjQRzePXyDGYPMmJwYSsLFwBthYFq
         7yZiEjjy922ppaIwaVxg17YvyoYHT97U2XzHQ2qMlQYLqzXr39BHzS25keTPmeVcN001

里面那个 s=arc-20160816 指的是选择器 (selector),搭配 d=google.com 的领域名称,搭配 _domainkey 这个关键字, 最终就得到『 arc-20160816._domainkey.google.com 』这个领域名称了!再通过 dig 去追踪, 就可以得到 DKIM 的公钥数据!所以总结一下,你需要设置的三个领域的 TXT 项目,大致有:

  • SFP: 如 gmail.com, mail server 本身的网域名称
  • DMARC: 如 _dmarc.gmail.com, DMARC 搭配 mail server 网域的主机名称
  • DKIM: 如 arc-20160816._domainkey.google.com, DKIM 使用 selector 与 _domainkyey 搭配 google server 网域的主机名称

底下,就让我们一个一个来设置!还是得要说明,DKIM 不见得要设置,但是 SFP 与 DMARC 应该要处理妥当才好喔!

SPF, DKIM, DMARC 的基础设置

就让我们一项一项工作来处理!

  • 先设置发信站的 mail server 信任 IP 设置: SPF

根据 google 的文档说明, SPF 的实际作法可以参考底下的链接:

要达成上述的功能,你先要找到:

  • 你的 mail server 所在的 IP 地址。假如你有两部 mail server,分别在 192.168.0.1 以及 192.168.10.1 时, 那就可以简单的填写地址为:『 ip4:192.168.0.0/24 ip4:192.168.10.0/24 』这样。
  • 通常建议开放 gooogle 的网域,所以添加『 include:_spf.google.com 』
  • 另外建议再加上 a 与 mx 这两个参数,让与 mail server 有关的 A 与 MX 设置支持的 IP 也放行。

所以,针对 SPF 这个信任的发信端 mail server IP 设置当中,请修改你的 bind 设置档,以鸟哥来说, 假设整个 domain 就是 mail server 的 IP,那设置值可以是这样的:

[root@email ~]# vim /var/named/dynamic/named.your.domain
@  IN  MX 10   @
@  IN  TXT     "v=spf1 ip4:192.168.0.0/24 ip4:192.168.10.0/24 include:_spf.google.com a mx ~all"

这样就搞定了 SPF 了!其他更详细的设置,请自行参考上面的链接!

  • 再来处理 DMARC 的信件处理规则

信件通过 SPF 之后的处理规则,可以参考底下的数据设计:

基本上,就是添加一个 _dmarc.your.domain 的 DNS 纪录,我们不做任何设计...直接交给 mail server 去处理过滤即可! 你唯一要设计的,是将 DMARC 可能产生的报表数据管理员的 email address 填写进去即可。简单的设计可以是这样的 (跟前面一样,假设你的 mail server 就是整个网域!):

[root@email ~]# vim /var/named/dynamic/named.your.domain
_dmarc  IN   TXT   "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-reports@your.mail.server"
  • DKIM 密钥与选取器的设置

基本上,如果你寄出的 mail 表头没有额外指定,接收端的 mail server 并不会套用 DKIM 的项目。 但是,某些时刻,我们还是得要自制一下这个 public key 比较好!至少在进行某些测试时, 比较容易通过啦!呵呵!要自制密钥,可以前往底下这个网站自己处理好:

dkim 密钥系统
dkim 密钥系统
由 dkimcore 网站自制的 selector 与 domain

如上所示,你会制作出一个 1654239065.example 的选取器,以及领域名称为『 example.com 』的设置值。 然后,还会得到一组完整的 rsa 加密的哈希码,这样就可以拿来设计你的 DNS 了!设计如下:

[root@email ~]# vim /var/named/dynamic/named.your.domain
1654239065.example._domainkey.example.com. IN TXT "v=DKIM1;k=rsa;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNAD...."

特别注意,不要使用网页上面的格式!我们的 rockylinux 8 应该是支持非常长的字符串,所以,将全部的数据串在一起, 使用一对双引号涵盖即可。然后,特别加上 k=rsa 那一段!指定编码为 rsa 的意思!这样就搞定了全部的设置值了!

增加 gmail 的验证码

即使上面的 DNS 已经设置妥当,但是,某些 mail server 还是不买单的!例如 gmail 还是不买单... 其实不只 gmail 啦,比较大型的 mail server 供应商,基本上,都会要求寄信单位『验证』其正确性! 再次去查看 google.com 的 TXT 值,有点像这样:

[root@email ~]# dig -t txt google.com
;; ANSWER SECTION:
google.com.    3600    IN      TXT     "MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB"
google.com.    3600    IN      TXT     "docusign=1b0a6754-49b1-4db5-8540-d2c12664b289"
google.com.    3600    IN      TXT     "webexdomainverification.8YX6G=6e6922db-e3e6-4a36-904e-a805c28087fa"
google.com.    3600    IN      TXT     "docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e"
google.com.    3600    IN      TXT     "globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8="
google.com.    3600    IN      TXT     "v=spf1 include:_spf.google.com ~all"
google.com.    3600    IN      TXT     "facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95"
google.com.    3600    IN      TXT     "google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o"
google.com.    3600    IN      TXT     "google-site-verification=TV9-DBe4R80X4v0M4U_bd_J9cpOJM0nikft0jAgjmsQ"
google.com.    3600    IN      TXT     "apple-domain-verification=30afIBcvSuDV2PLX"

即使是 google,也得要对 facebook, apple 买单的!所以啦!不要愤愤不平!大家都一样 (这其实是对鸟哥自己说的...)。 好吧,想要让 gmail 不要退我们的信件,也只能够处理一下啦!请前往底下的网站 (你必须要拥有 gmail 的帐号), 然后准备入你的 mail server 吧!

在登录上述网页之后,按下『Get Started』之后,会进入到您管理的网站数据。 在整个浏览器右下方有个加号 (+),按下它!然后就会出现如下的画面:

gmail 验证码

输入你的 mail server 网域,就按下『 NEXT 』按钮。然后就会出现如下的画面:

gmail 验证码

你会看到 TXT record 那个项目!现在,先不要继续!先来搞定 DNS 的设置值:

[root@email ~]# vim /var/named/dynamic/named.your.domain
@ IN  TXT   "google-site-verification=UGFF_PfzUvg7WcJ8mhYlc3WNe8o0DKZNCqhSsHTQBbc"

[root@email ~]# systemctl restart named-chroot

修改你的 DNS 设置值,增加这一段设计在 TXT 的项目中,然后重新启动 DNS。要注意喔,那个 SOA 的序号一定要长大! 而且,注意你的 TTL 设置,一定要在超过 TTL 设置的时间之后,才回去按下 VERIFY 按钮! 否则,你刚刚的 DNS 设置,可能还没有被激活啊!要注意!要注意!

通过这样的设计,你的 mail server 应该不至于被 gmail 挡住了!而如果你又被其他 mail server 挡住, 大概只要重复这个验证码的步骤来处理即可。只是,得要到对方的网站去取得你的验证码啰!

测试设置值

上述功能处理完毕之后,先来查阅看看,我们的 mail server 是否真的设置妥当了!要注意喔, 你的 DNS 服务器重新启动之后,要超过 ttl 设置值,再来测试,会比较准。所以啰,这次的 mail server 问题, 其实要解决的是 DNS 的设置!哈哈哈!先来看一下第一个测试网站的测试结果:

要注意的是,输入的测试值应该是你的 domain name 才对!不过,如果你的设置主要是针对 mail server, 而且 mail server 并不是整体网域的话,那就输入你的 mail server 主机名称即可。基本上,会有个惊叹号, 显示『DMARC Policy Not Enabled』,那个应该是没关系!不用理会!除非有遇到其他『X』的符号,否则, 应该就是顺利过关!

另外一个检测的方式,是 google 自己提供的!前往底下的网址测试看看:

去到上面的网站,在网域名称填写你的 mail server 主机名称,然后在 DKIM 选取器填写刚刚我们在 DKIMcore 网站上面指定到的 selector,然后按下『运行检查』,最后就会出现一张报表, 报表里面没有出现重大错误即可!基本上,会有点像底下这样:

gmail 验证码

鸟哥自己认为第一个警示可以不用理他!因为鸟哥自己的 mail server 并没有跟 gmail 合作,所以出现第一个警告, 应该也是合理的!另外,那个 spf 的按钮可以按一下,确认你的发信 IP 以及 google 的 IP 而已。这样的整个流程, 你的 mail server 应该就不会被抵挡了!祝福各位!

参考数据

修改历史:
  • 2022/06/03:最近遇到被 gmail 退信的问题,找了找,终于找到解决方案!怕忘记,赶紧写一篇!
2022/06/03 以来统计人数
计数器
http://vbird.cn is designed by VBird during 2001~2022.