S-nail

来自 ArchWiki

此文章或章节需要语言、wiki 语法或风格方面的改进。请参阅 Help:Style 以获得参考。

原因: 非常冗长,大量代码,不符合风格指南。(在 Talk:S-nail 中讨论)

Arch Linux 使用 S-nail 作为其 POSIX mailx 的实现。S-nail 具有 MIME 功能,并扩展了行编辑、S/MIME、SMTP、IMAP、POP3 等功能。Mailx 是 Unix 邮件系统的用户端,而系统端传统上由 sendmail 承担。S-nail 也可以直接发送到外部 SMTP 服务器,因此不需要本地 MTA。

安装

安装 s-nail 软件包。

使用示例

由于系统范围的配置文件 (/etc/mail.rc) 引入了一些有用的标准,因此通过已安装的本地邮件传输代理 (MTA)(例如 sendmailpostfix)发送邮件可以像下面这样简单

# echo 'Message body' | mailx --debug --subject='A subject' --attach=an_attachment.txt foo1@bar.example 'Foo2 <foo2@bar.example>'

使用 -d/--debug 标志会产生沙盒 dry-run。您可以通过设置变量 mta 来调整用作 MTA 的程序(通过 mta-argumentsmta-no-default-argumentsmta-argv0 进行微调)。

请参阅手册 mailx(1)。特别是,请参阅 mailx(1) § 发送邮件和非交互模式

# < /etc/passwd LC_ALL=C.UTF-8 mailx --debug -:/ --set=sendwait --set=ttycharset=utf8 --set=mta=/usr/bin/sendmail --subject='My password file!' -. 'Back <side@book>'
# echo Message was passed successfully: $?

默认情况下,消息传递是异步的,mailx 会在准备好的消息传递给传递机制后立即退出,仅说明消息准备是否成功(或不成功)。但是,如果设置了 sendwait 选项,则启动的(内置或非内置)MTA 的退出状态将用作消息传递“成功”或“失败”状态。

-./--end-options 命令行选项将强制终止选项处理并打开消息发送模式。

如前面的示例所示,命令可以(并且应该)通过 LC_ALL=C.UTF-8-://−−resource-files=/ 从环境设置和配置文件中分离出来,并使用显式的 -S/--set-X/--startup-cmd 命令行标志来创建其自身的可重现设置。

在没有 MTA 干预的情况下,使用 expandaddr 选项可以将消息发送到文件和管道

# echo bla | mailx --set=expandaddr --subject=test ./mbox.mbox
# echo bla | mailx --set=expandaddr --subject=test '|cat >> ./mbox.mbox'
# echo bla | mailx --set=expandaddr --subject=test -

可以为 expandaddr 赋值并用于地址验证。以下示例假设 somefile.pdf 存在。如上所述,应删除 -d/--debug 以避免 dry run。它将 record 选项设置为用于记录所有传出邮件的文件,以便我们可以查看生成的邮件

# echo Body | \
>   LC_ALL=C.UTF-8 mailx --debug -:/ --set=v15-compat --set=sendwait --set=ttycharset=utf8 \
>     --set=from='Me <me@home>' \
>     --set=expandaddr=fail,-all,+addr \
>     --set=nosave --set=record=/tmp/out.mbox \
>     --set=mimetypes-load-control \
>     --startup-cmd='mimetype application/pdf pdf' \
>     --attach=somefile.pdf --subject=Subject \
>      -. '(foo2bar) <foo2@bar.example>' bob@hey.example
# mailx --read-only --file /tmp/out.mbox

手册章节 mailx(1) § 入门mailx(1) § 阅读邮件和交互模式 值得在寻找更多“速成”方法时浏览一下。

在以下情况中,当 USERPASS 作为 URL 的一部分指定时(且仅在此情况下),它们必须进行 URL 百分号编码:mailx 提供了 urlcodec 命令来为您执行此操作

# printf 'urlcodec encode USER PASS\nx\n' | mailx -#

-# 用于 -#/--batch-mode。printf 以及 mailx 都受您的区域设置影响

# # In UTF-8:
# printf 'urlcodec encode SPAß\nx\n' | mailx -#
  SPA%C3%9F
# # In ISO-8859-1:
# printf 'urlc enc SPAß\nx\n' | mailx -#
  SPA%DF

配置

配置文件是用户特定的 $HOME/.mailrc 和系统范围的 /etc/mail.rc,后者位于 PKGBUILD 的 备份数组 中,因此将在 s-nail 升级后保留。本文中的所有其余示例均基于此配置模板,该模板仅设置了一些安全和发送模式基础知识

# All the examples require v15-compat!
set v15-compat

# Arch Linux-specific locations of certificates.
# Since these are subject to the Arch Linux update mechanism,
# use only those, do not try to load OpenSSL builtin ones.
# And use the TLS specific set: see "man 8 update-ca-trust"
#set ssl-ca-dir=/etc/ssl/certs
set ssl-ca-file=/etc/ssl/certs/ca-certificates.crt
set ssl-ca-no-defaults

# Do not use protocols older than TLS v1.2.
# Change this only when the remote server does not support it:
# maybe use ssl-protocol-HOST (or -USER@HOST) syntax to define
# such explicit exceptions, then, e.g.
#     ssl-protocol-USER@archlinux.org="-ALL,+TLSv1.2"
set ssl-protocol=-ALL,+TLSv1.2

# Explicitly define the list of ciphers, which may improve security,
# especially with protocols older than TLS v1.2.  See ciphers(1).
# This is an example: in reality it is possibly best to only use
# ssl-cipher-list-HOST (or -USER@HOST), as necessary, again..
set ssl-cipher-list=TLSv1.2:!aNULL:!eNULL:@STRENGTH
#set ssl-cipher-list="ALL:!aNULL:!eNULL:!MEDIUM:!LOW:!MD5:!RC4:!EXPORT"

# Request strict transport security checks
set ssl-verify=strict

# Essential setting: select allowed character sets
# (Have a look at the "Character sets" manual section)
set sendcharsets=utf-8,iso-8859-1

# A very kind option: when replying to a message, first try to
# use the same encoding that the original poster used herself!
set reply-in-same-charset
# When replying to or forwarding a message the comment and name
# parts of email addresses are removed unless this variable is set
set fullnames

# When sending messages, wait until the Mail-Transfer-Agent finishs.
set sendwait

# Only use builtin MIME types, no mime.types(5) files.
# That set is often sufficient, but look at the output of the
# `mimetype' command to ensure this is true for you, too
set mimetypes-load-control

# Default directory where we act in (relative to $HOME if not absolute)
set folder=mail
# A leading "+" (often) means: under folder
# record is used to save copies of sent messages, $DEAD is error storage
# inbox: system mailbox, by default /var/mail/$USER: file %
# $MBOX: secondary mailbox: file &
set MBOX=+mbox.mbox record=+sent.mbox DEAD=+dead.mbox
set inbox=+system.mbox

# Define some shortcuts; now one may say, e.g., file mymbo
shortcut mymbo %:+mbox.mbox \
         myrec +sent.mbox

# This is optional, but you should get the big picture
# by reading the manual before you leave that off
set from="Your Name <youremail@domain>"

# Mailing-list specifics (manual: "Mailing lists"):
set followup-to followup-to-honour=ask-yes reply-to-honour=ask-yes
# And teach some non-subscribed / some subscribed lists, too
mlist @xyz-editor.xyz$ @xyzf.xyz$
mlsubscribe ^xfans@xfans.xyz$

使用外部 SMTP 服务器发送邮件

要通过内置 SMTP(简单邮件传输协议)客户端将消息发送到外部 SMTP 服务器,必须设置或调整几个选项。根据需要将以下内容添加到上述配置中,更改粗体字符串。阅读手册章节 mailx(1) § 关于 URL 语法和凭据查找 是值得的。

# It can be as easy as
# (Remember USER and PASS must be URL percent encoded)
set mta=smtp://USER:PASS@HOST \
    smtp-use-starttls

# It may be necessary to set hostname and/or smtp-hostname
# if the "SERVER" of smtp and "domain" of from do not match.
# Reading the "ON URL SYNTAX.." and smtp manual entries may be worthwhile
set mta=(smtp[s]/submission)://[USER[:PASS]@]SERVER[:PORT] \
    smtp-auth=login[/plain]... \
    smtp-use-starttls

# E.g. here is a real life example of a very huge free mail provider
# (Activate this account via mailx -AXooglX from the command line,
# or use the ? acc[ount] XooglX command in interactive mode)
account XooglX {
   # Localize options, forget them when changing the account
   localopts yes
   # (The plain smtp:// proto is optional)
   set mta=smtp://USER:PASS@smtp.gmXil.com smtp-use-starttls
   set from="Your Name <youremail@domain>"
}

# And here is a pretty large one which does not allow sending mails
# if there is a domain name mismatch on the SMTP protocol level,
# which would bite us if the value of from does not match, e.g.,
# for people who have a sXXXXeforge project and want to speak
# with the mailing list under their project account (in from),
# still sending the message through their normal mail provider
account XandeX {
   localopts yes
   set mta=smtps://USER:PASS@smtp.yaXXex.ru:465 \
       hostname=yaXXex.com smtp-hostname=
   set from="Your Name <youremail@domain>"
}
提示: 在 Gmail 中启用两步验证,并为 S-nail 添加应用专用密码,您将希望使用该密码而不是您的常规 Gmail 密码。

请注意,当在 $HOME/.mailrc 中存储密码时,您应该使用 chmod 0600 设置适当的 权限。您还可以设置 netrc-lookup 选项,并将用户凭据存储在 $HOME/.netrc(或 $NETRC)中;例如,这是一个实际示例,设置了 SMTP、POP3 以及 IMAP,并将所有用户凭据存储在那里

account XandeX {
   localopts yes
   set from="Your Name <youremail@domain>"
   wysh set netrc-lookup # netrc-pipe='gpg -qd ~/.netrc.gpg'
   set mta=smtps://smtp.yXXXXx.ru:465 \
       smtp-hostname= hostname=yXXXXx.com
   set pop3-keepalive=240
   shortcut pop pop3s://pop.yXXXXx.ru
   # Type xp to login to the POP3 account
   commandalias xp 'fi pop'
   set imap-keepalive=240
   shortcut imap imaps://imap.yXXXXx.ru
   # Type xi to login to the IMAP account
   commandalias xi 'fi imap'
 }

并且,在 $HOME/.netrc

machine *.yXXXXx.ru login USER password PASS

在这种情况下,USERPASS 是明文,而不是 URL 编码的。您可以进一步多样化,并使用加密密码存储。要相应地调整示例,只需使用 OpenPGP 加密您的 ~/.netrc 文件,并取消注释上面的 netrc-pipe 语句。可以像这样创建加密存储 ~/.netrc.gpg

# gpg -e .netrc
# eval `gpg-agent --daemon --pinentry-program=/usr/bin/pinentry-curses --max-cache-ttl 99999 --default-cache-ttl 99999`

测试配置(使用 -d/--debug 命令行选项进行 dry-run)

# echo test-body | mailx --verbose --verbose --account=XandeX --subject=test-subject some@where

交互式使用

在整个手册中,交互式使用被称为“撰写模式”。mailx(1) § 撰写模式

Mailx 具有支持宽字形的命令行编辑器,具有历史记录功能和彩色消息显示支持。因为它力求符合 POSIX 标准,所以在交互式使用之前必须调整一些设置,但这并不能阻止所有描述。阅读 mailx(1) 是不可避免的,但至少在示例配置之上添加以下内容

# (The global configuration /etc/mail.rc provides some commented basics;
# in particular it shows all options that POSIX mandates as defaults.)

# Start into interactive mode even if the system mailbox is empty or
# does not exist.  mailx will exit immediately without that one
set emptystart

# When composing a message, start directly into $EDITOR
set editalong

# Start $PAGER when a message is longer than VALUE lines;
# without VALUE: screen $LINES
set crt=

# A nicer prompt for a modern terminal
wysh set prompt='?\${?}!\${!}[\${account}#\${mailbox-display}]? '

# Add more entries to the history, and make that persistent
set history-gabby history-file=+.s-nailhist
# When printing messages, show only these headers
# (Easier to retain what you want than to ignore
# what you do not; use Print to see all headers and Show
# to see the raw message content)
retain date from to cc subject

# Try to get around weird MIME attachment specifications
# (This option can take a value, see the manual for more)
set mime-counter-evidence=0xE

# Display HTML parts inline, nicer than what the builtin viewer can achieve
#set pipe-text/html='@* lynx -stdin -dump -force_html'
# Learn another mimetype
mimetype model/vrml wrl vrml

# Create some new commands so that, e.g., `ls /tmp' will..
commandalias ls !ls -latro
commandalias ps !ps axu

进入后,使用 list 打印所有可用的内置命令。键入 `?X' 尝试展开 "X" 并打印帮助字符串;由于 mailx 允许缩写所有命令,因此这有时很方便,例如,尝试 ?h?he?hel ... 命令 help 将打印最常用命令的简短摘要,如果设置了变量 verbose,则会更多。

用法

当启动进入交互模式时,会打印初始打开的邮箱内容的摘要,就像通过 headers 命令一样。在标头显示中,消息被赋予数字(从 1 开始),这些数字唯一标识消息。可以使用 print 命令打印消息,或简写:pp 尊重要显示的标头的 retain(或 ignore)列表,而 Print 命令则不会,并且会显示所有标头;Show 命令将打印原始消息内容。

默认情况下,打印当前消息(点),但就像许多其他命令一样,可以指定消息列表,如手册章节 mailx(1) § 指定消息 中所述;例如,p:u 将显示所有未读消息,p. 将打印当前消息(点),p 1 5 将打印消息 1 和 5,p-p+ 将分别打印上一条和下一条消息。请注意,在空行中简单地键入 RETURN 就像 next (n) 一样,因此会打印下一条消息。

from 命令对于概述很有用,例如,f '@<@arch linux 将打印所有消息的标头摘要,这些消息在某些消息标头中包含字符串“arch linux”,而 f '@arch linux 将仅匹配主题中包含“arch linux”的消息;最后,正则表达式 f @^A[^[:space:]]+ 查找主题以 A 字符开头的所有消息,并且在该 A 字符之后没有空格字符。请注意,当搜索表达式等中存在空格时,可能需要引用。

  • fileFile 打开一个新的邮箱,后者以只读模式打开
  • newmail(取决于邮箱,检查新邮件并)打印新消息的列表
  • he(headers)重新打印消息列表
  • z- z+ z0 z$ 滚动浏览标头显示(取决于您使用的终端,Home/End/PageUp/PageDown 键将是可用的别名)
  • folders 显示当前设置的 folder 下的邮箱列表
  • r 回复给定消息的所有收件人
  • R 回复给定消息的发送者
  • Lreply “邮件列表”回复给定消息
  • movemv 移动(一条或多条)消息
  • (un)flag 将(一条或多条)消息标记为(未)标记
  • new 将(一条或多条)消息标记为未读
  • seen 将(一条或多条)消息标记为已读
  • P 打印(一条或多条)消息以及所有标头
  • p 打印(一条或多条)消息以及所有非忽略标头
  • show 打印(一条或多条)消息的原始消息内容
  • writew 以本机格式将消息和附件下载到本地存储

消息撰写

撰写通过键入 mail user@host 或回复消息开始。当您输入 $EDITOR(假设设置了 editalong)时,您将发现自己处于本机编辑器中,您可以在其中使用波浪号转义符执行许多操作(通过 ~? 获得简短帮助)。特别感兴趣的是 ~@,它允许交互式编辑附件列表,或者,当给定参数时,添加(一个或多个)(逗号分隔的列表)附加附件,以及 ~^,它是一个多路复用器命令,提供对消息的一些控制,例如,创建自定义标头。

要发送邮件,请使用 Ctrl+d 发送 EOT 信号或键入 ~. 在单独的一行上。

使用 S/MIME

该手册包含有关如何创建证书等的逐步示例 (mailx(1) § 使用 S/MIME 签名和加密消息 以及 mailx(1) § S/MIME 逐步指南)。假设您已经拥有私钥和签名证书,只需创建我们需要的配对文件

# cat private-key.pem signed-certificate.pem > ~/pair.pem

并通过以下方式设置 S-nail

set smime-sign-cert=~/pair.pem \
    smime-sign-message-digest=SHA256 \
    smime-sign

从现在开始,发送的任何消息都将被签名。默认消息摘要将是 SHA1,这是 RFC:5751 要求的。请注意,S/MIME 始终相对于变量 from 的设置工作,因此最好将上述设置放在 account 中。verify 命令验证 S/MIME 消息,但请注意,S/MIME 解密和验证目前完全基于 OpenSSL,它仅支持具有简单 MIME 结构的消息。

OpenPGP 支持缺失的变通方法

S-nail 尚不支持 OpenPGP。但是,使用宏,至少可以自动验证内联 --clearsign 签名的消息,并且使用命令别名,它们的用法变得方便:例如,在资源文件中使用以下内容,您只需键入 V 即可验证 clearsigned 消息

define V {
   \localopts yes; \wysh set pipe-text/plain=$'@*#++=@\
      < "${MAILX_FILENAME_TEMPORARY}" awk \
            -v TMPFILE="${MAILX_FILENAME_TEMPORARY}" \'\
         BEGIN{done=0}\
         /^-----BEGIN PGP SIGNED MESSAGE-----/,/^$/ {\
            if(done++ != 0)\
               next;\
            print "--- GPG --verify ---";\
            system("gpg --verify " TMPFILE " 2>&1");\
            print "--- GPG --verify ---";\
            print "";\
            next;\
         }\
         /^-----BEGIN PGP SIGNATURE-----/,/^-----END PGP SIGNATURE-----/ {\
            next;\
         }\
         {print}\
         \;\
      print
}
define RK {
  !printf 'Key IDs to gpg --recv-keys: ';\
    read keyids;\
    gpg --recv-keys ${keyids};
}
commandalias V '\'call V
commandalias RK '\call RK'

使用 IMAP 邮箱

以下只是一些快速提示。还可以定义 folderinbox 以指向 IMAP 服务器文件夹,例如。支持国际化名称。

set v15-compat
# or many servers will expire the session
set imap-keepalive=240
set imap-cache=~/.imap_cache
# You may want to define shortcuts to folders, for example:
shortcut myimap "imaps://USER:PASS@server:port"
set inbox=myimap

参见