文章

域名邮箱

今天要把域名的Name Server(NS)从namesilo换成cloudflare,顺便把域名邮箱也切了过去。不如再顺便把去年搞的域名邮箱相关的书签清理掉。

为什么要切换NS?因为namesilo的NS实在没法跟cloudflare一较高下……

  1. Prerequisite
  2. 邮件的安全认证
    1. SPF
    2. DKIM
    3. DMARC
  3. 域名邮箱
    1. 邮件收发基本原理
    2. 域名邮箱方案
      1. 邮件接收:邮件转发
      2. 邮件接收:收发平台
      3. 邮件发送:别名邮箱
      4. 邮件接收:收发平台
  4. 其他
    1. 邮件中转记录
    2. 发件建议
  5. 感想

Prerequisite

邮件认证的方式主要有三种:

  • SPF
  • DKIM
  • DMARC

依赖域名的TXT记录来完成。

关于MX记录和TXT记录,参考Linux - dig & DNS

邮件的安全认证

SPF

Sender Policy Framework,发件人策略框架,用于验证发送邮件的服务器ip来自受信任的服务器

哪些服务器是受信任的服务器?域名里SPF策略记录的那些服务器就是受信任的服务器。

查看163.com的SPF记录,它用的是spf.163.com这个domain的规则:

1
2
3
4
5
[puppylpg:~]$ dig +short TXT 163.com
"57c23e6c1ed24f219803362dadf8dea3"
"google-site-verification=hRXfNWRtd9HKlh-ZBOuUgGrxBJh526R8Uygp0jEZ9wY"
"v=spf1 include:spf.163.com -all"
"qdx50vkxg6qpn3n1k6n1tg2syg5wp96y"

查看spf.163.com的规则,发现它又分成了a.spf.163.comb.spf.163.com等:

1
2
[puppylpg:~]$ dig +short TXT spf.163.com
"v=spf1 include:a.spf.163.com include:b.spf.163.com include:c.spf.163.com include:d.spf.163.com include:e.spf.163.com -all"

其中,a.spf.163.com包含一大堆ipv4的ip:

1
2
[puppylpg:~]$ dig +short TXT a.spf.163.com
"v=spf1 ip4:220.181.12.0/22 ip4:220.181.31.0/24 ip4:123.125.50.0/24 ip4:220.181.72.0/24 ip4:123.58.178.0/24 ip4:123.58.177.0/24 ip4:113.108.225.0/24 ip4:218.107.63.0/24 ip4:123.58.189.128/25 ip4:123.126.96.0/24 ip4:123.126.97.0/24 ip4:103.74.28.0/24 -all"

所有这些ip的服务器发送的邮件,都可以说自己来自@163.com,其他ip的服务器发的邮件如果也这么说,就会被收件服务器判定为非法。

如果有其他发件服务器声称自己From: 163.com,就会被收件服务器拒绝,因为它的ip不在spf.163.com所列的那些ip里。

但是SPF只能验证ip,相当于传统信封的封皮地址,不能验证邮件内容。必须和DMARC一起,才能验证出钓鱼邮件。比如,163的发件服务器发出一封邮件,From为163.com,内容原本写的是“请来163注册邮箱”。但内容在转发的途中可以被修改成“请来qq注册邮箱”,此时邮件的来源ip依然是163服务器的ip,SPF不能验证这一点。大意的用户可能就信了这是一封来自qq的邮件。

SPF是以DNS TXT record的形式记录在DNS里的。

DKIM

DomainKeys Identified Mail,域名密钥识别邮件,用来校验邮件是经过原始发件服务器授权的,且可以验证某些部分没有被篡改。收件方通过查询发件方的公钥做这些校验。

发件服务器比如163.com给发出的邮件的某些部分做电子签名,收件服务器收到163.com的邮件,先从163.com的DNS查到它的公钥,再拿公钥验签。如果通过,说明签名部分的内容没有被中间的转发服务器篡改。这些行为对终端用户一般不可见。

做DKIM校验的邮件的邮件头会有私钥生成的签名,写入DKIM-Signature header,比如:

1
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1624647686; s=m1; d=elastic.co; i=@elastic.co; h=Content-Type:MIME-Version:Subject:To:From:Date; bh=sDjq9gl31HAtML/Nbd8Y4Z08c3jiS9k9cjtFiTZrK9U=; b=k7ZiVMD8J3xE82ZOVGXbBWOAAzBbBNxsZMLGIo1/D66zw5ZF8CX84P1zcluGENNB cFEiJ+zxIgti86h7qDu1GtUMGftl1emPw0hwl67iYWYpTSRInC4RqixFpejSz9rylgZ dhvmdHP8PhnOR6BSGi0OLnEjP/3httZ3A/aLZ4Vs=

