Maddy 是一个 GO 语言开发的 ALL-IN-ONE 邮件系统,主要功能是通过 SMTP 发送和接收邮件,通过 IMAP,客户端可以实现访问,也支持 DKIM、SPF、DMARC、DANE、MTA-STS 等邮件相关的安全和反垃圾协议。
通俗点讲就是部署特别方便, 资源占用少,非常适合个人使用的电子邮件服务器。
项目地址:maddy/maddy.conf at master · foxcpp/maddy (github.com)
前提:
参考:常用邮件端口
以下用 example.com
这个域名作演示,实际中替换成真实域名。
从 https://sslforfree.com 申请 mx1.example.com
证书,下载得到 certificate.crt
和 private.key
将 certificate.crt
和 private.key
分别重命名为 fullchain.pem
、privkey.pem
(配置文件中默认指定的名称)
从 maddy.conf 下载官方默认的配置文件,并修改其中内容:
(hostname) = mx1.example.com
(primary_domain) = example.com
创建一个目录 maddydata 用于存放容器内的数据映射,并且把上面的证书文件与 maddy.conf 放入
此时的 maddydata 目录结构如下:
maddydata
├── certs
│ └── mx1.example.com
│ ├── fullchain.pem
│ └── privkey.pem
└── maddy.conf
docker run \
--name maddy \
-e MADDY_HOSTNAME=mx1.example.com \
-e MADDY_DOMAIN=example.com \
-v /maddydata/certs:/etc/maddy/certs/ \
-v /maddydata:/data \
-p 25:25 \
-p 143:143 \
-p 587:587 \
-p 993:993 \
-d foxcpp/maddy:latest
如果 docker 服务启动失败,根据 docker logs maddy
查看日志寻找原因
更详细的解释可以参考官方文档 Installation & initial configuration - maddy
注意,
example.com
应该改成你自己的域名
# A 记录
example.com. A 10.2.3.4
# MX 记录
example.com. MX 10 mx1.example.com.
# MX 域解析
mx1.example.org. A 10.2.3.4
# SPF
example.com. TXT "v=spf1 mx ~all"
example.com. TXT "v=spf1 mx ~all"
# _dmarc
_dmarc.example.com. TXT "v=DMARC1; p=quarantine; ruf=mailto:[email protected]"
# _mta-sts. _smtp.tls
_mta-sts.example.com. TXT "v=STSv1; id=1"
_smtp._tls.example.com. TXT "v=TLSRPTv1;rua=mailto:[email protected]"
# 设置的值项目运行后自动生成,cat maddydata/dkim_keys/example.com_default.dns
default._domainkey.example.com. TXT "v=DKIM1; k=ed25519; p=xxxxxxxxxxxx"
如果有 IPV6 地址,也可以配置上:
example.com. AAAA 2001:beef::1 # IPV6 有就配置
mx1.example.org. AAAA 2001:beef::1 # IPV6 有就配置
对于各个配置的详细解析可以参考后面部分。
进入 maddy 容器中:
docker exec -it maddy sh
Maddy 使用虚拟用户,所以不像 postfix 和 dovecot 一样需要创建系统用户。它需要创建的登录账户和 IMAP 本地存储账户。(登录账户是 SMTP 和 IMAP 登录时的验证信息)
# 创建一个 [email protected] 的登录账户
$ maddyctl creds create [email protected]
# 查看登录账户列表
$ maddyctl creds list
# 创建一个 [email protected] 邮件储存账户
$ maddyctl imap-acct create [email protected]
# 查看刚存储账户列表
$ maddyctl imap-acct list
# 可以看到账户下的邮件分类
$ maddyctl imap-mboxes list [email protected]
INBOX [\HasNoChildren]
Sent [\Sent \HasNoChildren]
Trash [\Trash \HasNoChildren]
Junk [\Junk \HasNoChildren]
Drafts [\Drafts \HasNoChildren]
Archive [\Archive \HasNoChildren]
# 可以查看当前账户对应分类接收到的邮件,一般收件在 INBOX 中
$maddyctl imap-msgs list [email protected] INBOX
登录上一个 Web 邮箱(例如 163),往你刚刚创建的 [email protected]
发送邮件
查看是否收到邮件:
$ maddyctl imap-msgs list [email protected] INBOX
UID 1: <[email protected]> - =?utf-8?B?dGVzdEBoYWhhY29kZS5jbg==?=
[\Recent], 2023-03-22 09:54:47 +0000 UTC
无论邮箱系统用的什么软件,都绕不开邮件相关的域名解析,只要搞邮件就需配置以下域名解析:
收发邮件时,MX 记录指定了自己的邮件服务器地址,可以设置优先级,一般建议 2 条以上 mx 记录()
域名 类型 值 优先级
example.com mx mx1.example.com 10
设置对应 MX 子域名的记录:
mx1.example.com A 10.2.3.4
设置好后使用 dig 命令验证一下:
dig mx example.com
将域名映射到 IP 地址是正向解析,从 IP 地址到域名的映射就是反向解析,在公网上,反向解析无法由 DNS 提供,因为 IP 地址的管理权限属于运营商,所以需要向运营商申请添加反向解析,运营商通过 PTR(Pointer Record)记录将 IP 地址指向域名。邮件服务器 IP 不做 PTR 记录,发送邮件后会有很大概率被当成垃圾邮件。
联系供应商加好后,可以用 dig 命令验证:
dig -x mx1.example.com
SPF 全名是 发件人策略框架,主要作用是将发信的邮件服务器和发信域名进行绑定,防止伪造发件人。在 SPF 记录中使用 TXT 记录指定允许发信的服务器,当对方收到邮件后,系统会验证发信域名并读取 SPF 记录中的 IP,验证是否一致后采取进一步动作。
以谷歌 SPF 记录为例:
# dig txt gmail.com
gmail.com. 300 IN TXT "v=spf1 redirect=_spf.google.com"
# dig txt _spf.google.com
_spf.google.com. 300 IN TXT "v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all"
# dig txt _netblocks.google.com
_netblocks.google.com. 300 IN TXT "v=spf1 ip4:35.190.247.0/24 ip4:64.233.160.0/19 ip4:66.102.0.0/20 ip4:66.249.80.0/20 ip4:72.14.192.0/18 ip4:74.125.0.0/16 ip4:108.177.8.0/21 ip4:173.194.0.0/16 ip4:209.85.128.0/17 ip4:216.58.192.0/19 ip4:216.239.32.0/19 ~all"
SPF 记录以 v=spf1
开头,以 all
结尾,中间可以使用 ip4/ip6/a/mx/include/redirect 等关键字进行 ip 范围指定。SPF 记录的匹配机制会结合 限定词 来告诉服务器匹配记录时的动作。常见的限定词有:
+
放行,如果没有明确指定限定词,则为默认值。-
硬拒绝,直接拒绝来自未经授权主机的邮件。~
软拒绝,邮件可被接受,也可被标记为垃圾邮件。?
中性,不考虑邮件是否被接受。个人邮件设置允许 mx 记录中的服务器发信即可,最终设置 SPF 记录为:
example.com txt "v=spf1 mx -all"
DKIM 记录主要作用也是防止邮件被恶意篡改,保证邮件内容的完整性,使用的方式是与 SSL 类似,服务器产生一个公私钥对,私钥为每一封外发的邮件签名并在邮件头中插入 DKIM 签名(DKIM-Signature 头),公钥则保存在域名的记录中,邮件接收方接收邮件时,通过 DNS 查询获得公钥,并使用公钥解密邮件签名, 从而验证邮件有效性和完整性。
Docker 运行 Maddy 启动后会自动生成 DKIM 私钥和需添加的 dns 记录,位置在:
dockerdata/dkim_keys/example.com_default.dns
default._domainkey.example.com txt "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0......"
DMARC 基于现有的 SPF 和 DKIM 协议,并声明对验证失败邮件的处理策略。邮件接收方接收邮件时,首先通过 DNS 获取 DMARC 记录,再对邮件来源进行 SPF 验证和 DKIM 验证,对验证失败的邮件根据 DMARC 记录进行处理,并将处理结果反馈给发送方。
_dmarc.nixops.me txt "v=DMARC1; p=quarantine; ruf=mailto:[email protected]"
p
:reject 拒绝该邮件;none 为不作处理;quarantine 标记为垃圾邮件。ruf
:检测到伪造邮件,接收方报告的邮箱地址MTA-STS 是 MTA 严格传输安全协议,作用是确保发送给我们的电子邮件通过 TLS 安全地传输,防止中间人攻击。启用 MTA-STS 后,发送方邮件服务器只有在满足以下条件时,才会向我们发送邮件:
当然如果发送方不支持 MTA-STS,仍然可以发送邮件(可能会有中间人攻击),主要是为了兼容。
启用 MTA-STS 所需条件:
策略文件 mta-sts.txt 的内容为:
version: STSv1
mode: enforce
mx: mx1.nixops.me
mx: mx2.nixops.me
max_age: 86400
创建子域名并启用 https,最终的访问路径为:
https://mta-sts.nixops.me/.well-known/mta-sts.txt
配置 MTA-STS 的 TXT 记录:
_mta-sts.nixops.me TXT "v=STSv1; id=20211031T010101;"
一般 id 为时间戳。
启用了 MTA-STS 后,DANE 可以确保 TLS 证书是有效的,实际上是通过 DNS 的方式扮演了 CA 的角色。 DANE 通过 TLSA 记录,来声明某个证书的是可信的,由于 DANE 是基于 DNS 协议,可能会有被挟持的可能,因此需要启用 DNSSEC 来保障传输过程中不被修改。
为了保障 TLS 证书安全:
此步为加强安全性,有能力推荐启用配置。
参考文章:
其他参考链接及有用的工具: