msmtp
msmtp 是一个非常简单易用的 SMTP 客户端,具有相当完整的 sendmail 兼容性。
安装
安装 msmtp 包。此外,还需安装 msmtp-mta,它会创建一个指向 msmtp 的 sendmail 别名。
基本设置
自 msmtp 1.8.6 版本起,您可以将用户配置文件放在 ~/.msmtprc 或 $XDG_CONFIG_HOME/msmtp/config。以下是一个 msmtp 配置示例(该文件基于位于 /usr/share/doc/msmtp/msmtprc-user.example 的用户配置示例文件;系统配置文件应放在 /etc/msmtprc,其对应的示例文件位于 /usr/share/doc/msmtp/msmtprc-system.example)。
- 使用 OAuth,通过 #OAuth2 设置。
- 如果您使用双重身份验证:创建应用专用密码。
~/.msmtprc
# Set default values for all following accounts. defaults auth on tls on tls_trust_file /etc/ssl/certs/ca-certificates.crt logfile ~/.msmtp.log # Gmail account gmail host smtp.gmail.com port 465 tls_starttls off from username@gmail.com user username password plain-text-password # A freemail service account freemail host smtp.freemail.example from joe_smith@freemail.example ... # Accounts can inherit info from another account account postmasterfreemail : freemail from postmaster*@freemail.example # Set a default account account default: gmail
用户配置文件必须由其所有者显式可读/可写,否则 msmtp 将失败。
$ chmod 600 ~/.msmtprc
为避免将密码以明文形式保存在配置文件中,请使用 passwordeval 调用外部程序,或参阅下面的 #密码管理 部分。以下使用 Gnu PG 的示例常用于解密密码。
echo -e "password\n" | gpg --encrypt -o .msmtp-gmail.gpg # enter id (email...)
gpg --encrypt -o .msmtp-gmail.gpg -r <email> -。最后的连字符不是拼写错误,而是指示 gpg 使用 stdin。运行此代码片段后,输入您的密码,按 Enter,然后按 Ctrl-d,gpg 即可加密您的密码。~/.msmtprc
passwordeval "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.msmtp-gmail.gpg"
OAuth2 设置
当站点配置不支持基本用户名/密码身份验证或不希望使用时,可以使用 OAuth2 来安全地验证 msmtp。
oama
msmtp 本身缺乏续订或授权 OAuth2 凭据的能力。一个全面的解决方案是使用 oama 工具,它为 IMAP/SMTP 客户端提供续订能力和 OAuth2 凭据授权。
要使用 oama,请安装 oama-binAUR 并配置 msmtp 使用它。
# account at Google with oauth2 access account YOUR_EMAIL_NAME@gmail.com from YOUR_EMAIL_NAME@gmail.com user YOUR_EMAIL_NAME@gmail.com auth oauthbearer passwordeval oama access YOUR_EMAIL_NAME@gmail.com host smtp.gmail.com port 587 tls on tls_trust_file /etc/ssl/certs/ca-certificates.crt
访问令牌的续订在后台自动进行,对用户透明。
使用 mail 命令
要使用 mail 命令发送邮件,您必须安装 s-nail 包,它也提供了 mailx 命令。您还需要一个 sendmail 兼容的 MTA,可以通过安装 msmtp-mta(它将 sendmail 符号链接到 msmtp)或编辑 /etc/mail.rc 来设置 sendmail 路径来实现。
/etc/mail.rc
set mta=/usr/bin/msmtp
每个想要发送邮件的用户的主目录都需要有一个 .msmtprc 文件,或者可以使用系统范围的 /etc/msmtprc。
msmtp 也支持别名。将以下行添加到 msmtprc 的 defaults 部分或您的本地配置文件中。
/etc/msmtprc
aliases /etc/aliases
并在 /etc 中创建一个别名文件。
/etc/aliases
# Example aliases file
# Send root to Joe and Jane
root: joe_smith@example.com, jane_chang@example.com
# Send everything else to admin
default: admin@domain.example
测试功能
account 选项(--account=,-a)指定使用哪个账户作为发件人。
$ echo "hello there username." | msmtp -a default username@domain.com
或者,同时发送主题和正文。
$ printf "Subject: Test\n\nhello there username." | msmtp -a default username@domain.com
或者,将地址放在一个文件中。
To: username@domain.com From: username@gmail.com Subject: A test Hello there.
$ cat test.mail | msmtp -a default <username>@domain.com
--read-envelope-from 代替 -a default,根据您将要发送的消息中的 From: 字段自动选择账户。您还可以使用 --read-recipients,-t 来读取邮件的 To、Cc 和 Bcc 标头中的收件人地址,以及命令行中提供的收件人。Cronie 默认邮件客户端
要使 Cronie 使用 msmtp 而不是 sendmail,请确保已安装 msmtp-mta,或编辑 cronie.service systemd 单元。
/etc/systemd/system/cronie.service.d/msmtp.conf
[Service] ExecStart= ExecStart=/usr/bin/crond -n -m '/usr/bin/msmtp -t'
然后,您必须告诉 cronie 或 msmtp 您的电子邮件地址是什么。一种实现方法是将它添加到 msmtp 配置中。
- 添加到
/etc/msmtprcaliases /etc/aliases
- 创建
/etc/aliasesyour_username: email@address.com
或者,您可以直接将其添加到 crontab 中。
- 向 crontab 添加
MAILTO行。MAILTO=email@address.com
- 向 crontab 添加
MAILFROM行。MAILFROM=email@address-from-msmtp.com
- 最后一部分对于防止此错误至关重要。
sendmail: server message: 550 5.7.1 Rejected due to unmatching envelope and header sender.
密码管理
msmtp 的密码可以存储在明文、加密文件或密钥环中。
GNOME Keyring
msmtp 原生支持将密码存储在 GNOME Keyring 中。按照链接的 wiki 页面上的说明设置密钥环并安装 libsecret。然后,通过运行以下命令存储密码:
secret-tool store --label=msmtp host smtp.your.domain service smtp user yourusername
msmtp 现在应该会自动找到密码。
GnuPG
password 指令可以省略。在这种情况下,如果相关账户的 auth 设置为除 off 之外的有效值,从交互式 shell 调用 msmtp 将在发送邮件前询问密码。如果 msmtp 是由其他类型的应用程序(如 Mutt)调用的,它将不会提示。对于这种情况,可以使用 --passwordeval 参数调用外部密钥环工具,如 GnuPG。
要做到这一点,请设置 GnuPG,包括 gpg-agent,以避免每次都输入密码。然后,为此类的 msmtp 创建一个加密密码文件。如下进行:创建一个权限为 700 的安全目录,该目录位于 tmpfs 上,以避免将未加密的密码写入磁盘。在该目录中创建一个包含邮件账户密码的纯文本文件。然后,使用您的私钥加密该文件。
$ gpg --default-recipient-self -e /path/to/plain/password
删除纯文本文件,并将加密文件移动到最终位置,例如 ~/.mail/.msmtp-credentials.gpg。在 ~/.msmtprc 中添加:
~/.msmtprc
passwordeval "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.mail/.msmtp-credentials.gpg"
通常,这足以在发送 Mutt 中的消息时出现 GUI 密码提示。如果无法发出 gpg 提示请输入密码,则先启动 gpg-agent。启动代理的一个简单技巧是使用反引号 `command` 语法在您的 muttrc 中执行外部命令。例如,您可以将以下内容放在您的 muttrc 中:
muttrc
set my_msmtp_pass=`gpg -d mypwfile.gpg`
Mutt 将在启动时执行此命令,gpg-agent 将缓存您的密码,msmtp 将正常工作,您可以发送邮件。
另一种选择是将密码放在 ~/.netrc 中,该文件可以作为 msmtp、OfflineIMAP 和相关工具的通用池。
pass
您可以在 pass 密码管理器中存储您的凭据。
如果您使用您的主密码(通常存储在您的 pass 文件第一行)登录您的 SMTP 服务器,您可以将以下内容添加到您的 .msmptrc 中:
~/.msmtprc
passwordeval "pass your_email_password_entry | head -n1"
如果您正在使用 Gmail 并已设置了应用专用密码,以下配置将更适合您。将您的应用专用密码保存在您的 pass 密码文件中,但加上 msmtp: 前缀。
your_email_password_entry
your_main_password login: your_username url: the_url_of_your_email msmtp: your_msmtp_app_password
然后将以下内容添加到您的 .msmptrc 中:
~/.msmtprc
passwordeval "pass your_email_password_entry | awk '/^msmtp:/ { print $2; }'"
在任一情况下,尝试使用 msmtp 发送电子邮件都将触发 pass,如果您最近未输入过 pass 主密码,它可能会要求您输入。
杂项
离线使用 msmtp
尽管 msmtp 很棒,但它要求您在线才能使用。这对于连接不稳定的笔记本电脑用户或拨号用户来说并不理想。已经编写了几个脚本来解决这个问题,统称为 msmtpqueue。
这些脚本安装在 /usr/share/doc/msmtp/msmtpqueue 下。您可能希望将脚本复制到计算机上的便利位置(/usr/local/bin 是一个不错的选择)。
最后,更改您的 MUA,在发送电子邮件时使用 msmtp-enqueue.sh 而不是 msmtp。默认情况下,排队的邮件将存储在 ~/.msmtpqueue 中。要更改此位置,请在脚本中更改 QUEUEDIR=$HOME/.msmtpqueue 行(或删除该行,并在 .bash_profile 中导出 QUEUEDIR 变量,如下所示:export QUEUEDIR="$XDG_DATA_HOME/msmtpqueue")。
当您想发送您创建并排队的任何邮件时,运行:
$ /usr/local/bin/msmtp-runqueue.sh
将 /usr/local/bin 添加到您的 PATH 可以为您节省一些手动输入的键盘敲击。脚本附带的 README 文件包含一些有用的信息,建议阅读。
Vim 语法高亮
msmtp 源代码分发版包含一个用于 Vim 的 msmtprc 语法高亮脚本,位于 /usr/share/vim/vimfiles/syntax/msmtp.vim。文件类型不会自动检测。启用它的最简单方法是在文件顶部或底部添加一个 modeline,例如:
# vim:filetype=msmtp
使用 PHP 和 msmtp 发送邮件
在您的 php.ini 中查找 sendmail_path 选项并进行如下编辑:
sendmail_path = "/usr/bin/msmtp -C /path/to/your/config -t"
请注意,如果您计划将 msmtp 作为 sendmail 的替代品与 php 或类似工具一起使用,则不能使用用户配置文件(即 ~/ 下的配置文件)。在这种情况下,只需创建 /etc/msmtprc,然后删除您的用户配置文件(如果您打算将其用于其他用途,则不必删除)。还要确保您正在使用的工具(php、django 等)可以读取它。
来自 msmtp 手册:用户配置文件中定义的账户会覆盖系统配置文件中的账户。用户配置文件必须只有用户读/写权限。
因此,不可能拥有一个位于 ~/ 下的配置文件,同时又能被 php 用户读取。
要测试它,请将此文件放在您的 php 启用服务器上或使用 php-cli。
<?php
mail("your@email.com", "Test email from PHP", "msmtp as sendmail for PHP");
?>
php-fpm 将会因发送邮件失败并在日志中记录警告:PHP Warning: mail(mail.log): failed to open stream,除非您将 /etc/msmtprc 的权限设置为用户读/写 (600)。
故障排除
TLS 问题
如果您看到以下任一消息:
msmtp: TLS certificate verification failed: the certificate hasn't got a known issuer
msmtp: TLS certificate verification failed: The certificate is NOT trusted. The certificate issuer is unknown.
这很可能意味着您的配置文件中的 tls_trust_file 参数不正确。
只需遵循优秀的文档。它会解释如何找出给定 smtp 服务器的服务器证书颁发者。然后,您可以探索 /usr/share/ca-certificates/ 目录,看看您是否碰巧在那里找到了所需的证书。如果没有,您将不得不自己获取证书。如果您使用自己的证书,可以通过将以下内容添加到您的 ~/.msmtprc 来让 msmtp 信任它:
tls_fingerprint <SHA1 (recommended) or MD5 fingerprint of the certificate>
如果用户拥有服务器使用的证书,并且该证书存储在 PEM 文件中,他可以使用 openssl 找到存储的证书指纹。
openssl x509 -in CERT.pem -inform PEM -fingerprint
如果您尝试通过 Gmail 发送邮件并收到此错误,请查看此线程,或者只需使用上面提供的第二个 Gmail 示例。
如果您完全绝望,但 100% 确定您正在与正确的服务器通信,您可以随时暂时禁用证书检查:
$ msmtp --tls-certcheck off
如果您看到以下消息:
msmtp: TLS handshake failed: the operation timed out
您可能受到此bug的影响。使用 --with-ssl=openssl 重新编译(msmtp 默认使用 GnuTLS 编译)。
服务器发送了空回复
如果您收到“服务器发送了空回复”错误,这可能意味着邮件服务器不支持在端口 587 上使用 STARTTLS,而是需要通过端口 465 使用 TLS。
要让 msmtp 在端口 465 上使用 TLS,请将以下行添加到 ~/.msmtprc:
tls_starttls off
Zoho SMTP 服务器
当邮件在邮件头和邮件正文之间没有空行时,也可能在 Zoho SMTP 服务器上发生这种情况(参见 Debian bug #917260)。解决方法是在两者之间添加一个额外的空格:
"test-header\n\ntest-body"
GSSAPI 问题
如果您收到以下错误:
GNU SASL: GSSAPI error in client while negotiating security context in gss_init_sec_context() in SASL library. This is most likely due insufficient credentials or malicious interactions.
尝试将您的 auth 设置从 gssapi 更改为 plain,而不是在您的 .msmtprc 文件中[1]。
auth plain
信封未被接受
在以下情况下:
msmtp: envelope from address mail@server not accepted by the server msmtp: server message: 530 5.5.1 Authentication Required. msmtp: could not send mail (account default from /etc/msmtprc)
尝试启用身份验证:
auth on
或任何其他方法。