docker mailserver(下文简称 DMS),是一个部署起来非常简单的邮件服务器方案。使用 docker 不和其他服务冲突,只包含邮件服务器非常简洁,最小安装需要的内存小于 500M,项目开发活跃。
背景知识
邮件服务主要参与者
- MUA:客户端,如 K9 Mail
- MTA:处理发送和接收,如 Postfix
- 外向邮件给到 MTA,之后 MTA 一跳一跳给到最终收件人的 MTA
- 内向邮件由 MTA 接收,之后给到 MDA
- MDA:暂存邮件,提供给客户端,如 Dovecot
1
2
Sending an email: MUA ----> MTA ----> (MTA relays) ----> MDA
Fetching an email: MUA <--------------------------------- MDA
收发邮件涉及的端口和协议
前置准备
- 一个域名:可以用 freenom 申请,在家部署可以结合 dynu 的 ddns。下文这个域名都用 example.com 代表,复制命令时注意替换
- 设备:少量邮箱,不开杀毒和垃圾邮件过滤的话 DMS 很不吃内存,大概几百 M。硬盘看邮件数量。如果开 vps 注意下述端口问题
- 端口:25,465,993。如果用了 NAT 这几个端口要穿出去;如果用 vps 要提前查好,很多 vps 墙掉了往外发邮件的 25 端口,一些可以发工单申请开,实在开不了 25 端口可以用发送代理服务,下文有步骤
- 需要 https 证书的域名:imap.example.com,smtp.example.com,推荐 letsencrypt 配置
- 时间:dns 记录如果设错了,修改之后生效会需要一定时间,测试阶段可以把 TTL 设到最小。其他的操作都不是很耗时
安装
过完这一部分应该可以正常收邮件和发站内邮件。
下载需要的文件
1
2
3
4
5
DMS_GITHUB_URL='https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master'
wget "${DMS_GITHUB_URL}/docker-compose.yml"
wget "${DMS_GITHUB_URL}/mailserver.env"
wget "${DMS_GITHUB_URL}/setup.sh"
chmod +x ./setup.sh
测试 docker,下面命令不是报错输出就行
1
./setup.sh help
修改配置文件内容
- docker-compose.yml
- hostname:一般叫 mail
- domainname:服务器网址,如 example.com
- volumes 加一条
- /etc/letsencrypt:/etc/letsencrypt:ro
:letsencrypt 的证书可能用软链接,docker 里和 host 里的路径需要完全相同,挂载的文件夹需要包含软链接文件和原文件 - 可以注释掉 143 和 587 端口,这两个是允许明文收发邮件的不推荐用
- mailserver.env
- SSL_TYPE: letsencrypt
启停 DMS 用以下命令。注意:不要用 start/stop 或者 ctrl-c,可能导致问题
1
2
docker-compose up # 会占用一个tty显示log
docker-compose down
当调试完成的差不多,可以将 DMS 作为一个进程启动。DMS 默认配置会自动启动,这样系统 enable docker 的话,邮件服务开机后就会自动启动
1
docker-compose up -d
启动 docker mailserver
1
docker-compose up
以下命令都假设在docker-compose.yml
中container_name
没改(默认是mailserver
)。
首次启动时 dovecot 需要至少一个账户才能启动。首次启动之后开另一个命令行添加账户
1
./setup.sh email add me@example.com
别名 postmaster 账户
1
./setup.sh alias add postmaster@example.com me@example.com
要让其他邮件服务器可以找到负责 example.com 的邮件服务器,需要在 dns 里添加 mx(mail exchange) 记录。按照上面的配置,mx 记录的值应该是 mail.example.com。下面是一个例子
到这里就应该可以正常收邮件和发站内信了。DMS 不提供 web 界面,可以用 k9 mail app,nextcloud 的 mail 插件等查看邮件。配置过程中收邮件的协议应该是 imap,端口 993;发邮件的协议应该是 smtp,端口 465。这两个端口都是强制加密的,客户端和自己的邮件服务器之间的通信不会有明文邮件内容。
收多个域名的邮件
比如邮件服务器在 mail.example.com 上,想要收 me@another.com 邮箱的邮件。如果你能修改 another.com 的 mx 记录,这个非常简单。
首先在 DMS 里创建一个用户 me@another.com
1
docker exec -it mailserver setup email add me@another.com
之后给 another.com 添加 mx 记录。你会发现 mx 记录除了一个网址之外还有一个数,这代表这条 mx 记录的优先级,数越小优先级越高,一般是 10 的倍数。其他人在给 another.com 发邮件时会按 mx 记录优先级从高到低(那个数字从小到大)一个一个尝试,成功投递就不往后试了。你可以给自己的服务器一个高优先级,之后给一个第三方可靠的方案,比如 zoho(用自己的域名免费)或者 proton mail(用自己的域名应该收费)一个低的优先级作为备份。一个例子
发送
为了在你收到一封邮件时可以相信:这个邮件真的是声称的发送者发的,内容没被篡改,发送者可以代表这个域名发邮件,发邮件比收配置起来复杂很多。首先确定你的网络环境可以从 25 端口往外发东西,否则就算能用 25 以外的端口发出邮件,接收方大概率也会拒收。
以下是个人对三个机制的理解,仅供参考。
DKIM(DomainKeys Identified Mail)
验证邮件发送者真的是声称的发送者。大概的机制应该类似 https,用私钥签名,公钥验证。在邮箱域名下会有一个 email._domainkey 的 txt 记录,里面包含一个公钥字符串。邮件发送时用邮件服务器上存的私钥+邮件的一些信息和内容生成一个签名,这样接收方可以验证邮件确实来自声称的发送方,而且内容在发送过程中没被篡改。如果你因为 25 的原因不能直接发出邮件,这个没必要配。
一个白名单,也是一个 txt dns 记录,里面列出谁可以代表这个域名发邮件。
DMARC(Domain based Message Authentication, Reporting and Conformance)
DKIM 是一个检测,SPF 是一个白名单
v=DMARC1; p=none; rua=mailto:dmarc.report@linhan.ml; ruf=mailto:dmarc.report@linhan.ml; sp=none; ri=86400
- p:如果 SPF/DKIM 校验没过,怎么处理这封邮件
- none:Reports possible suspicious mail messages, but all mail is sent to inbox
- quarantine:Fail SPF/DKIM policy, then message is sent to SPAM/Junk folder
- reject:Fail SPF/DKIM policy, then message is dropped and not delivered at all
- sp:和 p 一样,不过是给这个域名的子域名的。如果不计划用子域名,推荐设成 reject
SMTP 代理
如果你服务器所在的网络环境不允许从 25 端口往外发邮件,可以用一个 smtp 代理。邮件先发到 smtp 代理,之后代理从他的 25 端口发出邮件。可选的服务商有很多,DMS 推荐了mailgun,sendgrid,aws ses。我用的sendinblue,每天有 300 封免费额度。
DMS 方面的配置参考这里,填写 RELAY_HOST,RELAY_PORT,RELAY_USER,RELAY_PASSWORD 就行,信息服务商都会提供。
用代理的话 DKIM 是在代理那签,不需要自己配。DMARC 和自己直接发送没区别。自己的 spf 需要包含代理的 spf 规则。查一个服务商的 spf 规则可以用mxtoolbox。一般应该都是 spf.服务域名。比如这是 sendinblue 的 spf lookup 结果。这样你的 spf dns 记录应该就是如下:
1
v=spf1 include:spf.sendinblue.com -all
如果你还用了一个备份邮件服务,那需要结合两家的 spf,比如下面这样
1
v=spf1 include:spf.sendinblue.com include:spf.zoho.eu -all
注意 dns 记录不要超过 256 个字符。
更新
用 watchtower 可以在 dockerhub 镜像有更新时自动进行更新和重启 DMS,需要在 DMS 的 docker-compose.yml 中添加
1
2
3
4
5
6
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /root/.docker/config.json:/config.json
command: --interval 86400 --cleanup true
–no-restart:不重启
管理
列出服务器上所有的邮箱
1
./setup.sh email list