1. 为什么自建邮件发送服务依然值得投入
很多人觉得现在云厂商的邮件推送服务已经足够便宜,没必要自己折腾邮件服务器。我一开始也这么想,直到手上一个项目需要每天向几千个用户发送带附件的报表,用第三方推送服务算下来一个月成本不低,而且附件大小受限、发送频率被卡、模板审核流程繁琐。后来咬咬牙用 Postfix 搭了一套自己的 SMTP 发送服务,跑了大半年,稳定性和可控性远超预期。
Postfix 是一个老牌的邮件传输代理(MTA),它的设计目标就是安全和高效。相比 Sendmail 那种配置文件像天书一样的东西,Postfix 的配置逻辑清晰得多,每个参数都有明确的含义,出问题也容易定位。用它搭建一个“只负责对外发送、不接收外部来信”的 SMTP 服务,是最常见的用法之一——你不需要处理复杂的收信逻辑、不需要维护用户邮箱、不需要担心被人当成垃圾邮件中转站,只需要让它老老实实把你要发的邮件投递出去就行。
这套方案适合谁?如果你是一个开发者,手上有应用需要发通知邮件、报表邮件、验证码邮件;如果你是一个运维,想给内部系统搭一个统一的发信出口;如果你是一个技术爱好者,想搞清楚邮件发送到底是怎么回事——那这套东西都值得你花一个下午的时间搞明白。我下面会把整个搭建过程拆开揉碎,从原理到配置到排错,尽量让第一次接触的人也能跟着做下来。
2. 搭建前的整体设计与关键决策
2.1 为什么选择 Postfix 而不是其他方案
邮件服务器软件有好几个选择,Sendmail 太老且配置复杂,Exim 功能强但学习曲线陡,Postfix 在安全性、性能和易用性之间取得了很好的平衡。它的架构是模块化的,每个进程只负责一小块功能,比如 smtpd 负责接收、qmgr 负责队列管理、smtp 负责对外投递。这种设计的好处是,即使某个模块出问题,也不会把整个服务拖垮。
另一个重要原因是 Postfix 和 Dovecot、OpenDKIM、OpenDMARC 这些周边工具的配合非常成熟。你要发对外邮件,光把邮件扔出去是不够的,还得让收件方相信这封邮件不是垃圾邮件。这就涉及到 SPF、DKIM、DMARC 三件套,Postfix 可以很方便地和这些工具集成。
2.2 只发不收的架构设计
我建议的架构是:Postfix 监听本地的 25 端口(或者一个自定义端口),只接受来自本机或内网特定 IP 的邮件提交请求,然后通过 SMTP 协议把邮件投递到收件方的邮件服务器。整个链路是这样的:
- 你的应用通过 SMTP 协议连接本机的 Postfix
- Postfix 把邮件放入队列
- Postfix 根据收件人域名查询 DNS 的 MX 记录
- Postfix 连接目标邮件服务器并投递
这个过程中,你的服务器不需要对外开放 25 端口,不需要处理任何入站邮件,大大降低了安全风险。我见过不少人把邮件服务器配成开放中继,结果被垃圾邮件发送者利用,几天之内 IP 就被拉黑了。只发不收的架构天然避免了这个问题。
2.3 关于 IP 和域名的准备工作
在动手之前,有几件事必须先确认。第一,你需要一个能配置反向解析(PTR 记录)的 IP 地址。大部分云服务商的默认 IP 是不带反向解析的,你需要提交工单申请。反向解析的作用是让收件方通过 IP 反查域名时,能得到一个和你发信域名一致的结果。很多大型邮件服务商(比如 Gmail、Outlook)会把没有反向解析的 IP 直接拒掉或者扔进垃圾箱。
第二,你需要一个域名,并且能修改它的 DNS 记录。这个域名将用于发信人地址的后缀,比如noreply@yourdomain.com。你需要在 DNS 里添加 SPF 记录、DKIM 记录和 DMARC 记录,这些是让邮件顺利送达的关键。
第三,确认你的网络环境没有封锁 25 端口。部分云服务商默认封禁 25 端口的出站流量,需要申请解封。如果 25 端口出不去,可以考虑用 587 端口(提交端口)或者 465 端口(SMTPS)作为替代,但最终投递到对方服务器还是走 25 端口,所以出站 25 端口必须通。
3. Postfix 核心配置逐项拆解
3.1 安装与基础环境准备
在常见的 Linux 发行版上安装 Postfix 都很简单。以 Debian/Ubuntu 系为例:
apt update apt install postfix mailutils libsasl2-modules -y安装过程中会弹出一个配置向导,让你选择“Internet Site”还是“Satellite system”等。这里选“Internet Site”,系统邮件名填你的域名。如果错过了向导,可以用dpkg-reconfigure postfix重新配置。
安装完成后,Postfix 的主配置文件在/etc/postfix/main.cf,这是最重要的文件。我建议在修改之前先备份一份:
cp /etc/postfix/main.cf /etc/postfix/main.cf.bak3.2 main.cf 关键参数详解
下面是我实际使用的一套配置,逐项解释每个参数的作用。
# 主机名,必须是一个完整的域名 myhostname = mail.yourdomain.com # 发信域名,出现在邮件头中 mydomain = yourdomain.com # 发信人地址的域名部分 myorigin = $mydomain # 监听的网络接口,all 表示所有接口 inet_interfaces = all # 只监听 IPv4,避免 IPv6 带来的额外复杂度 inet_protocols = ipv4 # 允许哪些网段通过本服务器发信 mynetworks = 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 # 不接收任何外部域名的邮件 relay_domains = # 只允许本机和中继网段发信 smtpd_relay_restrictions = permit_mynetworks, reject_unauth_destination # 收件人域名限制 smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination # 邮件队列相关 queue_directory = /var/spool/postfix mailbox_size_limit = 0 message_size_limit = 52428800 # TLS 相关配置 smtpd_tls_cert_file = /etc/ssl/certs/mail.crt smtpd_tls_key_file = /etc/ssl/private/mail.key smtpd_tls_security_level = may smtp_tls_security_level = may smtp_tls_loglevel = 1这里有几个参数值得展开说。mynetworks决定了哪些 IP 可以直接通过你的服务器发信而不需要认证。如果你只在本机发信,保留127.0.0.0/8就够了。如果内网其他机器也要用,把对应网段加进去。千万不要写成0.0.0.0/0,那等于把服务器变成开放中继,后果很严重。
smtpd_relay_restrictions和smtpd_recipient_restrictions是安全的核心。permit_mynetworks允许信任网段发信,reject_unauth_destination拒绝所有不在允许范围内的投递请求。这两个配合起来,就能保证你的服务器只为你自己的域名发信。
message_size_limit我设成了 50MB,因为有时候要发带附件的报表。默认值通常只有 10MB 左右,如果你要发大附件,记得调大这个值,同时也要注意mailbox_size_limit和queue_minfree的配合。
3.3 配置发信认证
如果你的应用不在mynetworks范围内,或者你想更精细地控制谁能发信,可以启用 SASL 认证。Postfix 本身不提供认证功能,需要配合 Dovecot 或者 Cyrus SASL。
用 Dovecot 做 SASL 是比较现代的做法。先安装 Dovecot:
apt install dovecot-core dovecot-imapd -y然后在/etc/dovecot/conf.d/10-master.conf中确保以下内容存在:
service auth { unix_listener /var/spool/postfix/private/auth { mode = 0666 user = postfix group = postfix } }接着在/etc/postfix/main.cf中添加:
smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = $myhostname broken_sasl_auth_clients = yes这样配置之后,你的应用就可以用用户名密码通过 587 端口提交邮件了。记得在master.cf中确认 587 端口的 submission 服务是开启的:
submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_relay_restrictions=permit_sasl_authenticated,reject3.4 配置 SPF、DKIM 和 DMARC
这三样东西是邮件送达率的命脉。SPF 告诉收件方哪些 IP 有权代表你的域名发信,DKIM 给邮件加上数字签名让收件方验证邮件没被篡改,DMARC 则告诉收件方当 SPF 和 DKIM 验证失败时该怎么处理。
SPF 记录是一条 TXT 记录,加在你的域名 DNS 里:
v=spf1 ip4:你的服务器IP -all最后的-all表示除了列出的 IP,其他所有 IP 发来的邮件都视为伪造。如果你还用其他服务发信,把它们的 IP 或域名也加进去。
DKIM 需要安装 OpenDKIM:
apt install opendkim opendkim-tools -y生成密钥对:
opendkim-genkey -b 2048 -d yourdomain.com -s mail这会在当前目录生成mail.private和mail.txt。把mail.private放到/etc/opendkim/keys/yourdomain.com/下,然后把mail.txt里的内容作为 TXT 记录加到 DNS 里,记录名是mail._domainkey.yourdomain.com。
配置 OpenDKIM 与 Postfix 集成,在/etc/opendkim.conf中设置:
Domain yourdomain.com Selector mail KeyFile /etc/opendkim/keys/yourdomain.com/mail.private Socket inet:12301@localhost然后在 Postfix 的main.cf中添加:
milter_default_action = accept milter_protocol = 6 smtpd_milters = inet:localhost:12301 non_smtpd_milters = inet:localhost:12301DMARC 记录也是一条 TXT 记录:
v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.comp=quarantine表示验证失败的邮件建议收件方放入垃圾箱。刚开始可以先设p=none只做监控,确认没问题后再收紧。
4. 完整实操流程与验证方法
4.1 从零开始的部署步骤
假设你拿到了一台全新的 Linux 服务器,有一个已经解析到这台服务器的域名,并且反向解析也配好了。下面是完整的操作顺序。
第一步,设置主机名。编辑/etc/hostname写入mail.yourdomain.com,然后在/etc/hosts中添加一行127.0.0.1 mail.yourdomain.com mail。这一步很重要,Postfix 启动时会用主机名来标识自己,如果主机名解析有问题,邮件头会很难看,甚至被拒收。
第二步,安装 Postfix 和必要工具。除了前面提到的包,我还建议装上swaks,这是一个命令行发信测试工具,比mail命令好用得多:
apt install swaks -y第三步,修改main.cf。把前面列出的参数按你的实际情况填进去。特别注意myhostname必须是完整域名,mydomain是主域名,myorigin通常设成$mydomain。
第四步,配置 TLS 证书。你可以用 Let's Encrypt 免费申请:
apt install certbot -y certbot certonly --standalone -d mail.yourdomain.com证书生成后,在main.cf中指向对应的文件路径。注意 Postfix 需要读取私钥,权限要设置正确:
chmod 640 /etc/letsencrypt/live/mail.yourdomain.com/privkey.pem chown root:postfix /etc/letsencrypt/live/mail.yourdomain.com/privkey.pem第五步,启动服务并设置开机自启:
systemctl restart postfix systemctl enable postfix systemctl restart opendkim systemctl enable opendkim4.2 用 swaks 做第一轮发信测试
配置完成后,先用 swaks 发一封测试邮件到自己的另一个邮箱:
swaks --to yourtest@gmail.com \ --from noreply@yourdomain.com \ --server 127.0.0.1 \ --port 25 \ --header "Subject: Test Email" \ --body "This is a test message."如果一切正常,你会看到 swaks 输出完整的 SMTP 对话过程,最后显示250 OK。去收件箱看看,如果收到了,检查邮件头里的 SPF、DKIM、DMARC 是否都显示 pass。Gmail 的话,点邮件右上角的三个点,选“显示原始邮件”,搜索Authentication-Results这一行。
如果没收到,先检查垃圾邮件文件夹。如果垃圾箱里也没有,看 Postfix 的日志:
tail -f /var/log/mail.log日志会告诉你邮件是发出去了还是被拒了,被拒的原因是什么。
4.3 日志分析与送达率优化
Postfix 的日志非常详细,每一封邮件的生命周期都有记录。常见的日志行包括:
postfix/smtpd:接收连接postfix/cleanup:邮件进入队列postfix/qmgr:队列管理postfix/smtp:对外投递postfix/bounce:退信处理
如果看到status=sent,说明邮件成功投递到对方服务器。如果看到status=deferred,说明暂时投递失败,Postfix 会按一定间隔重试。如果看到status=bounced,说明永久失败,邮件被退回。
送达率优化是一个持续的过程。除了 SPF、DKIM、DMARC,还要注意以下几点:发信频率不要突然暴增,新 IP 要慢慢“热身”;邮件内容避免大量图片和短链接,这些容易触发垃圾邮件规则;退信率要控制在 5% 以下,退信太多说明你的收件人列表质量有问题;投诉率要低于 0.1%,有人点“举报垃圾邮件”对发信信誉影响很大。
5. 常见问题与排查技巧实录
5.1 邮件被拒收的典型原因
下面这张表是我在实际运维中整理出来的常见拒收原因和对应解法。
| 错误信息关键词 | 含义 | 解决方法 |
|---|---|---|
Connection refused | 对方 25 端口不通 | 检查目标服务器是否存活,或你的出站 25 是否被封 |
Relay access denied | 你的服务器不允许中继 | 检查mynetworks和smtpd_relay_restrictions |
SPF fail | SPF 验证不通过 | 检查 DNS 里的 SPF 记录是否包含你的发信 IP |
DKIM fail | DKIM 签名验证失败 | 检查 OpenDKIM 是否运行,密钥和 DNS 记录是否匹配 |
DMARC fail | DMARC 策略不通过 | 通常是 SPF 或 DKIM 有问题导致的连锁反应 |
Greylisted | 对方暂时拒收 | 等待几分钟后重试,Postfix 会自动处理 |
Blacklisted | IP 在黑名单里 | 去对应黑名单网站申请移除,检查是否被入侵 |
Message size exceeds limit | 邮件太大 | 调大message_size_limit,或改用链接下载 |
5.2 队列积压的处理方法
有时候你会看到邮件队列里堆了很多邮件,用mailq命令可以查看。如果队列太长,先别急着删,搞清楚原因再说。
mailq | tail -n 1这行会显示队列总大小和邮件数量。如果数量在几百以内,通常等一会儿就消化了。如果持续增长,可能是网络问题或者对方服务器在限速。
强制立即重试所有队列中的邮件:
postqueue -f删除队列中所有邮件(慎用):
postsuper -d ALL删除特定队列 ID 的邮件:
postsuper -d QUEUE_ID我个人的经验是,队列积压超过 1000 封就要警惕了。先看日志里有没有大量deferred,如果有,看deferred的原因是什么。如果是某个特定域名的问题,可以考虑暂时把那个域名加入transport_maps走不同的投递策略。
5.3 被当成垃圾邮件的排查思路
邮件进了对方的垃圾箱,这是最让人头疼的问题。排查思路是这样的:先确认 SPF、DKIM、DMARC 是否都 pass,这是基础。如果这三项有问题,先解决它们。如果三项都 pass 但还是进垃圾箱,那就要看内容评分和 IP 信誉了。
内容方面,避免使用“免费”、“立即行动”、“限时优惠”这类营销词汇,避免全大写标题,避免过多感叹号,图片和文字的比例要合理。IP 信誉方面,可以去一些公开的信誉查询网站看看你的 IP 有没有被列入黑名单。新 IP 建议先发少量邮件,慢慢增加量,让各大邮件服务商逐渐建立对你的信任。
还有一个容易被忽略的点:Message-ID和Date头。Postfix 默认会生成这两个头,但如果你用某些编程语言的邮件库发信,可能会覆盖它们。确保这两个头格式正确,否则也会影响评分。
5.4 安全加固的几条硬规矩
最后说几条安全方面的硬规矩,都是踩过坑之后总结出来的。
第一条,永远不要配置开放中继。mynetworks里只写你信任的网段,smtpd_relay_restrictions里必须有reject_unauth_destination。我见过有人图省事写成permit,结果服务器被利用发了上万封垃圾邮件,IP 直接被封。
第二条,限制发信频率。Postfix 本身有一些限速参数,比如smtpd_client_connection_rate_limit、smtpd_client_message_rate_limit,可以根据需要设置。如果你的应用发信量很大,建议在应用层也做限流,避免突发流量把服务器打挂。
第三条,定期更新软件。Postfix、OpenDKIM、Dovecot 都会不定期发布安全补丁,保持更新是最基本的安全措施。
第四条,监控日志和队列。设置一个简单的监控脚本,当队列长度超过阈值或者日志中出现大量错误时发告警。我一般用mailq | tail -n 1配合grep来做,简单有效。
第五条,备份配置文件。main.cf、master.cf、OpenDKIM 的密钥和配置,这些都要定期备份。有一次我迁移服务器,忘了备份 DKIM 私钥,结果所有邮件的 DKIM 签名都失效了,重新生成密钥并更新 DNS 又花了大半天时间。
这套 Postfix 发信服务我用了大半年,每天稳定发送几千封邮件,送达率保持在 98% 以上。中间遇到过几次小问题,基本都是 DNS 记录或者队列积压导致的,按照上面的排查思路都能很快解决。如果你也在考虑自建发信服务,希望这些经验能帮你少走一些弯路。