在 Linux 命令行中发送邮件 —— 各种介绍
好长时间都没有真正搞明白 Linux 中是怎么发送邮件的,决定稍微研究一下。
邮件发送简化流程
发送邮件的简化流程是这样的:
发送者的邮件客户端--> 发送者的邮件传送代理 --> 接收者的邮件传送代理 --> 接收者的邮件客户端
概念解释
- 邮件客户端/邮件用户代理(MUA,Mail User Agent)如:Mail、Mailx、Mutt、Mpack、Sendmail、sSMTP
MUA 就是用户使用的客户端,负责编写、查看邮件 - 邮件服务器/邮件传送代理(MTA,Mail Transport Agent)MTA 如:Sendmail、Postfix、sSMTP
接受由 MUA 编写的邮件并发送到对方的 MTA,或者从对方的 MTA 接受邮件并交给 MUA。
MTA 也会检查是本域名还是其他域名的邮件,发往其他域名的邮件称为转寄(relay)。
收到的邮件最后会留在 MTA 中。 - 邮件分发代理(MDA,Mail Deliver Agent)
其实是 MTA 的一部分,分析 MTA 收到的信件数据,来决定这份邮件的取向、如:过滤垃圾邮件、自动回复等。
那要是我的 MUA 和 MTA 不在一起呢?
- 邮件检索代理(MRA,Mail Retrieval Agent)。
MRA 可以通过 POP3、IMAP 协议来远程从 MTA 获取邮件
当然,一个软件可以充当多个角色,比如 Mailx 也可以直接通过 SMTP 协议发送邮件,Sendmail 又能当客户端又能发送邮件。
小知识
SMTP 与 IMAP 和 POP3
- SMTP(Simple Mail Transfer Protocol):用于 MUA 向 MTA 发送邮件,或是 MTA 向 MTA 发送邮件。
是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器。 - POP3(Post Office Protocol 3):用于 MUA 向 MTA 接收邮件。
允许电子邮件客户端下载服务器上的邮件,但是在客户端的操作(如移动邮件、标记已读等),不会反馈到服务器上,比如通过客户端收取了邮箱中的3封邮件并移动到其他文件夹,邮箱服务器上的这些邮件是没有同时被移动的 。POP3 还有一些其他问题,不推荐使用。 - IMAP(Internet Mail Access Protocol):用于 MUA 向 MTA 接收邮件。
而IMAP提供webmail 与电子邮件客户端之间的双向通信,客户端的操作都会反馈到服务器上,对邮件进行的操作,服务器上的邮件也会做相应的动作。
SSL 与 TLS 与 STARTTLS —— 传输过程中的邮件加密
在IMAP、POP、SMTP 等电子邮件技术开始使用时,SSL/TLS 加密技术还没大规模使用。那时,它们使用 IMAP 143、POP3 110、SMTP 25 端口进行明文传输。
为了安全性,出现了 SMTPS (SMTP-over-SSL), 最初使用的加密协议是 STARTTLS(显式 SSL/TLS),它首先在默认明文端口发送 STARTLS 命令,如果双方支持加密那么就移动到 587 端口进行 SSL/TLS 加密连接,如果不支持则进行明文连接,这带来了许多兼容性和安全问题。
为了进一步提高安全性,出现了强制 SSL/TLS(隐式 SSL/TLS),使用三个新端口(IMAP 993、POP3 995、SMTP 465),这些端口从一开始就要求 SSL/TLS 连接。意味着双方一开始就应该使用 SSL/TLS 进行连接,而不需要事先声明。
如今 STARTTLS 已经淘汰,大多数 SMTP 服务器都使用 465 或 587 端口进行隐式 SSL/TLS 连接。
那么 587 端口又是什么?
最初 IANA 为 SMTPS 分配了配了 SMTP 端口 465,然而 IANA 没有进行征求意见,因此 IETF 从未签署此方法或正式认可此端口。
然后,发送加密邮件的其他方法(例如 STARTTLS)变得流行,因此 IETF 最终将端口 587 定为 SMTPS 标准端口,同时支持 STARTTLS 和隐式 SSL/TLS,IANA 也同意了这一更改。
如今大部分服务商仍然支持 465 端口,虽然已经不推荐使用,但使用 465 端口可以避免一些兼容性问题。
SMTP 端口
端口 | 支持情况 |
25 | 不支持加密,支持 STARTTLS |
465 | 非标准端口,支持隐式 SSL/TLS |
587 | 支持隐式 SSL/TLS 和 STARTTLS |
2525 | 备用端口,可能支持隐式 SSL/TLS 和 STARTTLS |
POP3 端口
端口 | 支持情况 |
101 | 不支持加密,支持 STARTTLS,IMAP over STARTTLS |
995 | 支持隐式 SSL/TLS,POP3S (POP3 over SSL/TLS) |
IMAP 端口
端口 | 支持情况 |
143 | 不支持加密,支持 STARTTLS,IMAP over STARTTLS |
993 | 支持隐式 SSL/TLS,IMAPS(IMAP over SSL/TLS) |
警告:尽管 SMTP、POP、SMTP 这些传输协议是支持 SSL/TLS 加密的,但邮件本身是不加密的,这意味着双方的 MTA 将能完整的看到你的邮件内容(如 Gmail、QQ 邮箱、163 邮箱、Outlook 等)。
若要加密邮件本身,请使用 S/MIME 或 E2EE 协议。
实际操作
介绍完了概念,我们来讲讲怎么在 Linux 命令行里面发送邮件,比如 cron 失败提醒、脚本失败提醒……
MUA
首选 mailx,各大发行版应该都有。
替代了老旧的 mail,默认情况下 mailx 会调用 sendmail(不一定真的是 Sendmail 这个软件) 发送邮件,但也可以在配置文件中使其直接使用外部 SMTP 服务器发送邮件。
配置文件位于 /etc/mail.rc
发送邮件
mail -s "邮件主题" root@localhost
这种方法没有办法直接填写邮件正文,但你可以使用重定向符,或者管道来从某个文件输入邮件正文。
也可以用 , 分割多个收件人。或是使用 -a 带上附件。
cat 正文.txt | mail -s "邮件主题" root@localhost, admin@localhost
如果你不想在文件中写入正文,也可以这样:
echo "邮件正文" | mail -s "邮件主题" root@localhost
阅读邮件
直接输入 mail
或 mailx
即可。
使用外部 SMTP 服务器
注意:在系统中有 MTA 时 mailx 会忽略设置的 SMTP 服务器。
在配置文件 /etc/mail.rc
中写入
set from=
set smtp=mail.example.com:465
set smtp-auth-user=
set smtp-auth-password=
set smtp-auth=login
smtp="mail.example.com:465"
指定 SMTP 服务器主机名或 IP 地址和端口号;smtp-auth=login
指定将发生什么类型的 SMTP 身份验证,一般都是 login;smtp-auth-user="user1@example.com"
指定将用于验证的用户名;smtp-auth-password="password"
指定密码。确保您使用的系统是安全的,因为提供了明文密码;
mailx 能自动识别加密方式,一般无需手动指定。
这些信息应该从你的邮件提供者处获取,例如 Gmail 帮助、Outlook 帮助、QQ 邮箱帮助。
如果不想全局指定,也可以在命令行中指定 SMTP 服务器:
mailx -v -s "邮件主题" -S smtp="mail.example.com:465" -S smtp-auth=login -S smtp-auth-user="user1@example.com" -S smtp-auth-password=
更多用法
mailx 的更多用法请参阅:
MTA
真假 MTA
真正的 MTA:Sendmail、Postfix 等
兼容 sendmail 的转发器:sSMTP、Msmtp、eSMTP 等
一般而言我们没必要真的建立一个 MTA,而是提供与 sendmail 兼容的命令来将邮件转发到外部 SMTP 服务器。
Sendmail 和 Postfix 都比较复杂、sSMTP 已经无人维护,目前比较推荐使用 Msmtp。
真假 Sendmail
由于 Sendmail 的历史,所以很多软件会把 MTA 直接叫做 sendmail 而不管实际上的 MTA 是哪一个,因为它们基本都兼容 sendmail 格式。ls -l /usr/sbin/sendmail
可以看到 /usr/sbin/sendmail -> /etc/alternatives/mta
安装 MTA 后再由 /etc/alternatives/mta
指向真正的软件。
虽然有的 MUA 比如 mailx 也能直接使用外部 SMTP 服务器发送邮件,但部分软件还是会直接调用 sendmail,所以设置 MTA 也是有必要的。
安装 Msmtp
我们这里安装 Msmtp,RHEL 系列系统可以在 epel 源中找到此包。
你可以为每个用户设置,或者为整个系统设置,我们这里为整个系统设置。
创建文件 /etc/msmtprc
并写入:
#为以下所有帐户设置默认值
defaults
auth on
tls on
#为 TLS 设置可信 CA 列表。默认是使用系统设置,但是你可以选择你自己的文件。
#tls_trust_file /etc/ssl/certs/ca-bundle.crt
logfile ~/.msmtp.log
#账户1
account account1
tls_starttls off
host smtp.example.com
port 465
from username@example.com
user username
password plain-text-password
#账户2,不需要多个账户就删掉
account account2
tls_starttls off
host smtp.example.com
port 465
from username@example.com
user username
password plain-text-password
#设置默认账户,放在最后
account default : account1
tls_starttls
是否使用 STARTTLS 方式进行加密通讯。host
SMTP 服务器主机名或 IP 地址;port
SMTP 服务器端口号,SSL/TLS 加密一般为 465;from
发件人地址;user
SMTP 服务器用户名;password
SMTP 服务器密码;
这些信息应该从你的邮件提供者处获取,例如 Gmail 帮助、Outlook 帮助、QQ 邮箱帮助。
当然除了明文写入密码,也有这么几种方式可以传入密码:
# 密码方法 1: 将密码加入系统的钥匙圈,让 msmtp 自动获取。使用 Gnome 的 libsecret 来设置钥匙圈密码。
# $ secret-tool store --label=msmtp \
# host smtp.freemail.example \
# service smtp \
# user joe.smith
# 密码方法2:将密码存储在一个加密文件中,并告诉msmtp使用哪个命令来解密。这通常与 GnuPG 一起使用,如本例中。通常 gpg-agent 会询问一次解密密码。
# passwordeval gpg2 --no-tty -q -d ~/.msmtp-password.gpg
# 密码方法 3:将密码直接存储在这个文件中。通常情况下,将密码存储在明文文件中并不是一个好主意。如果你还是这样做了,至少要确保这个文件只能由你自己读取。
# password secret123
#密码方法4:将密码存储在~/.netrc。这种方法可能不再适用了。
#密码方法5:不指定密码。然后Msmtp会提示你输入密码。这意味着当 msmtp 运行时,你需要能够在终端输入。
更改默认 MTA
如果你的系统中有多个 MTA,或是 MTA 没有正确指向 Msmtp,使用此命令可以让你设置默认 MTA:alternatives --config mta
发送邮件
也可以用 Msmtp 发送邮件:
echo "邮件正文" | msmtp user@example.com
除了正文还会发送一些诊断信息,不太推荐使用此方式。
更多用法
更多用法请参阅:
在 Crontab 中使用
Crontab 会默认调用 MTA 将所有输出都发送到 root 邮箱,root 邮箱可以在 /etc/aliases
定义。
但 Crontab 不尊重 Msmtp 中的 SMTP 发送者设置,所以你需要在 cron 文件头部添加:
MAILFROM=
MAILTO=
默认情况下 cron 会发送所有输出,你可以将标准输出重定向到 > /dev/null
以此来仅接受标准错误输出邮件。
* * * * * root bash /opt/shell/error.sh > /dev/null
其他
- 还有域什么的没写……
- 不知道是怎么成功发出去的(图中主机名已被我修改为 Hostname,非实际主机名)
- 更为详细的流程以及搭建过程可以参考鸟哥的文章,但请注意这已经是 10 多年前的文章了:
https://linux.vbird.org/linux_server/centos6/0380mail.php
主要参考
- https://linux.vbird.org/linux_server/centos6/0380mail.php
- https://askubuntu.com/questions/536766/how-to-make-crontab-email-me-with-output
- https://sylvaindurand.org/send-emails-with-msmtp/
- https://www.rennetti.com/cheatsheet/235/using-msmtp-on-linux-centos
- https://www.poftut.com/linux-mail-mailx-commands-tutorial-examples-send-email-command-line/
- https://mailtrap.io/blog/starttls-ssl-tls/
No Comments