Postfix 配置通过远程 SMTP 服务器发送邮件

Anson 教程 96 次浏览 评论已关闭

平时运行 Shell 脚本或其它后台服务需要发送通知邮件,这类发送量不大的邮件可以使用现成服务,例如 Gmail/Outlook 这类。通过在 SMTP 客户端配置到远程 SMTP 服务器发信即可。

CentOS 7 默认安装了 Postfix 软件,它自带 STMP 客户端功能,可以直接用这个配置。如果想用更简单的,还有 msmtpssmtp 可以选择。

下面示例通过 Gmail SMTP 服务器发送邮件(提示:先到 Gmail 账户安全设置里开启“允许安全性较低的应用”,不然连接 SMTP 服务器可能不能验证。或者启用两步验证生成使用应用密码,这样可以避免使用 Gmail 账号主密码,安全性更好)。

停用其它 MTA 软件

如果之前安装了其它邮件传输代理软件,如 Sendmail,为避免冲突需先停用或卸载。

# 查询是否安装 Sendmail
rpm -q sendmail

# 停用 Sendmail
systemctl stop sendmail
systemctl disable sendmail

# 卸载 Sendmail
yum -y remove sendmail

Postfix 及相关软件安装

安装 Postfix

通常随系统安装。如果没有,从默认软件源安装即可。

# 查询是否安装 Postfix
rpm -q postfix

# 安装 Postfix
yum -y install postfix

安装 Cyrus SASL

这是 Postfix SMTP 客户端设置 SASL 身份验证所需要的(Gmail 这类邮件服务的 SMTP 服务器主要使用明文密码认证方式,故这里就不安装其它 Cyrus SASL 认证方式插件了)。

yum -y install cyrus-sasl-lib cyrus-sasl cyrus-sasl-plain

安装 Mailx

方便后面用 mailx 命令测试邮件发送。

yum -y install mailx

设置默认 MTA 软件

如果系统上安装了多个邮件传输代理软件,尽管前面禁用了,可能系统还在默认使用,需要检查 Postfix 是否是当前默认 MTA 软件。

# 设置默认 MTA(如果列表里只有 Postfix,直接回车设置)
alternatives --config mta

# 查询当前 MTA
alternatives --display mta

Postfix SMTP 客户端配置

通过远程 SMTP 服务器发送邮件需要做以下配置(这里使用 postconf 命令添加配置,也可以直接编辑 /etc/postfix/main.cf 文件添加配置)。

在下面配置里,我们没有设置默认 SMTP 服务器为所有 SMTP 会话启用 TLS 加密,而是将这些设置应用到所添加的邮件账户里(好处是可以避免使用全局设置可能带来潜在使用问题,但也有个不便,即后续发送邮件需要指定发件人地址,不然 Postfix 找不到要投递的 SMTP 服务器)。

关于 Postfix 如何关联发件人和其 SMTP 服务器的:如果设置了默认 SMTP 服务器,它会根据 SMTP 服务器地址查找已配置的对应发件人信息。如果没有设置默认 SMTP 服务器,而是采用下面配置方法,则会根据发件人地址查找已配置的对应 SMTP 服务器及发件人信息。

# 启用 SMTP 客户端 SASL 身份验证
postconf -e "smtp_sasl_auth_enable = yes"

# 过滤 PLAIN 和 LOGIN 以外的 SASL 认证方式
postconf -e "smtp_sasl_mechanism_filter = plain, login"

# 设置 SMTP TLS 加密会话 SASL 安全选项(较默认设置,这里删除了禁止明文密码认证方式)
postconf -e "smtp_sasl_tls_security_options = noanonymous"

# 设置 SMTP TLS 客户端 CA 证书列表(这里指定系统默认 CA 证书)
postconf -e "smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt"

# 启用依赖于发件人的 SASL 身份验证
postconf -e "smtp_sender_dependent_authentication = yes"