其中:

  • d:domain;
  • sselector,用于指定最终的域名,从该域名的TXT记录里可以获取public key信息
  • h:用于签名的header。From:是必须要有的,其他可选;
  • bh:body hash。未必是全文的hash,有可能截断到某个地方;
  • b最终的签名的base64形式。由body和选中的header生成;

其他kv对指定了其他细节,比如具体的签名算法等。

s + ._domainkey + .<domain> 就是获取公钥的域名。对于上面的签名例子,s是m1,domain是elastic.co,所以域名是m1._domainkey.elastic.co

1
2
[puppylpg:~]$ dig TXT m1._domainkey.elastic.co +short
"v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRuX6uJiu4rC0Ng4kUUFpS9UDVWEKHglP3qIETL720vy8G/ornMtb8THbuM0jhgKb575Yyd9rLNs1OCHhj+XpVt0Fhu2JkXOUNGG9iN6u1HjPokj3iRFNAqYl3xkFEOwjD+TmwYidiSVMZLElS2pZdDz2NdzMJDp8glCCaUnnoywIDAQAB"

其中:

  • v: version;
  • k: key type,其实就是公钥所用到的算法类型;
  • p:public key;

验签步骤:SMTP服务器收到邮件,做TXT记录查询,用到上述domain和selector,可以从返回结果中得到public key。

比如:用某网站查询工具查询上述public key,然后就可以用公钥验签了。

Ref:

  • https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail

DMARC

DMARC (Domain-based Message Authentication, Reporting and Conformance),基于域名的消息认证、报告、一致性。 SPF和DKIM提供了不同的验证机制,DMARC提供了一种机制,指定验证方式(SPF或DKIM或都要),如何检查From:,指定验证失败后的处理策略,如何上报这些行为等。

_dmarc + .<domain>就是查询DMARC策略的域名

1
2
[puppylpg:~]$ dig TXT _dmarc.elastic.co +short
"v=DMARC1; p=quarantine; pct=35; rua=mailto:postmaster@elastic.co"

其中:

  • v: version;
  • p: policy;
  • sp: subdomain policy;
  • pct: percent,邮件如果被判定为垃圾度超过阈值,则应用policy;
  • rua: 接收报告的地址;

Ref:

  • https://en.wikipedia.org/wiki/DMARC
  • https://www.mailgun.com/blog/deliverability/domain-reputation-and-dmarc/
  • https://work.weixin.qq.com/help?doc_id=524&helpType=exmail

域名邮箱

域名邮箱,即以自己的域名为邮箱后缀。比如我自己的域名puppylpg.xyz的域名邮箱就是@puppylpg.xyz

邮件收发基本原理

邮件发送主要是根据收件邮箱的域名,查询收件邮箱的域名的MX记录,找到邮箱收件服务器地址,然后使用smtp协议发送过去。

关于MX记录,参考Linux - dig & DNS

比如163发给gmail:

  1. 根据@gmail.com查询域名gmail.com的MX记录;
  2. 查到gmail收件服务器比如alt3.gmail-smtp-in.l.google.com
  3. 163发件服务器通过smtp协议发送邮件给刚刚查到的gmail收件服务器;

发送邮件还涉及到邮件认证,gmail服务器收到邮件后就会使用上面介绍的SPF、DKIM、DMARC等策略对邮件进行认证。能够通过认证的邮件被收件方标记为垃圾的可能性更低。

域名邮箱方案

理论上,想收发邮件需要自己部署邮件服务器。但一般不至于这么大动干戈,基本都是借用/租用别人的邮件服务器。

邮件接收:邮件转发

邮件转发可以在自己没有部署邮件服务器的场景下接收邮件。

比如我们想使用@puppylpg.xyz作为邮箱,但实际上并没有部署对应的邮件接收服务器,就只能通过一个邮件转发服务商:

  1. 把自己域名的MX记录设置为该转发服务商,比如cloudflare
  2. 发件服务器(比如163.com)在发送邮件给@puppylpg.xyz时,通过查询puppylpg.xyz的MX记录,找到了收件方为cloudflare,就把邮件发了过去;
  3. cloudflare收到该邮件,会按照我们在其上配置的映射(比如把pika@puppylpg.xyz转发给shininglhb@gmail.com),把邮件转发给gmail邮件服务器;

下面是把cloudflare配置为邮件中转的MX记录和SPF记录:

Record typeHostnamePriorityValueStatus
MXpuppylpg.xyz26route1.mx.cloudflare.netAdded
MXpuppylpg.xyz65route2.mx.cloudflare.netAdded
MXpuppylpg.xyz28route3.mx.cloudflare.netAdded
TXTpuppylpg.xyz v=spf1 include:_spf.mx.cloudflare.net ~allAdded

