Maddy Mail Server 是一个 GO 语言开发的 ALL-IN-ONE 邮件系统,实现了 Mail Transfer agent (MTA), Mail Delivery Agent (MDA), Mail Submission Agent (MSA), IMAP server 等,说人话就是可以替换 Postfix、Dovecot、Opendkim、OpenSPF、OpenDmarc 等传统软件,主要功能是通过 SMTP 发送和接收邮件,通过 IMAP 实现客户端访问,也支持 DKIM、SPF、DMARC、DANE、MTA-STS 等邮件相关的安全和反垃圾协议。对比配置传统软件,即使是像 MailCow、Mail-in-a-Box 等基于 docker 的现成方案,安装、配置也足够简单、开箱即用,可以说是懒人必备。

一、准备工作

需要准备以下:

  1. 域名 + nameserver
  2. 开放25端口的服务器,最好可以做ip反解析
  3. 干净的IP,可以通过 mxtoolbox 查询黑名单
  4. 邮件软件 maddy

二、安装及配置 Maddy mail server

2.1 下载和安装

建议使用 docker 安装 Maddy,安装和配置起来更简单。github release 中已经有编译好的各平台可执行文件, 也可以从 github 下载最新版解压使用:

wget  https://github.com/foxcpp/maddy/releases/download/v0.7.1/maddy-0.7.1-x86_64-linux-musl.tar.zst

zst 后缀需要安装 zstd 进行解压:

yum install zstd -y 
tar -I zstd -xvf  maddy-0.7.1-x86_64-linux-musl.tar.zst

解压之后的目录有5个文件,安装 Maddy:

mv maddy maddyctl /usr/local/bin/
mkdir /etc/maddy && mv maddy.conf /etc/maddy/
mv systemd/*.service /usr/lib/systemd/system/
mv man/*.1 /usr/share/man/man1/ && mv man/*.5 /usr/share/man/man5/

2.2 配置 maddy mail server

2.2.1 添加用户

官方不建议 root 权限运行,先添加一个不可登录的普通用户:

useradd -mrU -s /sbin/nologin  -c "maddy mail server" maddy

添加完用户,设置一下相关的目录及文件的权限:

chown -R maddy:maddy /usr/local/bin/maddy* /etc/maddy 

2.2.2 更改配置文件

默认配置文件在 /etc/maddy/maddy.conf ,里面已经有一个开箱即用的配置,只需修改几个参数即可使用。

$(hostname) = mx1.opswill.com mx2.opswill.com
$(primary_domain) = opswill.com
$(local_domains) = $(primary_domain)  other.domain.com

tls file /etc/maddy/certs/$(hostname)/fullchain.pem /etc/maddy/certs/$(hostname)/privkey.pem

state_dir /etc/maddy/state
runtime_dir /etc/maddy/runtime
log syslog /var/log/maddy.log

按需修改以上内容即可,如果创建的普通用户未指定 home 目录,配置文件中的 state_dir、runtime_dir 需先创建目录并给权限。

2.2.3 申请 ssl 证书

SMTPs 和 IMAPs 服务需要 TLS 证书,建议使用 Let's Encrypt 的泛域名证书,具体申请方法就不介绍了。

证书需放入 /etc/maddy/certs/$(hostname) 中,在配置文件中指定时,需先写公钥(.crt),在写私钥 (.key)

证书需设置一下权限:

sudo setfacl -R -m u:maddy:rX /etc/maddy/certs/

2.2.4 创建用户

maddy 使用虚拟用户,所以不像 postfix 和 dovecot 一样需要创建系统用户。maddy 需要创建登录账户和 IMAP 的本地存储账户,登录账户是 SMTP 和 IMAP 登录时的验证信息:

 maddyctl creds create will@opswill.com

创建本地储存账户:

maddyctl imap-acct create will@opswill.com

查看是否创建成功:

maddyctl  creds list
maddyctl  imap-acct  list

2.3 启动服务

以上全部做好后,即可启动服务:

systemctl daemon-reload
systemctl start maddy

正常启动后,会开放以下端口:

  • 25 SMTP Transfer->Exchange ClearText
  • 465 SMTPs User->Submission TLS
  • 587 ESMTP User->Submission ClearText/STARTTLS
  • 143 IMAP Delivery->User ClearText
  • 993 IMAPs Delivery->User TLS

防火墙放行:

firewall-cmd --permanent --add-port={25/tcp,465/tcp,587/tcp,143/tcp,993/tcp}
firewall-cmd --reload

从外网 telnet 验证一下服务器公网 IP 是否开放以上端口。尤其需注意25端口是否能够访问

服务器端就配置好了,可以用手机或 outlook 等客户端进行连接测试。接下来为了收发邮件,还需配置域名解析才行。

三、域名解析配置

无论邮箱系统用的什么软件,都绕不开邮件相关的域名解析,只要搞邮件就需配置以下域名解析:

  • MX记录 :域名系统基础记录,指向邮件服务器
  • PTR记录 :即IP反解析,根据IP反查域名,需供应商来做
  • SPF记录 :指定哪些服务器可以使用你的域名发送邮件
  • DKIM记录 :防止发送的电子邮件内容篡改
  • DMARC记录 :当SPF和DKIM验证失败时,指定接收方的处理策略并向指定邮箱报告

3.1 MX 记录

收发邮件时,mx 记录指定了自己的邮件服务器地址,可以设置优先级,建议2条以上 mx 记录

域名       类型   值           优先级
opswill.com mx  mx1.opswill.com  10
opswill.com mx  mx2.opswill.com  20 

设置对应MX子域名的记录:

mx1.opswill.com  A  1.1.1.1
mx2.opswill.com  A  2.2.2.2

设置好后使用dig命令验证一下:

dig  mx  opswill.com @1.1.1.1
dig  a  mx1.opswill.com @1.1.1.1
dig  a  mx2.opswill.com @1.1.1.1

3.2 PTR 记录

将域名映射到 IP 地址是正向解析,从 IP 地址到域名的映射就是反向解析,在公网上,反向解析无法由 DNS 提供,因为IP地址的管理权限属于运营商,所以需要向运营商申请添加反向解析,运营商通过 PTR(Pointer Record)记录将 IP 地址指向域名。邮件服务器IP不做PTR记录,发送邮件后会有很大概率被当成垃圾邮件。

联系供应商加好后,可以用 dig 命令验证:

dig -x 1.1.1.1

3.3 SPF 记录

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 记录为:

  opswill.com  txt  "v=spf1 mx -all"

3.4 DKIM 记录

DKIM 记录主要作用也是防止邮件被恶意篡改,保证邮件内容的完整性,使用的方式是与 SSL 类似,服务器产生一个公私钥对,私钥为每一封外发的邮件签名并在邮件头中插入 DKIM 签名(DKIM-Signature头),公钥则保存在域名的记录中,邮件接收方接收邮件时,通过 DNS 查询获得公钥,并使用公钥解密邮件签名, 从而验证邮件有效性和完整性。

Maddy 第一次启动后已经自动生成 DKIM 私钥和需添加的 dns 记录,位置在 state dir(/etc/maddy/state)下的 /dkim_keys/_default.dns 中,添加 txt 记录:

default._domainkey.opswill.com  txt  "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0...省略..."

3.5 DMARC 记录

DMARC 基于现有的 SPF 和 DKIM 协议,并声明对验证失败邮件的处理策略。邮件接收方接收邮件时,首先通过 DNS 获取 DMARC 记录,再对邮件来源进行 SPF 验证和 DKIM 验证,对验证失败的邮件根据 DMARC 记录进行处理,并将处理结果反馈给发送方。

添加 DMARC 记录:

_dmarc.opswill.com  txt  "v=DMARC1; p=quarantine; ruf=mailto:report@ipip.dev"

p:reject 拒绝该邮件;none为不作处理;quarantine 标记为垃圾邮件。
ruf:检测到伪造邮件,接收方报告的邮箱地址

3.6 MTA-STS 和 TLS 报告

MTA-STS 是 MTA 严格传输安全协议,作用是确保发送给我们的电子邮件通过 TLS 安全地传输,防止中间人攻击。启用 MTA-STS 后,发送方邮件服务器只有在满足以下条件时,才会向我们发送邮件:

  • 使用有效的证书通过身份验证
  • 使用 TLS 1.2 或更高版本进行加密

当然如果发送方不支持 MTA-STS,仍然可以发送邮件(可能会有中间人攻击),主要是为了兼容。

启用 MTA-STS 所需条件:

  • 创建策略文件,并提供HTTPS方式访问
  • 通过DNS 设置txt记录,告诉其它邮件服务商支持MTA-STS

3.6.1 创建策略文件

策略文件 mta-sts.txt 的内容为:

version: STSv1
mode: enforce
mx: mx1.opswill.com
mx: mx2.opswill.com
max_age: 86400

创建子域名并启用 https ,最终的访问路径为:

https://mta-sts.opswill.com/.well-known/mta-sts.txt

3.6.2 配置 MTA-STS 的TXT记录

_mta-sts.opswill.com TXT “v=STSv1; id=20211031T010101;"

一般id为时间戳

3.6.3 启用 TLS 报告

和 DMARC 记录类似,启用 TLS 报告可以接受外部邮件服务器会发送以下内容:检测到的 MTA-STS 政策、流量统计信息、失败的连接以及无法发送的邮件等详细信息。

添加以下 txt 记录:

_smtp._tls.opswill.com     TXT     "v=TLSRPTv1;rua=mailto:sts-reports@opswill.com"

3.7 DNSSEC、DANE 及 CAA

启用了 MTA-STS 后,DANE 可以确保 TLS 证书是有效的,实际上是通过DNS的方式扮演了 CA 的角色。 DANE 通过 TLSA 记录,来声明某个证书的是可信的,由于 DANE 是基于 DNS 协议,可能会有被挟持的可能,因此需要启用 DNSSEC 来保障传输过程中不被修改。

  1. 启用 DNSSEC 需域名注册商及 dns 服务商都支持,在 DNS 服务商处选择开启 DNSSEC ,然后将提供的 DS 记录填写到域名注册商即可
  2. 使用 TLSA证书生成工具 及 PEM 格式的 TLS 证书生成 TLSA 记录
  3. 使用 CAA Record Helper生成的 CAA 记录

为了保障 TLS 证书安全:

  1. DNSSEC 保障 DNS 记录传输过程中的安全
  2. DANE 在客户端侧阻止不当签发的证书
  3. CAA 指定域名允许哪个证书颁发机构为其颁发证书

此步为加强安全性,有能力推荐启用配置

四、邮件通知到 Telegram

在 maddy.conf 中,找到 storage.imapsql local_mailboxes,添加一个 imap_filter :

storage.imapsql local_mailboxes {
    driver sqlite3
    dsn imapsql.db

    imap_filter {
       command /data/script/notice.sh  {sender} {original_rcpt_to} {subject}
   }
}

邮件通知的脚本内容:


#!/bin/bash

logfile=/data/log/notice.log

echo -e "\n$(date "+%Y-%m-%dT%H:%M:%S")  starting sending tg notice with args: $@" >>$logfile

input="$3"

if ! command -v curl &> /dev/null; then
    if ! apk add curl; then
        exit 1
    fi
fi


#bash判断是否为 Base64 编码
if [[ "$input" =~ =\?utf-8\?B\?(.*)\?= ]]; then
    encoded=${BASH_REMATCH[1]}
    sub=$(echo "$encoded" | base64 -d)
else
    sub=$input
fi

MailMsg="New Mail From $1 To $2, Subject: $sub"

curl -s -X POST "https://api.telegram.org/botIDxxxx:botSECRETxxxx/sendMessage" -d "chat_id=185854188&text=$MailMsg" >>$logfile

echo  -e "\n$(date "+%Y-%m-%dT%H:%M:%S") tg notice has sent" >>$logfile

五、总结

邮箱服务不只是系统配置烦琐、反垃圾、安全相关、及域名解析等的都很麻烦,如果使用传统的软件,其实不是很适合新手。虽然有一些基于 docker 或者脚本的现成方案,但真部署和调试起来也不容易。对比传统软件 Maddy mail server 安装和配置都足够简单,满足一个现代安全邮箱所需的功能,也有一定的扩展性,虽然比较新还不够成熟,但对个人友好,适合懒人党对可靠性要求不高的情况。

参考链接及有用的工具:

  1. https://mxtoolbox.com/
  2. https://www.mail-tester.com/
  3. https://aykevl.nl/apps/mta-sts/
  4. https://support.google.com/a/answer/10683907
  5. https://support.google.com/a/answer/2466563?hl=zh-Hans
  6. https://service.mail.qq.com/cgi-bin/help?id=16