小议提高电子邮件送达率的方法

2015.06.12/2016.08.15发布于研究暂无评论/目录

简要总结通过SPF + DKIM + DMARC等技术提高邮件送达率的方法,备忘。

最近VPS服务器发送的logwatch邮件被gmail服务器当作垃圾邮件拒收了,不是被扔到垃圾箱里,而是直接悲剧的给退回了。之前还能用gmail的过滤器把邮件从垃圾箱里拾回来,现在可好,连破烂都没得捡了。

查阅了网上的一些资料后,发现设置SPF和DKIM可以有效的降低邮件被识别为垃圾邮件的几率,遂实践了一番,下面总结记录SPF, DMARC的设置方法和在Ubuntu 14.04服务器上为Exim4启用DKIM支持的流程。

SPF

SPF全称是Sender Policy Framework,简单的说就是在你域名的DNS服务商那里添加一条TXT记录来检验发件地址(bounce address)。

SPF配置举例

以Godaddy为例,添加一条TXT记录:

Host TXT Value
@ v=spf1 a -all
  1. v=spf1定义该SPF记录的版本号
  2. a表示使用该域名的A记录和AAAA记录[1]来获取对应的IP。
  3. -all表示如果邮件的bounce address域名对应的IP不在第2条的范围内,则拒收该邮件。

SPF记录语法简介

详细的SPF记录的语法可参考官方的语法介绍这篇文章,以下仅选择性的介绍一下。

SPF记录的开头都是版本号,目前就是v=spf1。其后跟着一个或多个Mechanisms,Mechanism用于匹配发件地址的IP并给出处理建议。

常见的Mechanism如下:

Mechanism 说明
all 匹配所有的IP,通常放在最后
ip4 定义IPv4地址范围
ip6 定义IPv6地址范围
a 匹配同一域名的A记录或AAAA记录
mx 匹配同一域名的mx记录
include 使用另一个域名的SPF记录

Mechanism通过一个前缀符号来定义对匹配IP的处理建议,例如上面例子里的-all

Mechanism前缀 处理建议
+ * Pass,通过
- Fail,拒绝
~ SoftFail,通过但作标记
? Neutral,中立

如果有多个Mechanism,每个Mechanism会依次被执行,如果匹配到了发件地址的IP地址,则由对应Mechanism的前缀来给出处理建议(如果没有前缀,默认是+)。如果所有的Mechanism都没有匹配到,则建议是Neutral(?)。

一般来说:

  • SPF记录的处理结果仅仅是个建议,最终要由你的邮件服务商来判定邮件是否为spam。
  • 邮件服务商在实现SPF的时候检查的是bounce address的域名,而不是From邮件头里的域名,一般使用Return-Path(来自SMTP协议的MAIL FROM命令)。[2]

DKIM

DKIM全称是DomainKeys Identified Mail,简单的说,DKIM会通过非对称加密算法来验证邮件来源的真实性和邮件内容的完整性。

DKIM流程简介

DKIM的验证流程大致如下[3]

  • 发出邮件时:
    1. 选用某种加密算法计算邮件内容的hash。
    2. 使用密钥加密hash。[4]
    3. 添加一个名为DKIM-Signature的邮件头来保存加密后的hash和其他相关的参数。
  • 服务器收到邮件后:
    1. 根据DKIM-Signature邮件头的参数(s和d),查询发件人对应子域名的TXT记录。
    2. 使用TXT记录里返回的公钥对DKIM-Signature邮件头里的hash进行解密。
    3. 使用相同的加密算法计算邮件内容的hash并与上一步的结果进行比对。
    4. 比对成功则验证通过。

Exim4配置DKIM

需要注意的是,Exim 4.70+才支持DKIM功能。

首先生成一对密钥,至少要1024位。(以下命令省略sudo)

# 将密钥放置到exim4的配置目录里
cd /etc/exim4
# 生成密钥
openssl genrsa -out dkim.private.key 2048
# 提取公钥
openssl rsa -in dkim.private.key -out dkim.public.key -pubout -outform PEM
# 只允许exim4服务的用户访问密钥
chown `ps -eo uid,gid,comm | grep exim4 | awk '{print $1":"$2}'` dkim.*.key
chmod 600 dkim.*.key

首先确保你的Exim4已经正确配置且能够正常发送邮件。

dpkg-reconfigure exim4-config

然后修改Exim4的配置,如果你的Exim4使用了split file配置,需要修改/etc/exim4/conf.d目录下的相关配置,如果使用single file配置,需要修改/etc/exim4/exim4.conf.localmacros[5]

修改的内容都是相同的,以下以split file配置为例说明。

# 添加一个macro定义文件
cat >> /etc/exim4/conf.d/main/00_exim4-config_macros << EOF
DKIM_CANON = relaxed
DKIM_SELECTOR = 201506121205
DKIM_PRIVATE_KEY = /etc/exim4/dkim.private.key
DKIM_DOMAIN = \${lc:\${domain:\$h_from:}}
EOF

其中,DKIM_SELECTOR可以任意设置,但是之后设置DNS的TXT记录时需要保持一致。详细的配置说明可参考官方文档

然后更新配置文件并重启exim4服务。

update-exim4.conf
service exim4 restart

最后在你的域名服务商那里配置DKIM的DNS记录,添加一条TXT记录。

Host TXT Value
201506121205._domainkey v=DKIM1; k=rsa; p=XXXX