MX records allow your domain to receive email. The TXT record is configured to allow your domain to send incoming emails out to your preferred email provider.

cloudflare本身并不能发送邮件,所以加这个SPF记录并没有啥用……所以我又给删了……

设置后MX记录为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ dig MX puppylpg.xyz

; <<>> DiG 9.16.37-Debian <<>> MX puppylpg.xyz
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32237
;; flags: qr rd ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;puppylpg.xyz.                  IN      MX

;; ANSWER SECTION:
puppylpg.xyz.           0       IN      MX      26 route1.mx.cloudflare.net.
puppylpg.xyz.           0       IN      MX      65 route2.mx.cloudflare.net.
puppylpg.xyz.           0       IN      MX      28 route3.mx.cloudflare.net.

;; Query time: 1339 msec
;; SERVER: 172.26.240.1#53(172.26.240.1)
;; WHEN: Tue Mar 07 23:04:16 CST 2023
;; MSG SIZE  rcvd: 162

邮件接收:收发平台

除了cloudflare,namesilo本身也提供这些服务,还有mailgun、endgrid、postmark、sendinblue、migomail等更专业的邮件收发服务平台。mailgun作为专业的邮件收发平台,不止可以作为中转服务器,它自己也可以作为目的服务器,这样就可以集中转和收发件于一体,实际收发件服务器也都是mailgun自己的。

mailgun还提供了收发件的api,可以程序化发送邮件。

参阅:

邮件发送:别名邮箱

邮件转发(email forwarding)只能做到接收邮件,想发送邮件的话需要找一个能做email hosting的厂商。比如mailgun,本身就支持发件。

除此之外,还可以使用gmail的别名邮箱功能,把xxx@puppylpg.xyz邮箱绑定为gmail邮箱的别名,就可以在gmail里以xxx@puppylpg.xyz的名义发件了。

主要步骤是:

  1. gmail开启两步认证(2FA);
  2. gmail添加xxx@puppylpg.xyz作为别名邮箱;
  3. xxx@puppylpg.xyz会收到一封确认邮件(所以要先配置邮件转发,不然@puppylpg.xyz根本收不到邮件):是否让gmail添加你为别名邮箱;

确认之后,gmail就可以用xxx@puppylpg.xyz的名义发送邮件了……

比较奇怪的一个功能……跟上面的MX记录并没有什么关系。当时知道这个东西的时候震惊我一万年,但什么原理至今没搞懂。gmail发送的邮件是怎么通过spf/dkim/dmarc认证的?这个确认机制到底是什么机制?

(实测163邮箱授权gmail别名邮箱,gmail以163的名义发送邮件之后,163的已发送里并没有该邮件。)

参考:

  • https://support.google.com/mail/answer/22370?visit_id=637762916561277309-3645915374&hl=zh-Hans&rd=1
  • https://www.owo233.xyz/index.php/archives/75/
  • https://www.namesilo.com/Support/Gmail-Instructions-for-Reply~to-Using-Custom-Domain

邮件接收:收发平台

如果用mailgun发件的话则会专业一些(现在要收费了),要配置的东西也会更多一些。需要修改自己的域名:

  1. 增加TXT SPF记录为mailgun发件服务器(所以需要发件的服务器才需要设置SPF,上线cloudflare也让我加SPF记录就很迷);
  2. 增加TXT DKIM记录为mailgun公钥
  3. optional:增加TXT DMARC记录;

难得的是,mailgun支持子域名邮箱,比如@mg.puppylpg.xyz。这样只需对该子域名设置MX、TXT记录就行了。

收件——

MX:

1
2
3
$ dig MX mg.puppylpg.xyz +short
10 mxb.mailgun.org.
10 mxa.mailgun.org.

发件——

SPF:

1
2
$ dig TXT mg.puppylpg.xyz +short
"v=spf1 include:mailgun.org ~all"

DKIM:

1
2
$ dig TXT pic._domainkey.mg.puppylpg.xyz +short
"k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn9rosvzlLcT21TKh89No23Hp6adwpCHpPs2XtfQCuHAQ55h1T5urVV4oaqjol4h5nVmO6sYy94gJo7zfgDSPmiuZo4QA+1rZCGXY2GlS8y/vxx8lxLZ+evamlsGwHjIRhBh+qptAVKEswQEAeVUbWAADlGsto6sKG3oqXOfPNewIDAQAB"

DMARC:

1
2
$ dig TXT _dmarc.mg.puppylpg.xyz +short
v=DMARC1; p=none; pct=100; rua=mailto:re+felkad5zuuj@dmarc.postmarkapp.com; sp=none; aspf=r;

postmark有一个生成dmark的网站:A free weekly email to help monitor & implement DMARC

下面是gmail收到mailgun的邮件后显示的认证情况:

邮件 ID20220110082029.e772addef3bbc221@mg.puppylpg.xyz
创建时间:2022年1月10日 16:20(已在 1 秒后递送)
发件人:Excited User liuhaibo@mg.puppylpg.xyz
收件人:shininglhb@gmail.com, shininglhb@163.com
主题:Hello from mailgun api, dmark verification?
SPF:PASS,IP 地址:159.135.228.13。了解详情
DKIM:‘PASS’,网域:mg.puppylpg.xyz。了解详情
DMARC:‘PASS’。了解详情

认证均通过。

域名cloudflare是专业的,邮件mailgun是专业的。

其他

邮件中转记录

正常gmail发邮件给gmail,邮件流动记录是:gmail → mx.google.com → gmail

而别名邮箱发邮件给gmail,邮件流动记录是:gmail → smtp.gmail.com → gmail → mx.google.com → gmail。整个流程里多了发送我们配置的别名邮箱的邮件到smtp.gmail.com这一步。

邮件每中转一次会给mail生成一个Received header,可以在gmail的message header对原始邮件的header进行分析:

#DelayFrom *  To *ProtocolTime received
01 secunknown mail-m17657.qiye.163.com 2021/12/31 GMT+8 上午10:48:55
17 secmail-m17657.qiye.163.com mx1.emailowl.comESMTPS2021/12/31 GMT+8 上午10:49:02
22 secmx1.emailowl.com.[Google]mx.google.comESMTPS2021/12/31 GMT+8 上午10:49:04
3  [Google]2002:a25:a28b::SMTP2021/12/31 GMT+8 上午10:49:04
4  [Google]2002:a05:6512:33d2:0:0:0:0SMTP2021/12/31 GMT+8 上午10:49:04

以上是我用namesilo做邮件转发所产生的记录:发件邮箱是@rd.netease.com,收件邮箱是自己的域名邮箱,域名邮箱通过namesilo转发给gmail。这里gmail作为自己的真正收件服务器:

  1. 网易邮箱大师客户端发送邮件给网易企业邮箱服务器mail-m17657.qiye.163.com
  2. 网易企业邮箱发送邮件到namesilo收件服务器mx1.emailowl.com
  3. namesilo转发邮件到gmail收件服务器mx.google.com

之后就可以在gmail里查看到发来的邮件了。(DNS配置的MX记录同步可能需要一段时间)

参阅:

  • 邮件header分析:https://toolbox.googleapps.com/apps/messageheader/
  • received header:https://www.pobox.help/hc/en-us/articles/1500000193602-The-elements-of-a-Received-header
  • 邮件header里的收发地址和邮件内容里的收发地址的区别:
    • https://stackoverflow.com/questions/10822190/in-smtp-must-the-rcpt-to-and-to-match
    • https://serverfault.com/questions/518119/legitimate-reasons-smtp-mail-from-will-not-match-from-header-in-data
    • https://stackoverflow.com/questions/1750194/why-does-email-need-an-envelope-and-what-does-the-envelope-mean

发件建议

发件不是发不出就完事儿了。要考虑接收被发出去的件被拉黑的feedback,并及时调整发件策略。否则整个发件服务器的ip都可能被搞黄:

  • 怎么防止自己被标记为垃圾:https://support.google.com/mail/answer/81126
  • 看看那些被gmail用户投诉了:https://support.google.com/mail/answer/6254652
  • 使用postmaster tools统计以某域名发送的邮件有多少被用户标为垃圾了:https://support.google.com/mail/answer/9981691
  • 一键退订:
    • https://mailtrap.io/blog/list-unsubscribe-header/
    • https://blog.1kcode.cn/gmail%E7%9A%84unsubscribe%E6%8C%89%E9%92%AE%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84%EF%BC%9F/
    • https://webpower.kf5.com/posts/view/1006613/
    • https://knowledge.validity.com/hc/en-us/articles/222445367-How-to-implement-the-List-Unsubscribe-header
    • https://www.litmus.com/blog/the-ultimate-guide-to-list-unsubscribe/
  • feedback loop:
    • https://mailrush.io/blog/email-feedback-loops-everything-you-need-to-know/
    • https://www.emailvendorselection.com/starting-with-a-new-esp-make-sure-you-are-in-the-feedback-loop/

感想

一个时代结束了。mail相关的书签就此删除~

本文由作者按照 CC BY 4.0 进行授权