现在我们将解释当两个人通过电子邮件进行通信时通常发生的信息流。 让我们假设 Alice,在她的机器 wonderland.com
上,想要发送邮件给 Bob,在他的机器 dobbs.com
上。 两台机器都连接到互联网。
了解互联网邮件消息由两个部分组成会很有帮助:邮件头和邮件正文,它们之间用空行分隔。 邮件头包含邮件的来源和目的地、用户提供的主题行、发送日期以及各种其他有用的信息。 正文是消息的实际内容。 这是一个例子
From: "Alice" <alice@wonderland.com> Message-Id: <199711131704.MAA18447@wonderland.com> Subject: Have you seen my white rabbit? To: bob@dobbs.org (Bob) Date: Thu, 13 Nov 1997 12:04:05 -0500 (EST) Content-Type: text I'm most concerned. I fear he may have fallen down a hole. -- >>alice>>
互联网邮件头的排列和含义由名为 RFC822 的互联网标准定义。
这是一个完整过程的图表 —— 我将在下面解释所有阶段和术语。
+---------+ +-------+ +-------+ types | sending | calls |sending| | Alice |--------->| MUA |--------->| MTA |::::>:::: +-------+ | | | | :: on the +---------+ +-------+ :: sending :: machine ....................................................................... SMTP :: ::::::::::::::::::::::::::::<:::::::::::::::::::::::::::: :: :: +---------+ +-----+ +-------+ :: |receiving| calls | | delivers to | Bob's | ::::>| MTA |--------->| LDA |===============>|mailbox| on the | | | | | | receiving +---------+ +-----+ +-------+ machine | | | | +----------------<-------------+ | | | +---------+ +-------+ | | Bob's | | Bob's |<----------+ | notifier| | MUA | +---------+ +-------+ | | | +-----+ | +----->| Bob |<----+ +-----+
要发送邮件,Alice 将调用一个名为邮件用户代理(或简称 MUA)的程序。 MUA 是用户认为的“邮件程序”; 它帮助她编写消息,通常通过调用她选择的文本编辑器。 当她点击 MUA 的“发送”按钮时,她的部分过程就完成了。 在本 HOWTO 的后面,我们将调查流行的 MUA。
她使用的 MUA 立即将她的消息传递给一个名为邮件传输代理(或 MTA)的程序。 通常这个程序是 sendmail
,尽管一些替代的 MTA 正在流行,并且可能会出现在未来的 Linux 发行版中。 在本 HOWTO 的后面,我们也将调查 MTA。
MTA 的工作是将邮件传递给 Bob 机器上的 MTA。 它通过分析 To 标头并查看 Bob 地址右侧的 dobbs.com
来确定 Bob 的机器。 它使用该地址打开与 Bob 机器的互联网连接。 建立该连接的机制是另一个完整的主题; 对于这个解释,知道该连接是 Alice 的 MTA 向 Bob 的机器发送文本命令并接收对这些命令的回复的一种方式就足够了。
MTA 的命令不会发送到 shell。 相反,它们会发送到 Alice 机器上的服务端口。 服务端口是一种汇合点,是互联网服务程序监听传入请求的已知位置。 服务端口已编号,Alice 的 MTA 知道它需要与 Bob 机器上的端口 25 通信才能传递邮件。
在端口 25 上,Bob 的机器有自己的 MTA 监听命令(可能是 sendmail
的另一个副本)。 Alice 的 MTA 将使用简单邮件传输协议(或 SMTP)与 Bob 的 MTA 进行对话。 以下是 SMTP 对话的样子。 Alice 机器发送的行用 S: 表示,Bob 机器的响应用 R: 表示。
S: MAIL FROM:<alice@wonderland.com> R: 250 OK S: RCPT TO:<bob@dobbs.com> R: 250 OK S: DATA R: 354 Start mail input; end with <CRLF>.<CRLF> S: From: "Alice" <alice@wonderland.com> S: Message-Id: <199711131704.MAA18447@wonderland.com> S: Subject: Have you seen my white rabbit? S: To: bob@dobbs.org (Bob) S: Date: Thu, 13 Nov 1997 12:04:05 -0500 (EST) S: Content-Type: text S: S: I'm most concerned. I fear he may have fallen down a hole. S: -- S: >>alice>> S: . R: 250 OK
通常,SMTP 命令是单行文本,其响应也是如此。 DATA 命令是一个例外; 在看到它之后,SMTP 监听器会接受消息行,直到它看到一行单独的句点为止。(SMTP 由互联网标准 RFC821 定义。)
现在 Bob 的 MTA 收到了 Alice 的消息。 它将在消息中添加一个看起来像这样的标头
Received: (from alice@wonderland.com) by mail.dobbs.com (8.8.5/8.8.5) id MAA18447 for bob@dobbs.com; Thu, 13 Nov 1997 12:04:05 -0500
这用于跟踪目的,以防邮件错误(有时消息必须通过多台机器中继,并且会有多个这样的标头)。 Bob 的 MTA 会将修改后的消息传递给本地投递代理或 LDA。 在 Linux 系统上,LDA 通常是一个名为 procmail
的程序,尽管也存在其他程序。
LDA 的工作是将消息附加到 Bob 的邮箱。 它与 MTA 分开,以便这两个程序都可以更简单,并且 MTA 可以专注于执行互联网事务,而无需担心用户邮箱的本地详细信息。
Bob 的邮箱通常是一个名为 /usr/spool/mail/bob 或 /var/mail/bob 的文件。 当他读取邮件时,他运行自己的 MUA(邮件用户代理)来查看和编辑该文件。
还有另一种程序在邮件链中很重要,尽管它本身不读取或传输邮件。 这是一个邮件通知器,一个监视您的电子邮件收件箱中的活动并在收到新邮件时向您发出信号的程序。
最初的通知器是一对名为 biff(1) 和 comsat(8) 的 Unix 程序。 biff 程序是一个前端,可让您启用 comsat 服务。 当此服务开启时,新邮件的标头将在到达时转储到您的终端。 此功能是为在 CRT 上使用面向行程序的人设计的; 在今天的环境中,这实际上不是一个好主意。
大多数 Unix shell 都有内置的邮件检查功能,这些功能允许它们以一种不太具有侵入性的方式充当通知器(在检测到新邮件时,仅在提示符之前发出消息)。 通常,您可以通过设置 shell 手册页上记录的环境变量来启用此功能。 对于 sh/ksh/bash 系列中的 shell,请参阅 MAIL 和 MAILPATH 变量
支持 X 的系统附带了几个小桌面小工具之一,这些小工具定期检查新邮件,并在收到新邮件时为您提供可见和可听的指示。 其中最古老和最广泛使用的是 xbiff; 如果您的 Linux 有预配置的 X 桌面设置,则 xbiff 很可能就在上面。 有关详细信息,请参阅 xbiff(1) 手册页。
如果您仔细阅读,您可能已经注意到我们上面描述的信息流取决于 Alice 的机器能够立即与 Bob 的机器对话。 如果 Bob 的机器宕机,或者已启动但未连接到互联网,会发生什么情况?
如果 Alice 的 MTA 无法立即联系到 Bob 的 MTA,它会将 Alice 的消息暂存在 wonderland.com
上的邮件队列中。 然后,它将以间隔重试发送邮件,直到达到过期时间,届时会向 Alice 发送退回消息,通知她失败。 在最流行的 MTA (sendmail) 的默认配置中,重试间隔为 15 分钟,过期时间为 4 天。
如今,许多 Linux 用户通过 ISP(互联网服务提供商)连接到互联网,并且没有自己的互联网域名。 相反,他们在 ISP 机器上拥有帐户。 他们的邮件被传递到该 ISP 机器上的邮箱。 但是,通常这些用户希望使用自己的机器读取和回复他们的邮件,这些机器使用 SLIP 或 PPP 间歇性地连接到 ISP。 Linux 支持远程邮件协议来支持这一点。
请注意,这与我们在上一节中讨论的场景有何不同。 位于队列中等待重新传输的邮件与分发到服务器邮箱的邮件不同; 队列中的邮件不被视为已传递,并且会过期,但传递到 ISP 服务器邮箱的邮件被视为“已传递”,并且可以无限期地保存在那里。
远程邮件协议允许服务器上的邮件被客户端程序通过网络链接拉取(这与 MTA 将邮件推送到接收 MTA 的正常传递相反)。 有两种常用的远程邮件协议; POP3(由互联网标准 RFC1939 定义)和 IMAP(由互联网标准 RFC2060 定义)。 几乎所有 ISP 都支持 POP3; 越来越多的 ISP 支持 IMAP(功能更强大)。
以下是一个 POP3 会话示例
S: <client connects to service port 110> R: +OK POP3 server ready <1896.697170952@mailgate.dobbs.org> S: USER bob R: +OK bob S: PASS redqueen R: +OK bob's maildrop has 2 messages (320 octets) S: STAT R: +OK 2 320 S: LIST R: +OK 2 messages (320 octets) R: 1 120 R: 2 200 R: . S: RETR 1 R: +OK 120 octets R: <the POP3 server sends message 1> R: . S: DELE 1 R: +OK message 1 deleted S: RETR 2 R: +OK 200 octets R: <the POP3 server sends message 2> R: . S: DELE 2 R: +OK message 2 deleted S: QUIT R: +OK dewey POP3 server signing off (maildrop empty) S: <client hangs up>
IMAP 会话使用不同的命令和响应,但在逻辑上非常相似。
要利用 POP3 或 IMAP,您需要一个远程邮件客户端程序来拉取您的邮件。 一些邮件用户代理内置了客户端功能(下面注明了哪些支持哪些),并且 Netscape 浏览器的邮件工具原生支持 POP 和 IMAP。
MUA 中内置的 POP 客户端设施的主要缺点是您必须显式地告诉您的邮件程序轮询服务器; 您不会像本地邮件或通过传统的 SMTP “推送”连接传递的邮件那样收到 xbiff(1) 或等效程序的通知。 当然,并非所有 MUA 都可以执行 POP/IMAP,因此您可能会发现自己在其他功能上妥协。
您的 Linux 可能附带了一个名为 fetchmail 的程序,该程序专门设计用于与远程邮件服务器对话、获取邮件,并通过向您的监听器发送 SMTP 将其馈送到您的正常邮件传递路径中。
除非您需要将邮件保留在服务器上(例如,因为您在客户端机器之间频繁移动),否则 fetchmail 可能比您的用户代理拥有的任何 POP/IMAP 功能都更好。 可以告诉 Fetchmail 在后台运行并定期轮询您的服务器,因此您的 xbiff(1) 或其他邮件通知程序将像 SMTP 邮件一样工作。 此外,与 MUA 中的客户端相比,fetchmail 对各种特性和非标准服务器怪癖的容忍度更高,并且具有更好的错误恢复能力。
这是一个图表,显示了两种情况(有和没有 fetchmail)的工作方式
+---------+ +-------+ +-------+ types | sending | calls |sending| | Alice |--------->| MUA |--------->| MTA |::::>:::: +-------+ | | | | :: +---------+ +-------+ :: on the :: sending SMTP :: machine ::::::::::::::::::::::::::::<:::::::::::::::::::::::::::: :: .::....................................................................... :: :: +---------+ +-----+ +-------+ :: |receiving| calls | | delivers | Bob's | ::::>| MTA |--------->| LDA |============>|server |::::>:::: | | | | to |mailbox| :: on the +---------+ +-----+ +-------+ :: mail :: server POP or IMAP :: ::::::::::::::::::::::::::::<::::::::::::::::::::::::::::::::::: :: .::........................................................................ :: :: +-----------+ :: | | :::::::>::::::::::::| fetchmail |:::::::: on the :: | | :: receiving :: +-----------+ :: machine, :: :: with fetchmail :: ::::::::::::::::<::::::::::::::::::: :: :: :: :: +---------+ +-----+ +-------+ :: :: |receiving| calls | | delivers to | Bob's | :: ::::>| MTA |--------->| LDA |===============>|mailbox| :: | | | | | | :: +---------+ +-----+ +-------+ :: | | :: | | :: +----------------<-------------+ | :: | | :: +---------+ +-------+ | :: | Bob's | | Bob's |<----------+ :: | notifier| | MUA | :: +---------+ +-------+ :: | | .::........................................................................ :: . | | :: without . | | :: fetchmail . | | :: . | +-----+ | :: +----------+ . +----->| |<----+ :: | Bob's | . | Bob | :::::| POP/IMAP |----.--------->| | | MUA | . +-----+ +----------+ .
当传入邮件附加到邮箱时,由 MTA 提供一些分隔符,以指示一条消息在哪里停止,下一条消息在哪里开始。
在 Unix 下,几乎所有邮件程序都使用的约定是以 ``From ''(空格很重要)开头的每一行都表示一条新消息的开始。 如果 ``From '' 出现在文本行的开头,Unix MTA 通常会在其前面加上大于号,使其看起来像 ``>From ''。 RFC822 标头遵循此 From 行(通常继续包含发送者姓名和接收日期)。
此约定起源于 Unix Version 7,因此这种邮箱被称为“V7 邮箱”; 它有时也称为“mbox 格式”。 除非另有说明,否则本 HOWTO 中提到的所有程序都期望使用此格式。 然而,它并非完全通用,期望和生成不同格式的工具可能会彼此严重混淆。
需要了解(并警惕!)的其他四种格式是 BABYL、MMDF、MH 和 qmail maildir。 其中,MMDF 最简单; 它使用由四个 control-As (ASCII 001) 字符后跟 CR-LF 组成的分隔符行。 MMDF 是早期且相当粗糙的互联网邮件传输; 后代仍在 SCO 系统上使用。
BABYL 是另一种遗留物,来自 MIT 的早期邮件系统。 Emacs 的邮件阅读器模式仍然使用它。
MH 和 qmail maildir 是“邮箱”格式,它们实际上将每个邮箱分解为一个文件目录,每个消息一个文件。 在这样的“邮箱”上运行 grep 将一无所获,因为 grep 将看到的只是目录位。
Microsoft Outlook Express .mbx 邮箱可以使用 mbx2mbox 应用程序转换为 RFC822 格式。