需要自己掌控邮件收发——比如给内部系统发告警、给注册用户发通知——可以用 Postfix 做发送(MTA),Dovecot 做接收(IMAP/POP3),两者配合就是一套够用的自建邮件服务。本文主环境为 Rocky Linux 9,从安装、双配置检查到本机投递闭环全部在容器里实测通过:postfix check 无输出、25/143 正常监听、测试邮件在 maillog 里留下 status=sent (delivered to maildir)。

跨服务器的收发依赖 MX 记录和 25 端口连通性,这部分容器验证不了,文末标注了验证边界;老读者关心的 CentOS 7 差异集中在「历史版本差异」一节。

前置条件

  • Rocky Linux 9(或同系 RHEL 9 发行版),root 权限;
  • 一个可用的域名(本文以 example.com 为例),能把 A/MX 记录指到这台机器;
  • 25/110/143 等端口未被云厂商封禁(多数云默认封 25,发信需申请解封)。

一、安装必要的软件

安装 Postfix、Dovecot,以及用于安全通信的 cyrus-sasl-plain:

1
dnf install postfix dovecot cyrus-sasl-plain

装完先补一条容易漏的:执行 newaliases 生成 /etc/aliases.db。不生成它,本地投递会一直卡在 deferred,maillog 报 alias database unavailable(实测踩到,详见常见报错)。

1
newaliases

再确认版本,写进你的部署记录里。实测输出(Rocky Linux 9 容器):

1
postconf mail_version && dovecot --version

配图1

二、配置 Postfix

编辑主配置文件:

1
vi /etc/postfix/main.cf

添加或修改以下行,搭起基本的邮件服务:

1
2
3
4
5
6
7
8
9
10
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
home_mailbox = Maildir/
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

注:原文这份清单里还有一行 mta_sts_policy = enforce。实测 Postfix 3.5.25 对它只报 unused parameter 警告、不阻断 check,但它不是有效配置;稳妥做法是从 main.cf 删掉,MTA-STS 如需落实走官方文档的独立方案。

几个关键项:

  • myhostname:邮件服务器的主机名。
  • mydestination:设置邮件可以送达的域名。
  • home_mailbox:用户的邮箱目录,Maildir/ 格式即每封邮件一个文件。
  • smtpd_sasl_auth_enable:启用 SASL 认证,认证工作交给 Dovecot 完成。
  • smtpd_recipient_restrictions:只允许本机网络和通过 SASL 认证的用户发信,其余未知目的地一律拒绝,避免被当成开放中继滥用。

改完先做语法检查,无输出即为合法(实测通过,退出码 0):

1
postfix check

再重启并设置开机自启:

1
2
systemctl restart postfix
systemctl enable postfix

验证服务状态:systemctl status postfix 应看到 active (running)。容器环境没有 systemd,实测用 postfix start 直接拉起,效果等价。

三、配置 Dovecot

Dovecot 负责邮件的接收(IMAP/POP3),同时给 Postfix 提供 SASL 认证服务。编辑主配置文件:

1
vi /etc/dovecot/dovecot.conf

确保有以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
disable_plaintext_auth = no
mail_privileged_group = mail
mail_location = maildir:~/Maildir
userdb {
driver = passwd
}
passdb {
args = %s
driver = pam
}
service auth {
unix_listener /var/spool/postfix/private/auth {
group = postfix
mode = 0660
user = postfix
}
}

mail_location 与 Postfix 的 home_mailbox = Maildir/ 指向同一套邮箱;service auth 里的 unix_listener 就是 Postfix 配置里 smtpd_sasl_path = private/auth 对应的那个套接字,两边靠它接通认证。

保存后用 doveconf -n 校验——它会打印 Dovecot 实际生效的非默认配置,报错说明语法有问题。实测打印出 disable_plaintext_auth = no、mail_location = maildir:~/Maildir 等行即为生效。

启动 Dovecot:

1
2
systemctl restart dovecot
systemctl enable dovecot

