自建邮件服务小记

咋回事啊

LWL 之前用过很多家的邮件服务。腾讯云企业邮箱、阿里云邮、ZOHO Mail、Submail (Push)…… 但是由于各种各样的原因,这些邮局都没能让我满意(例如国内大部分邮件服务甚至都不支持 DKIM 这种基础功能),于是咱决定自建一台邮件服务器。

前置准备

机器要求

LWL 使用 mailcow: dockerized 项目完成邮件服务器基础建设,因此需要满足一定的配置要求,具体如下:

  • CPU: 1 GHz
  • RAM: 1 GiB (1.5 GiB + Swap 最佳)
  • Disk: 5 GiB (不包括邮件储存空间)
  • System: x86_64 (所以 32 位系统大概用不了吧)

ClamAV 会大量占用 RAM. 可以在 mailcow.conf 中加入 SKIP_CLAMD=y 来关闭它。

另外,邮件服务器的真实 IP 无法隐藏,因此建议使用带高防的机器以防止遭受攻击。

检查端口

可以在 BASH 使用以下指令快速检查端口占用情况

netstat -tulpn | grep -E -w '25|80|110|143|443|465|587|993|995'

也可以参照下表自行检查

如有冲突情况,可以选择关闭正在占用端口的程序或是修改 mailcow.conf 中的默认端口设置。
服务器原有 NGINX 等网页服务时,可参看官方文档中的反向代理设置方法。这里顺带提供我使用的 NGINX 反代配置:

location ~* {
        proxy_pass http://127.0.0.1:8080;
        proxy_redirect https://127.0.0.1:8080 $scheme://$host:$server_port;
        proxy_redirect https://127.0.0.1:8443 $scheme://$host:$server_port;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

设置 DNS

对于邮件服务,DNS 配置错误将极有可能导致发出的所有邮件被收信方判定为 SPAM。因此正确的 DNS 配置是必要的。如果只提供程序使用(而非个人日常使用)的话,一般需要配置以下内容:

  • A / AAAA
  • MX Record
  • rDNS (即 PTR Record)
  • SPF
  • DKIM
  • DMARC

如果需要作为日常使用,为了便于邮件客户端配置,还可添加关于 autodiscoverautoconfig 相关的记录。这部分内容请参看官方文档

A / AAAA

A 记录,用于访问 mailcow 等组件的 Web 控制台,指向邮件服务器即可。
在稍后的安装过程中,程序会自动签发一张证书来保证 SSL/TLS 链接正常建立。由于使用 webroot 方式验证,请务必正确设置该记录。

MX Record

MX 记录的用途想必不用我再赘述,将其指向邮件服务器地址即可。

根据规范,不建议直接将 MX 记录指向 IP地址,应指向能够映射到一个或者多个 DNS 中类型为 A 或者 AAAA 的地址记录。且根据RFC2181,原则上禁止指向 CNAME 记录。

rDNS

rDNS,即反向解析,在 MTA (Mail Transfer Agent, 邮件传送代理)中通常被用于判断发送方邮件服务器域名与给定IP是否互相关联。

有些邮件系统例如会拒绝没有进行反向解析的发件服务器发出的所有消息,所以建议设置好反向解析。

由于 rDNS 需要你的服务器(IP)提供商协助才能设置,因此具体设置方法需咨询您的服务器提供商。部分服务商并不支持设置反向解析记录,如果为了搭建邮局特意购入服务器,请务必提前询问其对 rDNS 的支持情况。(当然,实在不支持那就没办法了╮(╯▽╰)╭)

SPF

SPF 记录的用途是阻止垃圾邮件发件人发送假冒您网域中的“发件人”地址的电子邮件。收件人可以参考 SPF 记录来确定号称来自您网域的邮件是否来自授权的邮件服务器。

如果你已经配置了 MX 记录,只需要添加一个内容为 "v=spf1 mx ~all" 的 TXT 记录即可完成 SPF 记录的配置。

例如,假设您的网域为 example.com。您为网域创建了 SPF 记录,将您的邮件服务器(们)识别为获得授权的邮件服务器。当收件人的邮件服务器收到来自 [email protected] 的邮件时,会检查 example.com 的 SPF 记录以确定该邮件是否有效。如果发送邮件的服务器不在 SPF 记录的您的邮件服务器列表中,收件人的邮件服务器会将其视为垃圾邮件而拒绝接收。

如果您的网域没有 SPF 记录,那么有些收件人可能会拒绝您发送的邮件,因为收件人无法验证相应邮件是否来自获得授权的邮件服务器。

(该文段修改自 Google)

DKIM

DKIM 记录是一个包含公钥的记录。邮件发出时,邮局会对邮局的标题、ID 等内容进行签名,收件方通过 DKIM 记录中的公钥验证该邮件签名是否有效,进而确认该邮件是否由真实的域名持有者发出。

正确的设置 DKIM 可有效提高邮件的可信度并提升到信率。由于密钥对生成需要后文内容支持,lwl 将在稍后讲述如何添加 DKIM 记录。不过,可以先让你看看它大概长什么样:

dkim._domainkey  IN TXT     "v=DKIM1; k=rsa; t=s; s=email; p=..."

DMARC

DMARC 记录用来指示收件方对 SPF 或 DKIM 检查情况的响应方式。由于 lwl 搭建只是作为系统发信使用,所以一步到位上了最严格的方式,即 DKIM / SPF 校验不通过就直接拒信(连对方垃圾箱都进不去)。具体配置条目如下:

_dmarc TXT "v=DMARC1; p=reject; pct=100;"

完成前置准备后,就可以开始进行安装了。

安装

Docker

Mailcow-dockerized 是基于 Docker 的项目,因此需要先安装 Docker。这不是本文的重点,如果有任何出错情况请自己多搜索一下(问我也没用我也不会)
在 BASH 执行以下指令即可完成安装:

curl -sSL https://get.docker.com/ | sh

Docker-Compose

还需要安装一个似乎是 Docker 包管理器的程序:

curl -L https://github.com/docker/compose/releases/download/$(curl -Ls https://www.servercow.de/docker-compose/latest.php)/docker-compose-$(uname -s)-$(uname -m) > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

Mailcow

终于到了今天的主角了,下面就来开始安装 Mailcow!

准备文件

使用 Git 下载相关文件即可:

git clone https://github.com/mailcow/mailcow-dockerized && cd mailcow-dockerized

生成配置文件

执行以下命令来生成配置文件。当要求输入域名时,请输入前文 rDNS 中设置的那个。(如果没设置 rDNS,请保证你输入的域名符合 FQDN 格式。如果你设置了 rDNS,服务商应该会保证你的格式符合 FQDN)

./generate_config.sh

如有需要,可以修改 mailcow.conf 中的配置项

拉取镜像并启动 mailcow

马上就要完成了!输入以下指令下载相关镜像并启动 mailcow:

docker-compose pull
docker-compose up -d

Done!

访问你之前输入的域名,就应该能看到 mailcow 的后台了。使用默认帐号 admin 和密码 moohoo 登录后台。

进一步配置

先修改掉默认的帐号和密码,如果想进一步提高安全性,设置两步验证(OTP),然后继续下面的步骤吧~

添加域名

选择顶部导航栏上的 Configuration -> Mailboxes -> Add domain 来添加一个域名

设置 DKIM

添加完域名后,我们终于可以完成上面没有设置完成的 DKIM 了。

回到 Configuration -> Administration, 选择下方的 Configuration 选项卡,在 Add ARC/DKIM key 区域填写域名,选择密钥长度(如果 DNS 服务商可以支持 2048 位长密钥的公钥,选择 2048 更安全。如果不支持,那就只能选 1024 位了)。Selector 如果没有冲突,一般不需要修改。

设置完成后,在上方应该能看到类似下图的信息:

前往 DNS 服务商,添加一条记录名为 Selector + ._domainkey. + Domain (host),类型 TXT,记录值为灰色框内内容的记录。如上图应该添加记录名为 dkim._domainkey,记录值为灰框内容的记录即可。如果上图中 Domain 改为 mail.example.com ,则相对应的,记录名应改为 dkim._domainkey.mail

添加用户

再次前往 Mailboxes 页面,选择 Add mailbox 并填写相关信息即可。

至此,您应该可以开始发送邮件了。用上面的信息通过 SMTP 发信试试吧!

IPv6

对于有 IPv6 地址的服务器,可编辑 data/conf/postfix/main.cf,搜索 smtp_address_preference 配置项,将其值改为 ipv6 以优先使用 v6 地址发信。
修改后执行 docker-compose restart 重启即可。

匿名化发送人

为了避免 IP 暴露可能引起的攻击,你可能使用了 CDN 等技术保护了后端 IP。但是在默认情况下,使用 SMTP 连接到邮件系统发信时,会将请求发信的 IP 信息写入邮件头中。使用下列步骤来去除这些信息:

新建 data/conf/postfix/mailcow_anonymize_headers.pcre,写入以下内容:

/^\s*Received:[^\)]+\)\s+\(Authenticated sender:(.+)/
    REPLACE Received: from localhost (localhost [127.0.0.1]) (Authenticated sender:$1
/^\s*User-Agent/        IGNORE
/^\s*X-Enigmail/        IGNORE
/^\s*X-Mailer/          IGNORE
/^\s*X-Originating-IP/  IGNORE
/^\s*X-Forward/         IGNORE

然后编辑 data/conf/postfix/main.cf,加入一句

smtp_header_checks = pcre:/opt/postfix/conf/mailcow_anonymize_headers.pcre

最后执行 docker-compose restart 重启即可。

设置 No Reply 邮箱

一般系统发信的邮箱是没人去看内容的,这时有必要设置拒绝所有来信。
在 mailcow 后台找到 SOGo 页面,登录要设置 no-reply 的帐号,选择左侧栏的设置 -> Mail -> FILTERS,按下图设置(其中 message 可以自己编一条)

让 WordPress 使用 SMTP 发信

global $phpmailer;
add_action('phpmailer_init', function (&$phpmailer) {
    $phpmailer->isSMTP();
    $phpmailer->Host = '你的邮件服务器地址';
    $phpmailer->Port = "465"; //使用 SSL 端口连接
    $phpmailer->SMTPAuth = true;
    $phpmailer->Username = "上文设置的用户名";
    $phpmailer->Password = '和密码';
    $phpmailer->SMTPSecure = 'ssl'; //使用 SSL 加密
    $phpmailer->From = "发送人邮件地址";
    $phpmailer->FromName = "发送人名称";
});

将以上内容加入主题的 function.php 即可

一些跑题的事情

至此全文的主要内容结束啦!去 Mail Tester 试试能拿多少分吧~

其实这篇文章刚开始写的时候标题打算叫 “欢迎来到实力至上主义的邮局”的( 后来觉得太尴尬了就还是没用……
于是下面是原定的两张题图,辛辛苦苦做了不发出来也太可惜了

最后,安利一下欢迎来到实力至上主义的教室这部番!超好看 233,本文的第一首 BGM 就是这部番的 ED 了!

- EOF -

98 条评论

昵称
  1. Yuuta

    目前在用 Docker-mailserver,感觉 Mailcow 好像更吼用点,有时间的话把以前的邮件都扔了然后换上去(x

  2. Ryan

    请教下博主,如果想做海外营销适合吗?大概一天要发10000封营销邮件。

    在考虑您这个自建邮局还有sendgrid.com的邮件营销服务

    1. Ryan

      @Ryan 没做过EDM营销,在TG上看到您的帖子,就过来请教了OωO

    2. lwl12

      @Ryan 这篇文章所述的搭建方法足够让你搭建一个从技术上看可信的邮件服务器,也就是说对方域可以确定邮件是从你这里发出的,但是如果是营销用途的话,技术上可信并不意味着内容就一定不会被判 SPAM。相反,自建系统由于 IP 信誉等无法保证,也没有很多大量发送邮件需要的预热等流程,个人认为实际效果会比专业服务糟糕。

      所以该花钱的时候还是花钱上专业服务吧_(:з」∠)_,我这个人博客和一些其他服务的通知信一般一天打死也超不过两百封的用用是没什么问题,拿来大量发送的话怕是分分钟就被拉进垃圾邮件黑名单了。

  3. dimlau

    其实,感觉,yandex 提供的域名邮箱还行。

    毕竟,自建邮局,消耗也太大了。

    1. lwl12

      @dimlau 目前我主域名收发信是走 Yandex,不过这类服务其实 ToS 都不允许发送自动系统信的,在大量发送的时候会出现 Rate Limit 等问题。

  4. Zvonimir

    用着mailgun转发到gmail,相当于免费的域名邮箱,gmail用着还是很爽的

    1. lwl12

      @Zvonimir 我现在也是全部转发给 Gmail 收信,不过出信的话走 Mailgun 应该就会比较麻烦了

    2. Zvonimir

      @lwl12 也不麻烦,直接把域名邮箱作为别名添加到gmail,通过mailgun发信,就跟原生gmail体验一样了。而且没有代发字样,也能添加dkim等一系列东西。

  5. pomoke

    机器实在缺内存,又懒得用其它邮局,就一直用着Gandi的邮局😂
    Gandi的webmail也是sogo3

  6. asd

    |´・ω・)ノ一直怕泄露 IP 不敢用 SMTP,然而现在已经没收信发信的需求了。邮件我都是去 HTTP API 调用 SAE 的(

  7. True

    企业用的吧。

  8. YHNdnzj

    目前用的是 NameSilo 的郵件轉發 + Gmail。有空試試這個🙂

    1. liwanglin12

      @YHNdnzj 自建服务主要是用来发信而不是收信(

    2. YHNdnzj

      @liwanglin12 我基本不發信(

  9. Pingback: 個人書籤 – YHNdnzj's Blog

  10. 音速灰行的起子

    没有DKIM刚需啊,像我这种用extmail的果然还是要学习一个

    1. liwanglin12

      @音速灰行的起子 DKIM 这种鉴权对于域名邮箱还是相当重要的。

  11. Pang

    「这些人都排着队来跟我说话」 这个title可以。哈哈 。我也来挤一挤,,

    1. liwanglin12

      @Pang 这个其实是和隔壁 DIYgod.me 的站长学的(

  12. Pang

    哎~ 老了 没空折腾了。 (/ω\)

  13. Pingback: mailcow 搭建邮件服务器 - 拖鞋门吹雪

  14. 快看那头熊

    比较想知道哪家公司的主机可以提供rdns功能,印象中很多主机商都会禁用25端口防止垃圾邮件

    1. liwanglin12

      @快看那头熊 这我也不太好推荐啊233,我自己在用 OVH,阿里云也可以 rDNS

  15. 不一样的科技宅

    点个赞

  16. Saiki

    谢lwl12大佬……自建邮件服务正常运行了。

  17. 程志辉

    可以的,路过想跟你说一下,天冷加衣哦~

  18. 山野愚人居

    太高级了,感觉用不来,我觉得免费的企业域名邮箱已经够用了!

  19. SCHENKERX

    之前看过这个项目,他们那时还没用Rspamd,而且我觉得这太臃肿了就自己手动建了一个。来交换电子邮件玩下吗(一直用来接收银行邮件,毫无压力,稳定运行两年+facial