
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 协议连接本机的 PostfixPostfix 把邮件放入队列Postfix 根据收件人域名查询 DNS 的 MX 记录Postfix 连接目标邮件服务器并投递这个过程中你的服务器不需要对外开放 25 端口不需要处理任何入站邮件大大降低了安全风险。我见过不少人把邮件服务器配成开放中继结果被垃圾邮件发送者利用几天之内 IP 就被拉黑了。只发不收的架构天然避免了这个问题。2.3 关于 IP 和域名的准备工作在动手之前有几件事必须先确认。第一你需要一个能配置反向解析PTR 记录的 IP 地址。大部分云服务商的默认 IP 是不带反向解析的你需要提交工单申请。反向解析的作用是让收件方通过 IP 反查域名时能得到一个和你发信域名一致的结果。很多大型邮件服务商比如 Gmail、Outlook会把没有反向解析的 IP 直接拒掉或者扔进垃圾箱。第二你需要一个域名并且能修改它的 DNS 记录。这个域名将用于发信人地址的后缀比如noreplyyourdomain.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 是比较现代的做法。先安装 Dovecotapt 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_namepostfix/submission -o smtpd_tls_security_levelencrypt -o smtpd_sasl_auth_enableyes -o smtpd_relay_restrictionspermit_sasl_authenticated,reject3.4 配置 SPF、DKIM 和 DMARC这三样东西是邮件送达率的命脉。SPF 告诉收件方哪些 IP 有权代表你的域名发信DKIM 给邮件加上数字签名让收件方验证邮件没被篡改DMARC 则告诉收件方当 SPF 和 DKIM 验证失败时该怎么处理。SPF 记录是一条 TXT 记录加在你的域名 DNS 里vspf1 ip4:你的服务器IP -all最后的-all表示除了列出的 IP其他所有 IP 发来的邮件都视为伪造。如果你还用其他服务发信把它们的 IP 或域名也加进去。DKIM 需要安装 OpenDKIMapt 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:12301localhost然后在 Postfix 的main.cf中添加milter_default_action accept milter_protocol 6 smtpd_milters inet:localhost:12301 non_smtpd_milters inet:localhost:12301DMARC 记录也是一条 TXT 记录vDMARC1; pquarantine; ruamailto:dmarcyourdomain.compquarantine表示验证失败的邮件建议收件方放入垃圾箱。刚开始可以先设pnone只做监控确认没问题后再收紧。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 证书。你可以用 Lets 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 yourtestgmail.com \ --from noreplyyourdomain.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退信处理如果看到statussent说明邮件成功投递到对方服务器。如果看到statusdeferred说明暂时投递失败Postfix 会按一定间隔重试。如果看到statusbounced说明永久失败邮件被退回。送达率优化是一个持续的过程。除了 SPF、DKIM、DMARC还要注意以下几点发信频率不要突然暴增新 IP 要慢慢“热身”邮件内容避免大量图片和短链接这些容易触发垃圾邮件规则退信率要控制在 5% 以下退信太多说明你的收件人列表质量有问题投诉率要低于 0.1%有人点“举报垃圾邮件”对发信信誉影响很大。5. 常见问题与排查技巧实录5.1 邮件被拒收的典型原因下面这张表是我在实际运维中整理出来的常见拒收原因和对应解法。错误信息关键词含义解决方法Connection refused对方 25 端口不通检查目标服务器是否存活或你的出站 25 是否被封Relay access denied你的服务器不允许中继检查mynetworks和smtpd_relay_restrictionsSPF failSPF 验证不通过检查 DNS 里的 SPF 记录是否包含你的发信 IPDKIM failDKIM 签名验证失败检查 OpenDKIM 是否运行密钥和 DNS 记录是否匹配DMARC failDMARC 策略不通过通常是 SPF 或 DKIM 有问题导致的连锁反应Greylisted对方暂时拒收等待几分钟后重试Postfix 会自动处理BlacklistedIP 在黑名单里去对应黑名单网站申请移除检查是否被入侵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 记录或者队列积压导致的按照上面的排查思路都能很快解决。如果你也在考虑自建发信服务希望这些经验能帮你少走一些弯路。