给监控系统当“邮差”一次 Postfix 只发不收邮箱的搭建实录搞运维的同学应该都有这种体会半夜两点被告警短信震醒爬起来一看发现是误报又或者监控平台推了一堆提醒结果全被企业邮箱当成垃圾邮件拒了。反反复复折腾之后你会意识到一个问题——监控告警邮件其实不需要一个功能完整的邮箱系统它只需要一个能发信、带认证、稳定不罢工的“发信通道”就够了。我之前一直在用某个第三方企业邮箱发监控告警但维护的服务器多了之后每次换邮箱密码、配频率限制都要和公司IT部门来回沟通实在是麻烦。后来干脆自己搭了一套仅用于外发的 Postfix 邮件服务器配合用户认证专门给 Zabbix、Prometheus Alertmanager、各类脚本跑批结果做消息推送。这套方案跑了两年多稳定发给 163、QQ、Gmail 和公司内部邮箱几乎没有被拒信。今天把它完整记录下来从需求分析到认证选型再到最终配置和排坑一次性讲透。这套方案适合谁如果你是运维工程师、SRE、后端开发手头有监控告警、定时任务、CI/CD 流水线需要发邮件通知又不想用第三方邮箱的复杂策略限制那你花一个小时照着这篇文章搭一套之后一劳永逸。全文以 Debian/Ubuntu 系统为例其他发行版命令略有差异但思路完全相同。1. 为什么只发不收以及认证方案怎么选1.1 单一职责原则下的“发信专用通道”先说核心需求邮件服务器只发不收并且启用用户认证。这里面有两个关键约束很多人第一次搭的时候容易把整件事想复杂。只发不收意味着这台服务器不需要接收外部来信不需要为每个员工创建邮箱账户也不需要处理 IMAP/POP3 收件服务。它要做的只有一件事接收来自内网监控系统或脚本的连接通过认证后把邮件交给上游或直接投递到目标邮箱。这么设计的好处非常明显安全面最小化。没有收件服务就没有远程投递攻击面别人想利用你服务器发垃圾邮件也很难突破认证层配置量大幅减少。不需要配置 virtual_mailbox_domains、不需要 Dovecot 的收件存储、不需要 SPF 的 MX 记录指向配置量砍掉一半以上运维心智负担低。把“发信”和“收信”两种职责解耦出问题时排查链路短日志量小。从架构上看这套 Postfix 在告警链路里扮演的是一个“本地 SMTP 出口网关”的角色。监控系统调用它它负责和外界的邮件服务器打交道。真正的难点不在 Postfix 本身而在于如何用安全的认证方式让合法的内网用户能发信同时挡住非授权用户。1.2 三种认证选型系统用户、SASL 库、LDAP 统一认证“用户认证”是标题里的重点也是方案选型的核心决策点。Postfix 自身不直接管理用户密码它是通过 SASLSimple Authentication and Security Layer框架来对接认证源的。常见的方案有以下三种我按实际落地情况做个对比。第一系统用户认证Cyrus SASL sasldb。把账号密码存在本地 sasldb 文件里Postfix 通过 saslauthd 或 sasldb 直接验证。优点是配置简单不需要额外依赖缺点是账号密码和系统用户分离账号多了不好管理而且 saslauthd 在高并发下性能一般。第二Dovecot SASL 认证。Dovecot 本身是收件服务器但它自带的 SASL 实现可以作为 Postfix 的认证后端。配置 Postfix 的 smtpd_sasl_type 为 dovecotPostfix 把认证请求通过 Unix socket 发给 DovecotDovecot 再去查 PAM、用户数据库或者 SQL。优点是灵活、性能好而且在只需要 IMAP 认证的叠加场景下天然兼容缺点是为实现认证得额外安装并维护一个 Dovecot 进程。第三LDAP 统一用户认证。如果你的公司已经有一套 OpenLDAP 或 AD 域控用户、密码、组织架构都在里面那把 Postfix 直接接入 LDAP 是最高效的做法。所有后续新增用户都走 LDAP不用在邮件服务器上单独维护账号。缺点是前期需要 LDAP 基础设施配置链路较长如果 LDAP 挂掉邮件认证也会挂掉。我最终选的是 Dovecot SASL 方案原因后面会详细说但你可以先记住结论Dovecot SASL 是目前社区用得最多、资料最全、性能均衡的选择对于 99% 的监控发信场景都够用。如果你的团队已经有 LDAP 体系第三种的思路是等价的只是把认证源换成 LDAP 服务器Postfix 侧配置不变。2. 核心原理拆解Postfix 认证机制的两个关键概念2.1 SMTP 会话里认证发生在哪一步新手最容易迷糊的一个概念是SMTP 认证到底是怎么“插入”到发送流程里的。我们用一个标准的 SMTP 会话来说明。一个邮件客户端发送邮件时和服务器之间的对话大致是这样客户端: EHLO monitor-server 服务器: 250-mail.example.com 服务器: 250-AUTH LOGIN PLAIN 服务器: 250-AUTHLOGIN 服务器: 250-PIPELINING 服务器: 250 8BITMIME 客户端: AUTH LOGIN 服务器: 334 VXNlcm5hbWU6 客户端: dXNlcg 服务器: 334 UGFzc3dvcmQ6 客户端: cGFzc3dvcmQ 服务器: 235 2.7.0 Authentication successful 客户端: MAIL FROM:alertexample.com 服务器: 250 2.1.0 Ok 客户端: RCPT TO:opsexample.com 服务器: 250 2.1.5 Ok 客户端: DATA 服务器: 354 End data with CRLF.CRLF 客户端: From: alertexample.com 客户端: To: opsexample.com 客户端: Subject: test 客户端: 客户端: hello 客户端: . 服务器: 250 2.0.0 Ok: queued as 4E2A1F1A3仔细看这个过程客户端是在发送 MAIL FROM信封发件人之前先执行了 AUTH 命令。也就是说认证是发生在 SMTP 会话的中前段只有认证成功之后服务器才会接受你的“发件人声明”和“收件人声明”。如果没有认证直接发 MAIL FROM服务器会返回530 5.7.0 Authentication Required。Postfix 的配置里smtpd_recipient_restrictions或smtpd_relay_restrictions中会用到permit_sasl_authenticated这个规则它的意思就是如果客户端完成了 SASL 认证那就放行后续的 RCPT TO 指令。反过来说如果客户端没认证且来源 IP 不在mynetworks白名单里RCPT TO 直接拒绝。这是整个只发不收方案的“门禁”核心。2.2 Cyrus SASL 与 Dovecot SASL到底该信谁Postfix 主配置里有两个参数控制 SASL 的实现方式smtpd_sasl_type和smtpd_sasl_path。前者指定用哪种 SASL 实现cyrus 或 dovecot后者指定认证 socket 的路径。Cyrus SASL 是更“原教旨”的 SASL 实现它有一套自己的密码库sasldb、插件机制和认证协议。配置上通过smtpd_sasl_type cyrus然后由 saslauthd 或 sasldb 来完成具体验证。它的优势是对 SASL 协议族支持最全面包括 LOGIN、PLAIN、CRAM-MD5、DIGEST-MD5 等劣势也比较明显配置文件分散在/etc/sasl2/和/etc/default/saslauthd两处权限、参数、用户库三个地方都是坑稍有不慎就出现“认证失败但查不到日志”的诡异问题。Dovecot SASL 的优势在于Dovecot 本身把认证模块做得非常成熟和完善无论是 PAM 还是 SQL 还是 LDAP都有文档化的标准配置模板。Postfix 只需要通过 Unix socket 与 Dovecot 通信认证过程完全由 Dovecot 接管。另外Dovecot 的认证进程是事件驱动模型性能在低并发场景下和 Cyrus 几乎没差别但稳定性好了很多。基于这些原因我最终选了 Dovecot SASL。有一点必须提醒你不管选哪种 SASL 实现Postfix 的 chroot 机制会影响 socket 路径的解析。Debian 系默认 Postfix 是进 chroot 的所以smtpd_sasl_path private/auth实际对应的文件系统路径是/var/spool/postfix/private/auth。你手工ls /var/spool/postfix/private/auth如果能看到 socket 文件说明 Dovecot 已经正确创建了这个文件。很多人报“No such file or directory”就是用宿主机路径去猜了没想到 chroot 前缀。3. 实操一步步搭出只发不收、带认证的 Postfix3.1 环境准备和初始配置本次实操环境Ubuntu 22.04 LTSPostfix 3.6Dovecot 2.3.16。主域名用monitor.example.com发件地址统一用alertmonitor.example.com。你按自己的域名替换即可。先更新系统包并安装必要组件sudo apt update sudo apt install postfix dovecot-core dovecot-imapd mailutils -y安装过程中 Postfix 会弹出一个配置界面选择“Internet Site”然后在“System mail name”里填你的域名。别纠结之后还能改。装了mailutils是为了测试时能直接用sendmail或mail命令发信非常方便。检查 Postfix 是否已经运行sudo systemctl status postfix确认状态为 active 后我们先看几个默认配置项这些通常在/etc/postfix/main.cf中。现在的发行版安装后会自带注释完整的模板但我们要改掉其中一半以上所以不用保守大胆编辑。3.2 编辑 main.cf定义监听的网卡和协议开始改配置文件之前把最终要用的 main.cf 核心片段先贴出来。这样改的时候心里有数不会边看代码边迷茫。sudo vim /etc/postfix/main.cf我的整体配置如下为了省篇幅注释信息保留了关键行其余无关的行删掉即可。# 主机名最好是 FQDN且能解析到本机避免一些邮件服务器校验失败 myhostname monitor.example.com # 发件地址的域名后缀。只发不收不需要多个域名 mydomain monitor.example.com myorigin $mydomain # 只监听本机回环地址避免外部直接连上来发信 inet_interfaces loopback-only # 关键无需收信所以不监听 110/143 等端口的投递只做发送 mydestination $myhostname, localhost.$mydomain, localhost, $mydomain # 允许中继的来源本机 内网指定网段按需放开 mynetworks 127.0.0.0/8, ::1/128, 10.0.0.0/8 # 不做本地投递所有邮件都往外送 local_transport error:local delivery disabled保存后执行postfix check检查有没有语法错误。这个命令会把配置项的语法、引用关系过一遍有错误会直接报出来。注意inet_interfaces loopback-only这个非常关键它决定了 Postfix 只监听 127.0.0.1 这个地址外部网络连不进来。有个细节有人问“既然只监听回环那内网其他机器怎么连上来发信”答案是通过 SSH 隧道或者监控服务本身就部署在同一台服务器上。对于大部分监控场景Zabbix Server、Prometheus、脚本跑批和 Postfix 在同一台机器用回环就足够了。如果非要让内网其他服务器直连那就把inet_interfaces改成本机内网 IP同时确认防火墙只放行可信来源访问 25 端口。3.3 启用 SASL 并配置 Dovecot 认证文件改完 main.cf 后在文件末尾追加以下内容来启用 SASL 认证# 启用 SMTP 认证 smtpd_sasl_auth_enable yes smtpd_sasl_type dovecot smtpd_sasl_path private/auth smtpd_sasl_local_domain $myhostname broken_sasl_auth_clients yes # 中继限制认证用户 内网白名单才给投递 smtpd_relay_restrictions permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination解释一下几个容易懵的参数smtpd_sasl_local_domain这个参数是告诉 Postfix 把 AUTH 登录的用户名按什么域名做归一化。如果用户名是alert客户端用alert或alertmonitor.example.com登录最终都会被转成完整形式。建议设成$myhostname避免不同写法导致认证不一致。broken_sasl_auth_clients yes兼容某些老旧客户端实现 AUTH 时不按标准带LOGIN后缀的情况。开启后一般没副作用建议保留。smtpd_relay_restrictions这是新版 Postfix 专门负责“谁允许中继”的规则表。老版本其实用smtpd_recipient_restrictions也能实现但官方从 2.10 开始引入smtpd_relay_restrictions优先级更高且“中继”逻辑和“收件限制”逻辑分离更清晰也更安全。接着配置 Dovecot 侧的认证 socket。编辑/etc/dovecot/conf.d/10-master.conf确保service auth那个段落里开启 Unix socket 监听sudo vim /etc/dovecot/conf.d/10-master.conf找到service auth配置块默认内容可能类似service auth { # unix_listener auth-userdb { # mode 0600 # user postfix # } }我们要改成 Postfix 可访问的 socketservice auth { unix_listener /var/spool/postfix/private/auth { mode 0660 user postfix group postfix } }这里重点强调socket 必须落在 Postfix 的 chroot 目录下也就是/var/spool/postfix/private/。而且权限要对Postfix 进程要能读写这个 socket。mode 0660加上user postfix、group postfix是实际中最稳的组合。如果你发现启动后 Postfix 还是连不上八成就是权限不对改成0666能快速验证问题但生产环境不建议一直开 0666。然后编辑/etc/dovecot/conf.d/10-auth.conf启用明文认证并放开 PLAIN/LOGIN 机制sudo vim /etc/dovecot/conf.d/10-auth.conf找到disable_plaintext_auth这一行改成disable_plaintext_auth no再找到auth_mechanisms确认包含auth_mechanisms plain login为什么允许明文认证因为 Postfix 和 Dovecot 之间走的是 Unix socket不经过网络传输明文也无所谓。如果你要面对的是网络环境中的 SASL auth那另说正常用 SSL/TLS 包裹 SMTP 会话即可这里不展开。最后Dovecot 验证用户的方式默认走系统 PAM。也就是说只要你在服务器上创建了系统账号就可以用它登录 SMTP 发信。为了安全我单独建一个专用账号并把它锁在 shell 上算是给发信用户一个“最小权限”sudo useradd -r -s /usr/sbin/nologin alert sudo passwd alertpasswd 会让你输入两遍密码这个密码就是后面监控系统要用到的认证密码。3.4 重启服务与端口验证配置改完重启服务让配置生效sudo systemctl restart dovecot sudo systemctl restart postfix然后检查两个关键状态sudo systemctl status postfix --no-pager sudo systemctl status dovecot --no-pager再确认 Postfix 监听了 25 端口、Dovecot 没有对外监听端口因为它只给 Postfix 提供 socket 认证sudo ss -lntp | grep :25 sudo ls -l /var/spool/postfix/private/auth如果一切正常你会看到类似输出srw-rw-r-- 1 postfix postfix 0 Jan 20 11:22 /var/spool/postfix/private/auth这个 socket 文件就是 Postfix 和 Dovecot 之间的“电话线”。线接通了认证就通。3.5 用 swaks 做一轮完整测试安装一个 swaks 工具它是测 SMTP 的神器比 telnet 高效太多了sudo apt install swaks -y swaks --to opsexample.com --from alertmonitor.example.com \ --server 127.0.0.1 --auth LOGIN --auth-user alert --auth-password 你的密码 \ --header Subject: Postfix auth test --body Testing postfix with auth.其中opsexample.com换成任何真实可接收的邮箱比如个人 Gmail。如果配置没问题输出会看到- 235 2.7.0 Authentication successful - 250 2.0.0 Ok: queued as ...最后查一下收件人邮箱会收到这封测试邮件。这里的“成功”包含两层含义一是 Postfix 接收了这封信二是有外部 MTA 接受了这封信的投递。如果只看到第一层第二层失败的话要去查mail.log。我实际测试时曾经碰到 Gmail 拒信提示“Technical details of temporary failure: 4.7.1”之类的最后发现是 PTR 记录不匹配。也就是说发信服务器的 IP 反向解析域名和 HELO 主机名对不上。这个问题困了很多新手后面章节我会专门列出来讲。4. 上生产前必须想清楚的细节DNS、防火墙和发件人策略4.1 SPF、DKIM、PTR少一个都可能进垃圾箱很多自建邮件服务器明明发信、收信、认证全没问题但对方邮箱就是收不到或者进了垃圾箱。原因基本都在 DNS 配置上。这里讲三个必备点。SPFSender Policy Framework在 DNS 里添加一条 TXT 记录声明“哪些 IP 被允许以你的域发送邮件”。例如monitor.example.com. IN TXT vspf1 ip4:你的服务器公网IP ~all直白点说SPF 就是一个“发件人白名单”。没有 SPF接收方大概率对来自你域的信存疑。DKIMDomainKeys Identified Mail用来给发出的邮件做数字签名收件人通过 DNS 获取公钥验证签名。Postfix 可以通过OpenDKIM实现签名。配置不复杂但涉及生成密钥、DNS 记录和 main.cf 集成三个环节值得之后单独写一篇。如果只是给监控告警用可以先不配但进了垃圾箱别奇怪。如果要求高就按官方文档配置完整。PTRPointer Record这是由 IP 所属方通常是机房或云厂商配置的反向解析。服务器 IP 的反解结果要尽量和myhostname一致。例如你的服务器 IP 是 1.2.3.4myhostname 是monitor.example.com那 1.2.3.4 的 PTR 必须指向monitor.example.com。主机名与 IP 对应关系是 Gmail、Outlook 等大型邮箱系统直接检查的硬指标。4.2 mynetworks 白名单和密码认证的边界在 main.cf 里我设置了mynetworks 127.0.0.0/8, ::1/128, 10.0.0.0/8。这意味着内网 10.0.0.0/8 网段的机器可以不认证直接发信。这个设计是故意的——很多内网监控脚本没有“优雅地携带认证”的能力直接允许受信网段投递最方便。但要注意这台 Postfix 如果部署在云上公网 IP 很容易被扫描到。即使只用回环地址如果云安全组里不小心放行了 25 端口外部流量一样能进来。所以哪怕只监听loopback-only我也建议在云控制台的安全组里把入方向 25 端口彻底关掉双保险。我做安全测试的时候试过在安全组放行 25 端口的瞬间日志里就会涌现大量SASL authentication failed或connect from unknown记录。所以端口层面最好把所有外部到 25 的入站流量都毙掉只在服务器内部开放。4.3 单点登录和 LDAP 延伸认证源再向前一步标题的热词里有“LDAP统一用户认证和单点登录”结合我们的场景说几句。如果你所在团队已经有 OpenLDAP 或 AD 域控那完全可以跳过服务器上的系统用户认证让 Dovecot 直接对接 LDAP。Dovecot 有专门的 LDAP 认证支持在/etc/dovecot/dovecot-ldap.conf.ext里配置服务器地址、base DN 和绑定 DN然后在10-auth.conf里启用ldap的 passdb 和 userdb 即可。这样做的收益是显而易见的新同事入职管理员只需要在 LDAP 里加一条账号记录邮件发信权限自动拥有离职时只需禁用 LDAP 账号认证立刻失效不用跑到每台服务器上删系统用户。对于成规模的运维团队这减少了巨大的账号维护成本也避免出现“人走了密码还留在邮箱配置里”的安全隐患。LDAP 配置里必须特别注意超时设置。我当时调了一段时间最后把dovecot-ldap.conf.ext里connect_timeout设为 5 秒request_timeout也设为 5 秒。这样 LDAP 一旦出现故障认证请求会在 5 秒内失败返回而不是卡住整个 SMTP 会话。否则监控系统发信超时告警反而变成另外一种故障。5. 常见问题与排查技巧实录5.1 认证失败反复出现日志到底看哪里Postfix 和 Dovecot 的日志分散在两个地方/var/log/mail.log或/var/log/maillog和 Dovecot 自己的日志。Debian/Ubuntu 上默认通过 rsyslog 统一收口用 journalctl 也能看sudo journalctl -u postfix -u dovecot --no-pager -n 100认证失败的经典报错长这样postfix/smtpd[1234]: warning: unknown[1.2.3.4]: SASL LOGIN authentication failed: authentication failure看到这句话说明 Postfix 本身收到了认证请求但下游验证没过。这时候要去 Dovecot 的日志里找更底层的原因sudo journalctl -u dovecot --no-pager -n 100常见原因有三个密码错误。这最好排查重新passwd一次即可。Dovecot 和 Postfix 之间的 socket 权限不通。检查/var/spool/postfix/private/auth的属主和权限确认 Postfix 用户有读写权限。PAM 配置异常。检查/etc/pam.d/dovecot是否存在且内容正确有时系统升级会覆盖掉这个文件。5.2 邮件已排队但对方就收不到Postfix 显示queued as但收件箱迟迟没到货分两种情况。第一种查看 mail.log 看到类似host gmail-smtp-in.l.google.com[142.250.x.x] said: 421 4.7.0的字样。这属于被对方临时拒绝通常和 IP 信誉有关。如果是新 IP、机房 IP、动态 IPGmail 基本都有临时限制。除了确认 PTR 和 SPF 之外也可以尝试从收件人到发件人一封一封“暖机”发送头部邮件内容越接近真实业务越好。第二种对方直接 550 拒绝。常见原因是 SPF 没配或者配错、发件域名和 myorigin 不一致、收件方有铁了心的反垃圾策略。处理办法是右键查看原始邮件里面会有Authentication-Results头能清楚看到 SPF、DKIM 是被 pass 还是 fail。5.3 发送频率过高触发热门邮箱限流监控告警有个特点不分白天黑夜系统抽风时可能就是每分钟一封。对于个人邮箱来说五分钟内在同一主题发送 50 封以上很容易触发限流。建议在 Postfix 层面直接做发送限速通过anvil模块控制每个客户端的连接频率和每次会话的邮件数smtpd_client_connection_rate_limit 10 smtpd_client_message_rate_limit 30这两行参数放 main.cf 里能有效防止某个告警循环把整个发信通道打挂。我见过真实案例监控系统的一个死循环脚本半天把邮件队列塞爆导致积压了几万封把磁盘直接撑满。有了限速之后就再没出过这种事故。5.4 忘记密码或需要轮换密码后的处理监控脚本里永远有一个最大的安全黑洞明文密码。不管是 Zabbix 的告警媒介脚本还是 Alertmanager 的 email_config密码都以可读形式躺在配置里。需要定期轮换时直接执行sudo passwd alert改完之后重启 Postfix 和 Dovecot 不是必需的但如果你发现某些客户端还在用旧密码连接且认证失败建议还是重启一下两个服务确保连接池里的旧认证状态被清干净。6. 从零到可用的完整清单最后把配置思路整理成一张速查表方便你部署时逐项对照项目配置动作验证命令关闭收信inet_interfaces loopback-onlyss -lntp | grep :25 无本地投递local_transport error:local delivery disabled内网发信测试启用认证smtpd_sasl_auth_enable yestelnet 127.0.0.1 25Dovecot socket/var/spool/postfix/private/authls -l /var/spool/postfix/private/auth中继限制permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination未认证发信测试创建用户useradd alertpasswd alertswaks --auth LOGINDNS 记录SPF 必须PTR/DKIM 按需dig TXT monitor.example.com限速smtpd_client_message_rate_limit观察 mail.log这套配置跑下来我最大的体会是自建发信服务器的难点不是“让它跑起来”而是“让它发出的信被真正信任”。认证只是门禁真正决定邮件会不会到达收件箱的是 SPF、DKIM、PTR 这些落在邮件系统之外的功夫。如果你只是给监控告警用直接按上面的步骤操作半小时内就能收到第一封由自己服务器发出来的邮件。等把这个通道跑顺了再回头看你会发现这套“只发不收”的 Postfix其实是你所有监控体系里最稳的那根绳子——它平时不出声但每次系统抽风都是它在第一时间叫醒你。