在 Linux 上使用 Exim4 发送邮件

2023-05-12 • 更新于 2024-02-17

带有 GUI 的 Linux 可以直接使用集成的邮件客户端,比如 Thunderbird。但在服务器上,发送邮件需要一些配置,踩一些坑。

邮件系统由三个部分组成:

  • Mail User Agent (MUA),发送和接收邮件。
  • Mail Transfer Agent (MTA),在计算机之间传输邮件。
  • Mail Delivery Agent (MDA),将收到的邮件投递到用户收件箱。

MUA 我使用的是 GNU Mailutils,MTA/MDA 使用的是 Exim4。

下面以网易 163 邮箱为例, 说明怎么在 Debian 11 上配置 Exim4。

脑瘫的网易把我服务器 IP 屏蔽了,发邮件就报 553 错误:

1rbFr0-005yuc-14 <= fuck.netease@163.com U=root P=local S=459
1rbFr0-005yuc-14 H=smtp163.mail.ntes53.netease.com [103.129.252.45] TLS error on connection (recv): The TLS connection was non-properly terminated.
1rbFr0-005yuc-14 ** ?@hotmail.com R=smarthost T=remote_smtp_smarthost H=smtp163.mail.ntes53.netease.com [103.129.252.45] X=TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256 CV=yes DN="C=CN,ST=zhejiang,L=hangzhou,O=NetEase (Hangzhou) Network Co.\, Ltd,CN=*.163.com": SMTP error from remote mail server after pipelined MAIL FROM:<fuck.netease@163.com>: 553 authentication is required,163 zwqz-smtp-mta-g5-0,_____wD3_4Uba9BlKz4cCQ--.10347S2 1708157724
1rbFr3-005yug-0L <= <> R=1rbFr0-005yuc-14 U=Debian-exim P=local S=2232
1rbFr0-005yuc-14 Completed
1rbFr3-005yug-0L H=smtp163.mail.ntes53.netease.com [103.129.252.45] TLS error on connection (recv): The TLS connection was non-properly terminated.
1rbFr3-005yug-0L ** fuck.netease@163.com R=smarthost T=remote_smtp_smarthost H=smtp163.mail.ntes53.netease.com [103.129.252.45] X=TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256 CV=yes DN="C=CN,ST=zhejiang,L=hangzhou,O=NetEase (Hangzhou) Network Co.\, Ltd,CN=*.163.com": SMTP error from remote mail server after pipelined MAIL FROM:<>: 553 NULL sender is not allowed,163 zwqz-smtp-mta-g5-3,_____wD3_7kda9Bly_Y5Aw--.8516S2 1708157726
1rbFr3-005yug-0L Frozen (delivery error message)

换 QQ 邮箱了,但是教程对网易也适用,前提是你的 IP 没被屏蔽。

先安装:

# apt install exim4 mailutils

SMTP 端口号

25

25 端口最初作为明文传输的 SMTP 端口,现在经常被 ISP 和云服务器提供商屏蔽,说是为了防止垃圾邮件。颇有点掩耳盗铃的意思。

使用 telnet 检测端口是否可用:

$ telnet smtp.163.com 25

个人测试发现,家用电信宽带、Vultr 可用,AWS 不可用。

465

465 是非标准的 SMTPS 端口,SMTPS 实际上就是 SMTP + TLS,类似 HTTPS 和 HTTP 的关系。虽然不是标准端口,但有很多邮件提供商提供支持。

587

587 是现在比较通用的标准端口,一般支持 STARTTLS 加密通信。

QQ 邮箱

从上面我们可以知道,SMTP 端口为 25,TLS 版本为 465,STARTTLS 版本为 587。

后两者支持加密通信,不过只要支持 STARTTLS,25 端口也可以加密通信。

QQ 邮箱符合标准,即 465 支持 SMTPS,587 支持 STARTTLS。

网易邮箱

网易比较坑爹,它确实支持 25、465、587 三个端口,但只有 25 支持 STARTTLS,后两者都是 SMTPS,而它显然没有在官网进行相关说明。

我们可以在 https://esmtp.email/tools/tls/ 检测加密支持情况。

配置 Exim4

# dpkg-reconfigure exim4-config

这会打开一个 TUI 配置向导。

选用 mail sent by smarthost 方案,System mail name 使用 localhost,IP 使用默认的环回地址,Other destinations for which mail is acceptedMachines to relay mail for 都留空。

IP address or host name of the outgoing smarthost 填入 smtp.qq.com::587,注意两个半角冒号,这里使用 STARTTLS,配置比 SMTPS 简单。

如果用网易 163,就填入 smtp.163.com::465,这里的 465 是网易支持的 SMTPS 端口,587 也可以,因为网易这逗比俩端口都是 SMTPS,效果完全一样。

其余选项按喜好配置即可。

需要注意的是,出于安全原因,root 用户不能接收邮件,因此最后一步设置 alias 时,通常设置为日常使用的用户,root 收到的邮件将投递到此用户收件箱内。

这些设置体现在 /etc/aliases 中。我们还可以设置当用户收到邮件时,将邮件投递到某个互联网邮箱,例如:

root: admin
admin: admin@example.com

运行 newaliases 使其生效。当系统收到邮件时(例如 Cron 定时任务),admin@example.com 就可以收到邮件提醒了。

然后在 /etc/exim4/passwd.client 中配置邮箱和密码:

# QQ
smtp.qq.com:username@qq.com:password
# 163
smtp.163.com:username@163.com:password

对于 QQ 和网易,这里的密码都要用授权码,登录 https://mail.qq.com https://mail.163.com 获取。

接着还要配置一下 /etc/email-addresses,这是本地用户发送邮件时的邮箱,与上面一致:

# QQ
root:username@qq.com
admin:username@qq.com

更新配置并重启服务:

# update-exim4.conf
# service exim4 restart

发个邮件试试:

$ echo "邮件内容" | mail -s "邮件标题" admin@example.com

日志位于 /var/log/exim4/mainlog

如果你是 STARTTLS,那应该已经发送成功了。但我的日志里有莫名其妙的报错:

1rbGz9-005zg6-1O H=smtp.qq.com [240e:ff:f100:1009::120] TLS error on connection (recv): Function was interrupted.

原因不明,但确实发送成功了。

SMTPS 还需要接下来的一些配置。

SMTPS 配置1

STARTTLS 请忽略此步骤。

创建 /etc/exim4/exim4.conf.localmacros

MAIN_TLS_ENABLE = 1
REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = *
TLS_ON_CONNECT_PORTS = 465
REQUIRE_PROTOCOL = smtps

注意端口 465 与上面一致。

编辑 /etc/exim4/exim4.conf.template,在 .ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS ... .endif 后(注意 .endif)添加:

.ifdef REQUIRE_PROTOCOL
    protocol = REQUIRE_PROTOCOL
.endif

.ifdef MAIN_TLS_ENABLE 后添加:

.ifdef TLS_ON_CONNECT_PORTS
    tls_on_connect_ports = TLS_ON_CONNECT_PORTS
.endif

更新配置并重启服务:

# update-exim4.conf
# service exim4 restart

运行 exim4 -qff 强制发送之前发送失败而暂存的邮件。

这下终于可以了。

Linux
知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

视频相关的命令和脚本

Homebrew 使用中的一些问题