容器实测时两个服务都能脱离 systemd 直接拉起(postfix start 和 dovecot 命令),ss -ltn 确认 25 与 143 都在监听。有一个容器特有的坑:conf.d/10-ssl.conf 默认的 ssl_cert 指向自签证书 /etc/pki/dovecot/certs/dovecot.pem,最小容器里没有这个文件,dovecot 直接起不来——补一张自签证书(或临时 ssl = no)即可,生产环境必须换成真证书。

四、测试邮件功能

本机投递链路可以完整闭环,实测如下。先建一个本地收件用户,再发一封测试邮件:

1
2
useradd mailtest
echo "hello from rocky9 container body" | mail -s "v4-test-subject" mailtest

发出后 tail /var/log/maillog,看到 status=sent 才算成功;实测最后一行是 status=sent (delivered to maildir),同时 /home/mailtest/Maildir/new/ 出现新邮件文件,cat 可见主题与正文,与发送内容逐字一致:

配图2

接收侧登录邮件客户端,或用 mutt 直接在命令行里查看:

1
mutt

注:容器内实测覆盖到本机投递闭环为止;跨服务器的收发依赖 MX 记录与 25 端口连通性,需在真实环境验证。来源:本机投递为实跑输出,外网收发为 Postfix/Dovecot 官方文档标准做法。

历史版本差异(CentOS 7)

  • 版本:CentOS 7 上是 postfix 2.10.1、dovecot 2.2.36;包名相同、配置语法一致,把 dnf 换回 yum 即可。本文的全部配置项在两代上都有效。
  • 系统源:CentOS 7 已于 2024-06-30 停止维护,mirrorlist 已下线,需切到 vault 归档(见常见报错),实测修复后安装正常。
  • 未知参数的容忍度:Rocky 9 的 Postfix 3.5.x 对不认识的参数只给警告;2.10.1 的行为未实测,保守起见 mta_sts_policy 这行在两代上都不要保留。

装坏了怎么办

配置改坏导致服务起不来时,先 postfix check / doveconf -n 定位语法错误;想整体回退,dnf remove postfix dovecot 后重装,再按本文重新配置即可——两套软件的配置都集中在 /etc/postfix/ 和 /etc/dovecot/,备份这两个目录就能在任何时候恢复现场。

常见报错

  • 本地投递一直 deferred,maillog 报 alias database unavailable:/etc/aliases.db 没生成。实测里邮件卡在队列(status=deferred (alias database unavailable)),执行 newaliases 后队列立刻消化成 status=sent。
  • 容器里 maillog 是空的:容器默认没有 syslog 守护进程。Postfix 3.4+ 可在 main.cf 加 maillog_file = /var/log/maillog 直写日志(实测有效),或者跑一个 syslog 服务。
  • 容器里 dovecot 起不来,报 ssl_cert 打不开:conf.d/10-ssl.conf 默认引用自签证书,最小容器没有;生成自签证书或临时 ssl = no,生产必须配真证书。
  • Cannot find a valid baseurl for repo: base/7:CentOS 7 EOL 后 mirrorlist 已下线。把 /etc/yum.repos.d/*.repo 里的 mirror.centos.org 替换为 vault.centos.org、注释掉 mirrorlist 行并启用 baseurl(实测修复后安装正常)。
  • 能发不能收:依次查 mydestination 是否包含收件域名、MX 记录是否指到本机、防火墙是否放行 25 端口。

注意事项

  • 用 firewalld 或 iptables 做访问控制,邮件服务器暴露在公网上,访问策略要收紧。
  • 生产环境应配置 SSL/TLS 加密,保护邮件数据在传输中的安全。
  • disable_plaintext_auth = no 允许明文认证,只在测试环境临时用,正式上线务必配合 TLS 并改回 yes。
  • smtpd_recipient_restrictions 三条规则缺一不可,少了 reject_unauth_destination,服务器就可能被外部当跳板群发垃圾邮件。

自建邮件服务的完整价值要靠”能发、能收、不被当中继”三条一起兑现:按本文装好、postfix check 与 doveconf -n 双双通过、本机投递实测 status=sent,再在真实环境把收发两条链路各测一封,这套服务才算真正接住了开头的需求。

本文由作者 2020-2024 年间的 CSDN 博客文章重构而来,原发布于 CSDN。