# 设置记录发件人和其对应 SMTP 服务器的文件
postconf -e "sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relay"

# 设置记录发件人和其对应账号信息的文件
postconf -e "smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd"

# 设置 TLS 策略表(为指定 SMTP 服务器会话启用 TLS 加密)
postconf -e "smtp_tls_policy_maps = hash:/etc/postfix/tls_policy"

创建相关配置文件

使用下面命令创建之前在 Postfix 配置里引用的文件。

# 创建记录发件人和其账号信息的配置文件
# 支持添加多个邮箱账号,每行一个,格式为“发件人地址 + 空格 + 邮箱账号 + 冒号 + 邮箱密码”
cat > /etc/postfix/sasl_passwd << "EOF"
[email protected] [email protected]:password
EOF

# 创建记录发件人和其 SMTP 服务器的文件
# SMTP 服务器域名用 [] 括住表示关闭 MX 查找(如果开启 MX 查找,会将邮件发送到域名 MX 记录里的目标)
# 如果要使用 465 端口 SMTPS 协议,需要 Postfix 3.0 及以上版本支持,并添加 smtp_tls_wrappermode = yes 参数
# 如果之前添加了多个邮箱账号,这里也要相应添加记录
cat > /etc/postfix/sender_relay << "EOF"
[email protected] [smtp.gmail.com]:587
EOF

# 创建 TLS 策略表配置文件
# 这里为指定 SMTP 服务器连接启用 TLS 强制加密(对于使用明文密码认证来说,配合 TLS 加密是必要的安全做法)
# 启用 TLS 加密后,即使 SMTP 服务器证书不受信任或名称错误,邮件也会继续传递,但如果不满足默认 SSL 协议版本最小密码强度配置,则会终止邮件传递
# 如果不确定远程 SMTP 服务器是否支持 TLS,可以将值设为更温和的 may 模式(这样当 TLS 握手失败时会自动禁用 TLS 重新连接)
cat > /etc/postfix/tls_policy << "EOF"
[smtp.gmail.com]:587 encrypt
EOF

为防范其他用户或服务读取文件,建议将相关文件所有者设为 root,只有 root 有读写权限。

chown root:root /etc/postfix/sasl_passwd
chmod 600 /etc/postfix/sasl_passwd
chown root:root /etc/postfix/sender_relay
chmod 600 /etc/postfix/sender_relay
chown root:root /etc/postfix/tls_policy
chmod 600 /etc/postfix/tls_policy

然后使用 postmap 工具生成经 Hash 处理的数据库文件,以供 Postfix 使用(生成文件也将具有相同的文件权限。后续如果修改了文件,需要重新运行 postmap 命令更新数据库文件)。

postmap /etc/postfix/sasl_passwd
postmap /etc/postfix/sender_relay
postmap /etc/postfix/tls_policy

最后运行 postfix check 检查 Postfix 配置是否有误,没问题后 postfix reload 刷新服务生效。

测试邮件发送

经上面配置完成后,使用下面命令测试邮件是否发送正常(红色部分设置发件人地址,蓝色部分设置收件人地址。收件人地址可以用这个邮件检测服务提供的,方便查看)。

# 从管道读取邮件正文
echo "测试邮件正文" | mailx -r "[email protected]" -s "测试邮件标题" reci[email protected]

# 从指定文件读取正文
mailx -r "[email protected]" -s "测试邮件标题" [email protected] < textfile

# 使用 -a 参数发送带附件邮件
echo "测试邮件正文" | mailx -r "[email protected]" -s "测试邮件标题" -a /path/to/file [email protected]

如果邮件发送后没有收到,请排查 Postfix 日志分析问题原因。

# 查看最近 50 条日志记录
tail -50 /var/log/maillog

# 如果日志里找不到错误记录,可能需要调高日志记录级别(测试后再改回去)
# 例如将日志记录级别调高至 10(默认为 2),刷新服务后生效
postconf -e "debug_peer_level = 10"
postfix reload