背景
由于
Gmail
邮箱在国内无法使用 且国内手机
号码无法继续注册账号原因,最近想着折腾一下 自建一台邮件服务器
玩玩。正好在国外有台 vps (搬瓦工的),比较空闲,目前且用来做扶墙使用,有点浪费,决定使用此台服务器搭建邮件服务器
。选择的部署方案选择了较为轻便的docker
,在了解网上主流的实现镜像后analogic/poste.io
&mailserver/docker-mailserver
,由于目前 vps 资源为2c 1g
的低配置,试着跑了一下前者,资源占用非常大(可能 默认开了什么功能什么的), 在当前有限的配置下有点跑不动。了解后者这个 项目 后,可以在最低1c 512m
下运行,最后决定选用后者docker-mailserver
进行部署。
环境说明
Email 服务器:
23.105.194.216
(搬瓦工 vps)使用容器镜像:
mailserver/docker-mailserver:latest
系统版本:
CentOS Linux release 7.9.2009 (Core)
内核版本:
4.14.129-bbrplus
Docker Version:
20.10.7
Docker Compose Version:
1.29.2
DNS 服务商:
aliyun
基础介绍
常见邮件服务端口 & 协议 介绍
详细介绍信息, 查看此文档
协议 | 端口 |
---|---|
SMTP | 25/587/465 |
IMAP | 143/993 |
POP3 | 110/995 |
常见 邮件软件 和 安全软件 介绍
软件名称 | 简介 |
---|---|
sendmail | 用于发邮件。资格最老的邮局,所有Linux发行版基本都带。但是配置麻烦。 |
postfix | Wietse Venema 觉得 sendmail 配置太麻烦了,就开发了一个 “简化配置版 sendmail”,即postfix。支持smtp协议。 |
dovecot | 用于收邮件,支持imap/pop3。 |
spamassasin | 垃圾邮件过滤器。可以自订规则。 |
clamav | 邮件杀毒工具。 |
opendkim | 生成dkim签名。有什么用?详见下面的“反垃圾邮件技术”。 |
fail2ban | 防止别人暴力破解用户名密码的工具。 |
反垃圾邮件技术介绍
邮件反垃圾技术(Anti-Spam)是指防止垃圾邮件(Spam)的技术手段。垃圾邮件通常是指发送大量不需要或不想要的邮件,这些邮件经常包含欺诈或诈骗信息、色情内容或恶意软件等。为了防止这些邮件占据用户的收件箱,邮件服务提供商和企业采用了一系列技术手段来防止垃圾邮件。常见的邮件反垃圾技术包括:
- SPF(Sender Policy Framework)技术。SPF 用于验证发送邮件的服务器是否在域名的授权列表中。如果不在,则认为是垃圾邮件。通过在域名的 DNS 中添加 TXT 记录,可以指定哪些服务器可以发送该域名的邮件。
- DKIM(DomainKeys Identified Mail)技术。DKIM 是一种数字签名技术,通过在邮件头中添加一个签名,可以验证邮件是否被篡改过。使用 DKIM 技术可以有效防止垃圾邮件和欺诈邮件。
- DMARC(Domain-based Message Authentication, Reporting and Conformance)技术。DMARC 技术是 SPF 和 DKIM 的加强版,它通过在域名的 DNS 中添加 TXT 记录,指定如何处理验证失败的邮件,可以有效地降低垃圾邮件和欺诈邮件的数量。
- 邮件过滤技术。邮件过滤技术是指通过人工智能算法和机器学习技术,对邮件进行分类和判断,判断哪些邮件是垃圾邮件,然后将其过滤掉。
- 黑名单和白名单技术。黑名单和白名单技术是一种基于地址列表的技术,通过将发件人的地址添加到黑名单或白名单中,来防止垃圾邮件。
- Greylisting 技术。Greylisting 是一种基于时间的技术,当服务器接收到一个新的邮件时,将其延迟一段时间(通常是数分钟),然后再重新发送。由于大多数垃圾邮件发送服务器不会尝试重新发送,因此这种技术可以有效地过滤掉垃圾邮件。
通过这些技术的组合应用,可以有效地降低垃圾邮件的数量,保障用户的邮箱安全和隐私。
安装部署
这里安装部署我们使用
Docker Compose
,使用较低版本还不行,建议是按照下面的步骤安装最新
的版本,如你已安装和配置,对下面部分配置做跳过即可。
安装前准备工作
-
安装 docker
curl -fsSL https://get.docker.com -o get-docker.sh # 使用脚本安装 sudo sh get-docker.sh cat > /etc/docker/daemon.json << EOF `# 配置优化` { "oom-score-adjust": -1000, "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" }, "max-concurrent-downloads": 10, "exec-opts": ["native.cgroupdriver=systemd"], "max-concurrent-uploads": 10, "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ] } EOF systemctl start docker \ `# 启动 并设置开机自启` && systemctl enable docker \ && systemctl status docker
-
安装 docker-compose
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \ && chmod +x /usr/local/bin/docker-compose \ && ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose \ && docker-compose --version
-
阿里云设置 DNS 记录
这里 设置的 DNS 未包含
DKIM
签名记录。这个记录需要在后面,使用脚本进行生成。DNS 类型 记录名 记录值 TTL A mail 23.105.194.216 30 分钟 MX @ mail.treesir.pub |10 (优先级 10) 30 分钟 TXT @ v=spf1 mx ~all 30 分钟 TXT _dmarc v=DMARC1; p=quarantine; rua=mailto:dmarc.report@treesir.pub; ruf=mailto:dmarc.report@treesir.pub; fo=0; adkim=r; aspf=r; pct=100; rf=afrf; ri=86400; sp=quarantine 30 分钟 表中
treesir.pub
注意替换为你自己的 主域名。 -
VPS 服务器设置 反向解析
PTR
(rdns) 记录 -
使用
certbot
生成letsencrypt
证书yum install -y certbot certbot certonly --manual --preferred-challenge dns -d mail.treesir.pub # `此 命令会生成 一条 TXT 记录记录用于验证`
将生成的 TXT 记录添加至 DNS 解析,添加后 使用
dig
进行检查解析是否生效后。生效
没有问题后回车
继续。注意此条记录不要删除
,后续续签证书
时 还需要用到,正常情况下会在/etc/letsencrypt/archive/xxx/
下生成对应域名的证书。yum install bind-utils `# 安装 dig 命令` dig TXT _acme-challenge.mail.treesir.pub `# 检查 解析`
配置定时续签证书
注意添加 crontab 定时任务时,检查一下
crond
服务器 是否有在正常运行。crontab -e `# 打开 crontab 配置文件` 0 5 * * 1 /usr/bin/certbot renew --quiet service crond status `# 检查服务是否正常运行`
部署 docker-mailserver
容器镜像
Clone 仓库地址
git clone https://github.com/docker-mailserver/docker-mailserver.git
更改后的配置展示
docker-compose.yml
文件
version: '3.8'
services:
mailserver:
image: docker.io/mailserver/docker-mailserver:latest
hostname: mail
domainname: treesir.pub
container_name: mailserver
env_file: mailserver.env
dns: 223.5.5.5
ports:
- "25:25"
- "143:143"
- "587:587"
- "993:993"
- "110:110"
- "995:995"
volumes:
- ./data/maildata:/var/mail
- ./data/mailstate:/var/mail-state
- ./data/maillogs:/var/log/mail
- /etc/localtime:/etc/localtime:ro
- ./config/:/tmp/docker-mailserver
- /etc/letsencrypt/archive/mail.treesir.pub:/tmp/ssl:ro
restart: always
stop_grace_period: 1m
cap_add: [ "NET_ADMIN", "SYS_PTRACE" ]
mailserver.env
文件
这里由于文件较长,不方便演示,且打印未注释的代码段
cat mailserver.env |egrep -v '^$|^#'
OVERRIDE_HOSTNAME=
DMS_DEBUG=1
SUPERVISOR_LOGLEVEL=
ONE_DIR=1
POSTMASTER_ADDRESS=yangzun@treesir.pub
ENABLE_UPDATE_CHECK=1
UPDATE_CHECK_INTERVAL=1d
PERMIT_DOCKER=network
NETWORK_INTERFACE=
TLS_LEVEL=
SPOOF_PROTECTION=
ENABLE_SRS=0
ENABLE_POP3=1
ENABLE_CLAMAV=0
ENABLE_AMAVIS=1
AMAVIS_LOGLEVEL=0
ENABLE_FAIL2BAN=0
FAIL2BAN_BLOCKTYPE=drop
ENABLE_MANAGESIEVE=
POSTSCREEN_ACTION=enforce
SMTP_ONLY=
SSL_TYPE=manual
SSL_CERT_PATH=/tmp/ssl/fullchain1.pem
SSL_KEY_PATH=/tmp/ssl/privkey1.pem
SSL_ALT_CERT_PATH=
SSL_ALT_KEY_PATH=
VIRUSMAILS_DELETE_DELAY=
ENABLE_POSTFIX_VIRTUAL_TRANSPORT=
POSTFIX_DAGENT=
POSTFIX_MAILBOX_SIZE_LIMIT=102400000
ENABLE_QUOTAS=1
POSTFIX_MESSAGE_SIZE_LIMIT=102400000
PFLOGSUMM_TRIGGER=
PFLOGSUMM_RECIPIENT=
PFLOGSUMM_SENDER=
LOGWATCH_INTERVAL=
LOGWATCH_RECIPIENT=
REPORT_RECIPIENT=0
REPORT_SENDER=
REPORT_INTERVAL=daily
POSTFIX_INET_PROTOCOLS=all
ENABLE_SPAMASSASSIN=0
SPAMASSASSIN_SPAM_TO_INBOX=1
MOVE_SPAM_TO_JUNK=1
SA_TAG=2.0
SA_TAG2=6.31
SA_KILL=6.31
SA_SPAM_SUBJECT=***SPAM*****
ENABLE_FETCHMAIL=0
FETCHMAIL_POLL=300
ENABLE_LDAP=
LDAP_START_TLS=
LDAP_SERVER_HOST=
LDAP_SEARCH_BASE=
LDAP_BIND_DN=
LDAP_BIND_PW=
LDAP_QUERY_FILTER_USER=
LDAP_QUERY_FILTER_GROUP=
LDAP_QUERY_FILTER_ALIAS=
LDAP_QUERY_FILTER_DOMAIN=
DOVECOT_TLS=
DOVECOT_USER_FILTER=
DOVECOT_PASS_FILTER=
DOVECOT_MAILBOX_FORMAT=maildir
DOVECOT_AUTH_BIND=
ENABLE_POSTGREY=0
POSTGREY_DELAY=300
POSTGREY_MAX_AGE=35
POSTGREY_TEXT=Delayed by Postgrey
POSTGREY_AUTO_WHITELIST_CLIENTS=5
ENABLE_SASLAUTHD=0
SASLAUTHD_MECHANISMS=
SASLAUTHD_MECH_OPTIONS=
SASLAUTHD_LDAP_SERVER=
SASLAUTHD_LDAP_BIND_DN=
SASLAUTHD_LDAP_PASSWORD=
SASLAUTHD_LDAP_SEARCH_BASE=
SASLAUTHD_LDAP_FILTER=
SASLAUTHD_LDAP_START_TLS=
SASLAUTHD_LDAP_TLS_CHECK_PEER=
SASLAUTHD_LDAP_TLS_CACERT_FILE=
SASLAUTHD_LDAP_TLS_CACERT_DIR=
SASLAUTHD_LDAP_PASSWORD_ATTR=
SASL_PASSWD=
SASLAUTHD_LDAP_AUTH_METHOD=
SASLAUTHD_LDAP_MECH=
SRS_SENDER_CLASSES=envelope_sender
SRS_EXCLUDE_DOMAINS=
SRS_SECRET=
DEFAULT_RELAY_HOST=
RELAY_HOST=
RELAY_PORT=25
RELAY_USER=
RELAY_PASSWORD=
上面的 配置含义说明,请参考 此文档
启动容器 & 后续配置工作
docker-compose up -d `# 启动容器`
docker-compose logs -f `# 观察容器 相关日志`
添加 email user
服务器在公网,这里就不要使用
弱密码
了,防止 hacker 进行 暴力破解。
./setup.sh email add yangzun@treesir.pub "xxx" `# 添加 邮件账号及密码`
./setup.sh email update yangzun@treesir.pub "xxx" `# 更新 邮件账号及密码`
生成 DKIM
签名记录
注意下面的配置中,设置了
keysize
参数。原因是默认使用的 keysize 大小为4096
,在aliyun
中 无法进行正常的添加。
./setup.sh config dkim keysize 2048
cat config/opendkim/keys/treesir.pub/mail.txt `# 查看 DKIM 签名记录`
mail._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ojqOcyeDlOn6TcpXCsU92xul6d54wlx/UwPTuE0aywFc+ihyKGAm9D8nmroneN7gf82qTtDbJiHghzRlf6JdpR3kM4ipWKaNRSlUL/64HQqrMeEWx5ErpcgwrXxKWI/rcQ7Rjg2BliP6ayJiEflH0FOtxfgLHnYEcSKupmCV8znM4rZ/LHx9RDwc7o8jWujey6h9zrYPXyqim"
"obGSB0PZGNQhe7mWRefMraFGgnNq+PrtEnmaOFxH2rG1Qh2hhMkeqJsH56yx9f1mxWYTX7r9FtvweGRb+GJNfi6a4vpDrTCffxx6XvGrq032i7VqHpmiaUUuM3j2x1DwHrIbpWTQIDAQAB" ) ; ----- DKIM key mail for treesir.pub
注意生成的记录,需要进行合并起来 才能使用。
添加 DKIM 记录值至 aliyun
DNS 类型 | 记录名 | 记录值 | TTL |
---|---|---|---|
TXT | mail._domainkey | v=DKIM1; h=sha256; k=rsa; p=xxxx | 30 分钟 |
验证测试
测试的平台为
MacOS
&Windows
两个平台 ,由于先前测试使用的工具为Foxmail
会出现无法发送邮件问题 ,所以这里 MacOS 中使用的 邮件工具为 自带应用eM Clien
。
证书验证测试
在进行邮件测试前,可以使用 此链接 中的工具,测试 是否支持
tls
验证。
MacOS & Windows 添加邮件记录
-
macos
-
window
eM Clien
工具会自动为我们配置IMAP
&SMTP
地址信息。
测试邮件发送
-
Windows to MacOS
正常收到邮件了
-
Macos to Windows
回复一个邮件 进行测试
测试 邮件收发 一切正常。
-------------------
看完这篇,你肯定还得看这篇:
如果你想要搭建邮件服务器,不管是多大规模,千万别选腾讯云。血的教训。
为啥呢?
1.腾讯云封了 25 端口,当然仅仅是封 25 端口,问题并不大,目前主流的邮箱服务商都支持邮件的加密传输,25 端口本来也是用不到的,用 465 端口或者 587 端口就好了。想法的确很好,但是我们都能想到的,腾讯又怎么会想不到?接下来才是腾讯的杀招:
2.QQ 邮箱只能通过 25 端口来连接。试想一下,你从零基础学起,看了无数教程,排除了无数故障,不知道白了多少根头发才搭建成的邮件服务器,到头来无法给 QQ 邮箱发邮件,一言难尽。这里还发现一个新的问题,QQ 邮箱不支持 465 端口和 587 端口,安全吗?
结论就是:如果你想要搭建邮件服务器,不管是多大规模,千万别选腾讯云。血的教训。
为啥呢?
1.腾讯云封了 25 端口,当然仅仅是封 25 端口,问题并不大,目前主流的邮箱服务商都支持邮件的加密传输,25 端口本来也是用不到的,用 465 端口或者 587 端口就好了。想法的确很好,但是我们都能想到的,腾讯又怎么会想不到?接下来才是腾讯的杀招:
2.QQ 邮箱只能通过 25 端口来连接。试想一下,你从零基础学起,看了无数教程,排除了无数故障,不知道白了多少根头发才搭建成的邮件服务器,到头来无法给 QQ 邮箱发邮件,一言难尽。
这里还发现一个新的问题,QQ 邮箱不支持 465 端口和 587 端口,安全吗?
这里来说一下这段时间以来,对三个端口的理解:
25 端口,就是最早的 SMTP 协议端口,是不支持加密传输的;
587 端口是 SMTP 协议增加了加密传输之后启用的端口,端口的连接过程和 25 端口是相同的,但是可以通过 STARTTLS 命令启用加密传输;
465 端口是从连接开始就要求是全程加密传输的。
我们来检验一下,首先我们找到 QQ 邮箱的 SMTP 服务器:
$ nslookup -query=mx qq.com
Non-authoritative answer:
qq.com mail exchanger = 20 mx2.qq.com.
qq.com mail exchanger = 30 mx1.qq.com.
qq.com mail exchanger = 10 mx3.qq.com.
...
复制
我们看到有三个服务器,其中 mx3.qq.com 的优先级最高,我们来连接 mx3.qq.com 的 465 端口,实际上,三个服务器的响应都是一致的,因为 465 端口是全程加密连接,所以我们用 openssl 来连接,如下:
$ openssl s_client -connect mx3.qq.com:465 -crlf -4
40CC6696657F0000:error:8000006E:system library:BIO_connect:Connection timed out:../crypto/bio/bio_sock2.c:125:calling connect()
40CC6696657F0000:error:10000067:BIO routines:BIO_connect:connect error:../crypto/bio/bio_sock2.c:127:
connect:errno=110
$ openssl s_client -connect mx3.qq.com:465 -crlf -6
407C4295987F0000:error:80000065:system library:BIO_connect:Network is unreachable:../crypto/bio/bio_sock2.c:125:calling connect()
407C4295987F0000:error:10000067:BIO routines:BIO_connect:connect error:../crypto/bio/bio_sock2.c:127:
connect:errno=101
复制
结果和我们在 postfix 日志中看到的一致,ipv4 地址超时,ipv6 地址无法连接,QQ 邮箱根本就不开放 465 端口,这也是很多人将 postfix 改成通过 465 端口发送邮件之后,仍然无法给 QQ 邮箱发邮件的原因。我们再尝试 587 端口,如下:
telnet mx3.qq.com 587
Trying 120.241.17.157...
Trying 2402:4e00:8010::b0...
telnet: Unable to connect to remote host: Network is unreachable
复制
587 端口同样无法连接,再尝试 25 端口,如下:
$ telnet mx3.qq.com 25
Trying 120.241.17.157...
Connected to mx3.qq.com.
Escape character is '^]'.
220 newxmmxsza11-4.qq.com MX QQ Mail Server.
ehlo mx3.qq.com
250-newxmmxsza11-4.qq.com
250-STARTTLS
250-8BITMIME
250-SIZE 73400320
250 OK
quit
221 Bye.
Connection closed by foreign host.
复制
我们看到 25 端口支持 STARTTLS 命令,也就是说 QQ 邮箱在 25 端口上做了 587 端口的事情,即保障了传输安全,又让 587 端口下了岗。这就是腾讯的个性,走出了自己的路,让别人无路可走。
看来只有申请解封 25 端口这一条路了,我们看看腾讯云是这样说的:
为了提升腾讯云 IP 地址发邮件的质量,默认限制云服务器 TCP 25 端口连接外部地址,如果您没有在云上部署邮件服务,该限制不会影响您的服务;如果您需要使用邮件服务,我们诚挚地向您推荐 腾讯企业邮箱。如果您一定要使用云主机向外连接 TCP 25 端口,请确保 TCP 25 端口仅用来连接第三方 SMTP 服务器,从第三方 SMTP 服务器外发邮件。如发现您使用云主机直接 SMTP 发送邮件,腾讯云有权永久封禁 TCP 25 端口,并不再提供相关服务。
企业邮箱这个提议,看的我都有点动心了,省时省力,不用担心服务器被黑,不担心垃圾邮件,虽然花点钱,但是值。而且不想花钱的也可以选择免费版。但我没有企业,更没有营业执照,想买企业邮箱,钱都花不出去。
我们把 SMTP 协议看作是一个邮局,它有两个窗口,一个窗口面向发邮件的个人,一个窗口面向其他邮局。
假设场景:用户甲、乙,邮局子、丑,甲给乙写一封信,然后拿着信来到子的个人窗口,子要求甲进行身份验证,验证成功,子收下信,然后将信送达乙所在的邮局丑的邮局窗口,丑核实子的邮局资质,以及乙是否是丑的客户,核实成功,丑收下信,然后投递到乙的邮箱。
我们看到个人窗口和邮局窗口功能不同,职责不同,对客户的要求也不同,在 SMTP 协议上都使用同一个端口。在实现上,邮箱服务商通常通过不同的域名将两个窗口拆开。
上面我们看到 mx3.qq.com 就是 QQ 邮箱的对邮局窗口,不收个人信件,而我们所熟知的 smtp.qq.com 是个人窗口,不收其它邮局发来的信件,我们来看下 QQ 邮箱个人窗口提供的服务,我们尝试连接 465 端口,如下:
$ openssl s_client -connect smtp.qq.com:465 -crlf
...
220 newxmesmtplogicsvrszc9.qq.com XMail Esmtp QQ Mail Server.
ehlo smtp.qq.com
250-newxmesmtplogicsvrszc9.qq.com
250-PIPELINING
250-SIZE 73400320
250-AUTH LOGIN PLAIN XOAUTH XOAUTH2
250-AUTH=LOGIN
250-MAILCOMPRESS
250 8BITMIME
mail from: <xxxx@yyyy.com>
503 Error: need EHLO and AUTH first !
405CE295207F0000:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:../ssl/record/rec_layer_s3.c:308:
复制
连接成功后,会看服务器返回 220 之前有好大一段的证书相关的内容,像我这样的业余人士,直接忽略就好了。
我们看到 smtp.qq.com 返回了 250-AUTH LOGIN PLAIN XOAUTH XOAUTH2,表明它提供 4 种身份验证服务,在这里身份验证是必须的,不登陆不能发送邮件,会被拒绝,而且要求发件人和登陆的用户必须为同一人。
同样我们可以验证 25 和 587 端口都能够连接,提供的服务也是相同的。
而 mx3.qq.com 则不提供身份验证服务,个人用户如果跑到这里来发邮件,人家可不会给你好脸色。在这里,它会对发邮件的邮局进行资质认证,以确保不是冒名邮件或垃圾邮件,同时要求收件人必须时本邮局的客户。
腾讯云解封 25 端口的条件,简单来说,腾讯云允许你作为一个普通用户去寄信,而不能提供邮箱服务。也就是说,你可以连接 smtp.qq.com,而 smtp.qq.com 支持 465 和 587 端口,没有开 25 端口的必要。你不可以连接 mx3.qq.com,即便是开了 25 端口也不可以。
所以,解封 25 端口这条路也被堵死了。