Pages

Saturday, 28 October 2017

自建邮件服务小记

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

机器要求

使用 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 记录,将您的邮件服务器(们)识别为获得授权的邮件服务器。当收件人的邮件服务器收到来自 user@example.com 的邮件时,会检查 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 试试能拿多少分吧.

No comments:

Post a Comment