如果你愿意购买第三方的邮件服务,那完全可以跳过邮件服务配置指南,并不影响后续的操作。但如果你是个热爱学习的人,那么不妨耐心的看完本章,学习更多关于邮件服务的知识。
📧 构建安全可靠的邮件服务器
搭建一套具备收发能力、安全机制、加密保障的邮件服务器,不仅需要掌握 SMTP/IMAP 等协议原理,还涉及操作系统层面、网络层面和安全策略的深度配置。
本系列文档共分为 四篇文章,系统讲解了邮件服务器从搭建到部署、从加密到防伪的全过程:
邮件服务器基础搭建:涵盖收发机制、域名解析、SSL 部署与 Postfix 主配置
邮件身份防伪机制:详解 SPF、DKIM、DMARC 的实现与校验流程
加密传输机制:配置 STARTTLS、SMTP Submission 和客户端身份认证
邮件收取服务与客户端支持:部署 IMAPS、安全接收外部邮件、客户端配置要点
📌 第一部分:基础配置全景
本文是系列的第一篇,旨在为整个系统打下坚实的基础。我们将围绕以下几个关键模块展开:
1. ✉️ 邮件收发机制原理
- 理解收发邮件的大致过程
- 理解邮件收发过程中域名记录的作用
2. 🌐 域名解析与 PTR 反向记录
- 配置 MX 记录 指向邮件主机名(如
mail.example.com
) - 设置 A 记录 解析主机名至公网 IP
- 必须设置 PTR 反向解析记录,确保邮件服务器不会被拒信或误判为垃圾源
🚨 邮件系统对 DNS 解析的依赖远超一般网站部署,不可忽视!
3. 🔐 SSL/TLS 证书申请
- 申请 Let’s Encrypt 或商业 SSL 证书
- 配置服务器使用自有证书,实现 SMTP/IMAP 的 TLS 加密通道
4. 📦 Postfix 安装与基础配置
- 安装 Postfix,配置
/etc/postfix/main.cf
主体参数 - 理解主体参数的作用
5. 🔥 防火墙与端口策略开放
- 合理放行端口,保障内外通信
📌 后续章节将继续深入:
- 如何让发出的邮件不被误判为垃圾?(SPF、DKIM、DMARC)
- 如何实现客户端加密收发?(STARTTLS、SMTP Submission)
- 如何支持邮件客户端?(以ThunderBird为例)
邮件收发原理简述
收发邮件的原理,本质上是基于SMTP、IMAP和POP3这三个核心协议来完成邮件传递和读取的。
邮件发送过程(Send):
- 用户撰写邮件,点击发送。
- 发件客户端(Outlook、Thunderbird、Webmail等)通过SMTP协议将邮件发送到发件方的邮件服务器。
- 发件服务器通过DNS查询MX记录找到收件人域名所对应的邮件服务器地址。
- 然后通过SMTP把邮件投递到收件人服务器。
- 收件人邮件服务器保存该邮件,等待收件人查收。
邮件接收过程(Receive)
- 收件人客户端通过IMAP或POP3协议去自己的邮件服务器拉取邮件。
- 用户阅读、回复、删除邮件等。
域名解析环节
在邮件投递过程中,发件服务器会通过DNS查询:
- MX记录(Mail Exchange):查找收件人域名的邮件服务器。
- A记录/IPv4地址:找到邮件服务器的IP。
- SPF、DKIM、DMARC记录:验证发件人的身份、邮件是否被篡改等。
接下来,我们根据上述原理来部署一台邮件服务器。
配置域名解析
我们进入域名管理页面,配置HOSTNAME
为mail的A记录、和一条TARGET HOSTNAME
为mail.example.com的MX记录即可。
配置PTR(反向解析)
为什么邮件服务器需要反向DNS记录?
1. 反垃圾邮件验证机制之一
- 邮件接收方服务器(如Gmail、Outlook、QQ邮箱)通常会做以下检查:
- 发件服务器的IP是否有PTR记录;
- PTR指向的主机名是否能正向解析回同一个IP;
- 主机名是否和邮件头信息匹配;如果没有正确配置反向DNS,邮件有较高概率被拒收或进入垃圾箱。
2. 反向记录是SMTP标准推荐的行为
- RFC反垃圾机制建议发信服务器应配置反向解析记录,以便接收方进行IP归属验证。
3. 建立信誉,提高送达率
- 一些邮件服务(如 Microsoft Outlook、Yahoo)会将没有PTR记录的服务器打入“低信誉IP池”,造成邮件延迟或直接退信。
通常,PTR记录需要在虚拟主机的管理页面中设置,请将PTR记录设置成你的邮件服务器主机名,即mail.example.com。设置完成后,执行下面的命令验证:
$ dig -x youripaddr #结果返回指向mail.example.com的PTR记录。
申请SSL证书
在上一章中,我们为HTTP服务申请了SSL证书。同样的,邮件服务也支持SSL,用于提高邮件传输过程中的安全性。
$ sudo certbot certonly --webroot -w /usr/share/nginx/html/ -d mail.example.com
如果这一步报permission denied相关的错误,执行下面的命令将html目录的owner改为nginx用户,然后再尝试申请证书:
$ sudo chown nginx:nginx /usr/share/nginx/html
你可能要问为什么这里的选项是–webroot?这是因为当前有HTTP Server在运行并且占用了80端口,而certbot的standalone模式会启用一个web应用与let’s encrypt服务器通信,这个应用也会占用80端口。所以在这种情况下standalone模式会导致端口冲突从而引起申请证书失败。
最终你将获得一对用于mail.example.com的证书。证书位于:
/etc/letsencrypt/live/mail.example.com/fullchain.pem #公钥
/etc/letsencrypt/live/mail.example.com/privkey.pem #私钥
Postfix安装及配置
安装:
$ sudo dnf install postfix
配置:
假设你的域名是example.com
$ sudo vim /etc/postfix/main.cf
去掉下面字段前的注释,并修改:
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
mynetworks = [::1]/128, 127.0.0.0/8
relayhost =
smtp_tls_security_level = may
inet_interfaces = all
inet_protocols = ipv4
下面来解释一下这组配置:
1. myhostname = mail.example.com
作用:定义这台邮件服务器的主机名(FQDN)。
- Postfix会将它用作SMTP连接时的EHLO主机名。
- 通常应该设置为你邮件服务器的DNS记录。
2. mydomain = example.com
作用:定义你的邮件域名。
- 通常是
myhostname
的主域部分。 - 用于构建其他相关配置,如
myorigin
、邮件地址后缀等。
3. myorigin = $mydomain
作用:定义“本地用户”发送邮件时使用的域名。
- 比如用户admin使用
mail
命令发送邮件,发送地址会是:admin@example.com
4. mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
作用:指定哪些域名的邮件是投递到本地(本机邮箱)的。
- 一般包括:
- 本机的主机名(
$myhostname
) - 本地环回(
localhost
) - 主域名(
$mydomain
)
- 本机的主机名(
如果邮件的收件人地址的域在这个列表中,则Postfix会将邮件投递到本地用户邮箱,而不是转发出去。
5. mynetworks = [::1]/128, 127.0.0.0/8
作用:指定哪些客户端IP被信任,可以“直接发信”而不需要认证。
- 默认只允许本地回环地址:
[::1]/128
是IPv6的localhost;127.0.0.0/8
是IPv4的localhost范围。
注意:不要轻易添加公网IP段,否则可能被滥用为中继发垃圾邮件!
6. relayhost =
作用:设置发送外部邮件时所使用的中继服务器。
- 留空表示邮件直接由本机投递。
- 如果你希望通过其他SMTP服务(如Gmail SMTP、腾讯企业邮等)中继发信,才需设置。
7. smtp_tls_security_level = may
作用:开启TLS加密传输的最低级别支持。
may
:如果对方支持TLS,则使用,否则继续明文发送。
8. inet_interfaces = all
作用:监听所有网络接口接收SMTP连接。
- 通常默认是
all
,如果你只想监听内网或某一IP,可单独指定。
9. inet_protocols = ipv4
作用:指定Postfix使用的网络协议版本。
- 设置为
ipv4
表示只监听IPv4,不使用IPv6。
启动postfix:
$ sudo systemctl enable --now postfix
配置防火墙规则
放行25端口的流量:
$ sudo firewall-cmd --permanent --add-port=25/tcp
$ sudo firewall-cmd --reload