这里的Host就是之前配置的DKIM_SELECTOR + ._domainkey,如果你的DKIM_DOMAIN是个子域名,比如mail.mydomain.com,那么Host改为201506121205._domainkey.mail即可。TXT Value里的p=XXXX就是你的公钥,需要注意的是,用你的公钥替换XXXX的时候不要有空格和换行

# 使用输出替换TXT Value里的XXXX,拷贝的时候不要有空白字符
grep -v -- '^----' /etc/exim4/dkim.public.key \
    | tr -d '\n' \
    | sed 's/$/\n/'

2048位的公钥长度将超过 一条TXT记录的长度上限(255),但是有的域名服务商支持一次添加多条记录值,有的域名服务商则不支持。此时,要么把域名托管到别的域名服务商(比如godaddy的offline dns服务),要么换1024位的密钥。

DMARC

全称是Domain-based Message Authentication, Reporting & Conformance,简单的说就是综合利用SPF,DKIM以及From邮件头来进行邮件验证。

启用DMARC验证要求邮件确实是从你域名下的服务器发出的,启用前请确认SPF或DKIM已正确配置。

DMARC配置举例

和SPF类似,启用DMARC需要在你的域名服务商那里配置一条TXT记录。

Host TXT Value
_dmarc v=DMARC1; p=quarantine; rua=mailto:me@mydomain.com

TXT Value中:

  • v=DMARC1表示DMARC记录的版本号。
  • p=quarantine表示建议隔离验证失败的邮件,通常意味着扔到垃圾箱里。
  • rua=mailto:me@mydomain.com表示寄送验证报告到该邮箱,这个不是必需项。

DMARC记录语法简介

详细的DMARC记录语法介绍可参考rfc74896.3节,这里仅简要介绍常用的几个配置:

以下称From邮件头里发件人的域名为作者域名(author domain)。

Tag Name 是否必需 说明
v 版本号,目前是DMARC1
p 对作者域名及其子域名下的验证失败的邮件的处理建议
aspf 是否严格匹配SPF验证的结果,默认是r(relaxed模式)
adkim 是否严格匹配DKIM验证的结果,默认是r(relaxed模式)
rua 报告发送地址
sp 对所有子域名下的验证失败的邮件的处理建议,默认和p相同

具体说明:

  1. p的值有以下选项,具体如何操作还得看你的邮件服务商如何实现:

    • none: 无建议。
    • quarantine: 建议隔离验证失败的邮件。
    • reject: 建议拒收验证失败的邮件。

    如果作者域名是子域名,比如mail.mydomain.com,则Host可定义为_dmarc.mail,该子域名的DMARC配置会覆盖mydomain.com的配置。

  2. aspfadkim的值有以下选项,用于定义bounce address域名(由SPF验证),DKIM_DOMAIN和作者域名匹配的严格程度:

    • r: relaxed模式,子域名也认为是匹配成功。
    • s: strict模式,域名必须完全相同。

    例如,mail.mydomain.commydomain.com两个域名在relaxed模式下是匹配的,但在strict模式下是不匹配的。

    需要注意的是,aspfadkim仅对当前域名有效,当前域名的子域名依然会使用默认值r。如果子域名需要设为strict模式,需要专门配置子域名的DMARC记录,例如:

    Host TXT Value
    _dmarc.subdomain v=DMARC1; p=reject; aspf=s; adkim=s

只要下面任一验证通过,DMARC验证即可通过。

  • SPF验证通过,且bounce address和作者域名匹配。
  • DKIM验证通过,且DKIM_DOMAIN和作者域名匹配。

其他方法

设置PTR记录

PTR记录用于反向域名解析,即使用IP查询域名, PTR记录一般在你的VPS服务商那里设置。

常见VPS服务商的PTR记录设置方法:

  • Linode: Linodes => Remote Access => Reverse DNS
  • 阿里云: 据说要开工单请客服帮忙设置。。。

检查设置效果和查错

使用mail-tester检查设置效果

mail-tester服务可以全方位的对你的邮件进行评分。

使用Gmail检查设置效果

假设你的email地址是me@gmail.com,域名是mydomain.com。

发送一封邮件试下,如果SPF和DKIM都已生效,则Gmail会显示邮送域和署域都是mydomain.com。

echo hello | mutt -- me@gmail.com

使用查看原始邮件功能可以看到一个Authentication-Results邮件头,全部验证成功则显示如下:

Authentication-Results: mx.google.com;
       spf=pass (google.com: domain of ...(此处省略若干字)
       dkim=pass header.i=@mydomain.com;
       dmarc=pass (p=NONE dis=NONE) header.from=mydomain.com

查错

试着做如下检查:

  1. 检查DNS记录是否生效。

     # 检查SPF记录
     dig -t txt mydomain.com +short
    
     # 检查DKIM的TXT记录,DKIM_SLECTOR配置见上文
     dig -t txt 201506121205._domainkey.mydomain.com +short
    
     # 检查DMARC的TXT记录
     dig -t txt _dmarc.mydomain.com +short
    
     # 检查PTR记录,假设发件服务器的IP是a.b.c.d
     dig -x a.b.c.d +short
    

    确认公钥里没有空格和换行符。

  2. 检查是否启用了IPv6而没有在DNS服务商那里配置AAAA记录。

参考资料


  1. 如果VPS服务器上启用了IPv6支持,记得为你的域名也配置AAAA记录。

  2. SPF FAQ:Envelope from scope, 引用于2015-06-13.

  3. 详细介绍可参考DKIM#How it works

  4. 加密后的hash还要使用Base64进行编码。

  5. Exim4的配置说明可参考Debian Wiki:Exim

#DKIM#SPF#debian#email#exim#ubuntu

评论