天天看点

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

本节书摘来华章计算机《计算机网络:自顶向下方法(原书第6版)》一书中的第2章 ,第2.4节,(美)james f.kurose keith w.ross 著 陈 鸣 译 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

自从有了因特网,电子邮件就在因特网上流行起来。当因特网还在襁褓中时,电子邮件已经成为最为流行的应用程序[segaller 1998],年复一年,它变得越来越精细,越来越强大。它是当今因特网上最重要和实用的应用程序之一。

与普通邮件一样,电子邮件是一种异步通信媒介,即当人们方便时就可以收发邮件,不必与他人的计划进行协调。与普通邮件相比,电子邮件更为快速并且易于分发,而且价格便宜。现代电子邮件具有许多强大的特性,包括具有附件、超链接、html格式文本和图片的报文。

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件
《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

在本节中,我们将讨论位于因特网电子邮件的核心地位的应用层协议。在深入讨论这些应用层协议之前,我们先总体上看看因特网电子邮件系统和它的关键组件。

图2-16给出了因特网电子邮件系统的总体情况。从该图中我们可以看到它有3个主要组成部分:用户代理(user agent)、邮件服务器(mail server)和简单邮件传输协议(simple mail transfer protocol,smtp)。下面我们结合发送方alice发电子邮件给接收方bob的例子,对每个组成部分进行描述。用户代理允许用户阅读、回复、转发、保存和撰写报文。微软的outlook和apple mail是电子邮件用户代理的例子。当alice完成邮件撰写时,她的邮件代理向其邮件服务器发送邮件,此时邮件放在邮件服务器的外出报文队列中。

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

邮件服务器形成了电子邮件体系结构的核心。每个接收方(如bob)在其中的某个邮件服务器上有一个邮箱(mailbox)。bob的邮箱管理和维护着发送给他的报文。一个典型的邮件发送过程是:从发送方的用户代理开始,传输到发送方的邮件服务器,再传输到接收方的邮件服务器,然后在这里被分发到接收方的邮箱中。当bob要在他的邮箱中读取该报文时,包含他邮箱的邮件服务器(使用用户名和口令)来鉴别bob。alice的邮箱也必须能处理bob的邮件服务器的故障。如果alice的服务器不能将邮件交付给bob的服务器,alice的邮件服务器在一个报文队列(message queue)中保持该报文并在以后尝试再次发送。通常每30分钟左右进行一次尝试;如果几天后仍不能成功,服务器就删除该报文并以电子邮件的形式通知发送方(alice)。

smtp是因特网电子邮件中主要的应用层协议。它使用tcp可靠数据传输服务,从发送方的邮件服务器向接收方的邮件服务器发送邮件。像大多数应用层协议一样,smtp也有两个部分:运行在发送方邮件服务器的客户端和运行在接收方邮件服务器的服务器端。每台邮件服务器上既运行smtp的客户端也运行smtp的服务器端。当一个邮件服务器向其他邮件服务器发送邮件时,它就表现为smtp的客户;当邮件服务器从其他邮件服务器上接收邮件时,它就表现为一个smtp的服务器。

rfc 5321给出了smtp的定义。smtp是因特网电子邮件应用的核心。如前所述,smtp用于从发送方的邮件服务器发送报文到接收方的邮件服务器。smtp问世的时间比http要长得多(初始的smtp协议的rfc可追溯到1982年,而smtp在此之前很长一段时间就已经出现了)。尽管电子邮件应用在因特网上的独特地位可以证明smtp有着众多非常出色的性质,但它所具有的某种陈旧特征表明它仍然是一种继承的技术。例如,它限制所有邮件报文的体部分(不只是其首部)只能采用简单的7比特ascii表示。在20世纪80年代早期,这种限制是明智的,因为当时传输能力不足,没有人会通过电子邮件发送大的附件或是大的图片、声音或者视频文件。然而,在今天的多媒体时代,7位ascii的限制的确有点痛苦,即在用smtp传送邮件之前,需要将二进制多媒体数据编码为ascii码,并且在使用smtp传输后要求将相应的ascii码邮件解码还原为多媒体数据。2.2节讲过,使用http传送前不需要将多媒体数据编码为ascii码。

为了描述smtp的基本操作,我们观察一种常见的情景。假设alice想给bob发送一封简单的ascii报文。

alice调用她的邮件代理程序并提供bob的邮件地址(例如[email protected]),撰写报文,然后指示用户代理发送该报文。

alice的用户代理把报文发给她的邮件服务器,在那里该报文被放在报文队列中。

运行在alice的邮件服务器上的smtp客户端发现了报文队列中的这个报文,它就创建一个到运行在bob的邮件服务器上的smtp服务器的tcp连接。

在经过一些初始smtp握手后,smtp客户通过该tcp连接发送alice的报文。

在bob的邮件服务器上,smtp的服务器端接收该报文。bob的邮件服务器然后将该报文放入bob的邮箱中。

在bob方便的时候,他调用用户代理阅读该报文。

图2-17总结了上述这个情况。

观察到下述现象是重要的:smtp一般不使用中间邮件服务器发送邮件,即使这两个邮件服务器位于地球的两端也是这样。假设alice的邮件服务器在中国香港,而bob的服务器在美国圣路易斯,那么这个tcp连接也是从香港服务器到圣路易斯服务器之间的直接相连。特别是,如果bob的邮件服务器没有开机,该报文会保留在alice的邮件服务器上并等待进行新的尝试,这意味着邮件并不在中间的某个邮件服务器存留。

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

我们现在仔细观察一下,smtp是如何将一个报文从发送邮件服务器传送到接收邮件服务器的。我们将看到,smtp与人类面对面交往的行为方式有许多类似性。首先,客户smtp(运行在发送邮件服务器上)在25号端口建立一个到服务器smtp(运行在接收邮件服务器上)的tcp连接。如果服务器没有开机,客户会在稍后继续尝试连接。一旦连接建立,服务器和客户执行某些应用层的握手,就像人们在互相交流前先进行自我介绍一样。smtp的客户和服务器在传输信息前先相互介绍。在smtp握手的阶段,smtp客户指示发送方的邮件地址(产生报文的那个人)和接收方的邮件地址。一旦该smtp客户和服务器彼此介绍之后,客户发送该报文。smtp能依赖tcp提供的可靠数据传输无差错地将邮件投递到接收服务器。该客户如果有另外的报文要发送到该服务器,就在该相同的tcp连接上重复这种处理;否则,它指示tcp关闭连接。

接下来我们分析一个在smtp客户(c)和smtp服务器(s)之间交换报文脚本的例子。客户的主机名为crepes.fr,服务器的主机名为hamburger.edu。以c:开头的ascii码文本行正是客户交给其tcp套接字的那些行,以s:开头的ascii码则是服务器发送给其tcp套接字的那些行。一旦创建了tcp连接,就开始了下列过程。

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

在上例中,客户从邮件服务器crepes.fr向邮件服务器hamburger.edu发送了一个报文(“do you like ketchup?how about pickles?”)。作为对话的一部分,该客户发送了5条命令:helo(是hello的缩写)、mail from、rcpt to、data以及quit。这些命令都是自解释的。该客户通过发送一个只包含一个句点的行,向服务器指示该报文结束了。(按照ascii码的表示方法,每个报文以crlf.crlf结束,其中的cr和lf分别表示回车和换行。)服务器对每条命令做出回答,其中每个回答含有一个回答码和一些(可选的)英文解释。我们在这里指出smtp用的是持续连接:如果发送邮件服务器有几个报文发往同一个接收邮件服务器,它可以通过同一个tcp连接发送这些所有的报文。对每个报文,该客户用一个新的mail from:crepes.fr开始,用一个独立的句点指示该邮件的结束,并且仅当所有邮件发送完后才发送quit。

我们强烈推荐你使用telnet与一个smtp服务器进行一次直接对话。使用的命令是

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

其中servername是本地邮件服务器的名称。当你这么做时,就直接在本地主机与邮件服务器之间建立一个tcp连接。输完上述命令后,你立即会从该服务器收到220回答。接下来,在适当的时机发出helo、mail from、rcpt to、data、crlf.crlf以及quit等smtp命令。强烈推荐你做本章后面的编程作业3。在该作业中,你将在smtp的客户端实现一个简单的用户代理,它允许你经本地邮件服务器向任意的接收方发送电子邮件报文。

我们简要地比较一下smtp和http。这两个协议都用于从一台主机向另一台主机传送文件:http从web服务器向web客户(通常是一个浏览器)传送文件(也称为对象);smtp从一个邮件服务器向另一个邮件服务器传送文件(即电子邮件报文)。当进行文件传送时,持续的http和smtp都使用持续连接。因此,这两个协议有一些共同特征。然而,两者之间也有一些重要的区别。首先,http主要是一个拉协议(pull protocol),即在方便的时候,某些人在web服务器上装载信息,用户使用http从该服务器拉取这些信息。特别是tcp连接是由想接收文件的机器发起的。另一方面,smtp基本上是一个推协议(push protocol),即发送邮件服务器把文件推向接收邮件服务器。特别是,这个tcp连接是由要发送该文件的机器发起的。

第二个区别就是我们前面间接地提到过的,smtp要求每个报文(包括它们的体)使用7比特ascii码格式。如果某报文包含了非7比特ascii字符(如具有重音的法文字符)或二进制数据(如图形文件),则该报文必须按照7比特ascii码进行编码。http数据则不受这种限制。

第三个重要区别是如何处理一个既包含文本又包含图形(也可能是其他媒体类型)的文档。如我们在2.2节知道的那样,http把每个对象封装到它自己的http响应报文中,而smtp则把所有报文对象放在一个报文之中。

当alice给bob写一封邮寄时间很长的普通信件时,她可能要在信的上部包含各种各样的环境首部信息,如bob的地址、她自己的回复地址以及日期等。同样,当一个人给另一个人发送电子邮件时,一个包含环境信息的首部位于报文体前面。这些环境信息包括在一系列首部行中,这些行由rfc 5322定义。首部行和该报文的体用空行(即回车换行)进行分隔。rfc 5322定义了邮件首部行和它们的语义解释的精确格式。如同http协议,每个首部行包含了可读的文本,是由关键词后跟冒号及其值组成的。某些关键词是必需的,另一些则是可选的。每个首部必须含有一个from:首部行和一个to:首部行;一个首部也许包含一个subject:首部行以及其他可选的首部行。注意到下列事实是重要的:这些首部行不同于我们在2.4.1节所学到的smtp命令(即使那里也包含了某些相同的词汇,如from和to)。那节中的命令是smtp握手协议的一部分;本节中研究的首部行则是邮件报文自身的一部分。

一个典型的报文首部看起来如下:

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

在报文首部之后,紧接着一个空白行,然后是以acsii格式表示的报文体。你应当用telnet向邮件服务器发送包含一些首部行的报文,包括subject:首部行。为此,输入命令telnet servername 25,如在2.4.1节中讨论的那样。

一旦smtp将邮件报文从alice的邮件服务器交付给bob的邮件服务器,该报文就被放入了bob的邮箱中。在此讨论中,我们按惯例假定bob是通过登录到服务器主机,并直接在该主机上运行一个邮件阅读程序来阅读他的邮件的。直到20世纪90年代早期,这都是一种标准方式。而在今天,邮件访问使用了一种客户-服务器体系结构,即典型的用户通过在用户端系统上运行的客户程序来阅读电子邮件,这里的端系统可能是办公室的pc、便携机或者是智能手机。通过在本地主机上运行邮件客户程序,用户享受一系列丰富的特性,包括查看多媒体报文和附件的能力。

假设bob(接收方)在其本地pc上运行用户代理程序,考虑在他的本地pc上也放置一个邮件服务器是自然而然的事。在这种情况下,alice的邮件服务器就能直接与bob的pc进行对话了。然而这种方法会有一个问题。前面讲过邮件服务器管理用户的邮箱,并且运行smtp的客户端和服务器端。如果bob的邮件服务器位于他的pc上,那么为了能够及时接收可能在任何时候到达的新邮件,他的pc必须总是不间断地运行着并一直保持在线。这对于大多数因特网用户而言是不现实的。相反,典型的用户通常在本地pc上运行一个用户代理程序,而它访问存储在总是保持开机的共享邮件服务器上的邮箱。该邮件服务器与其他用户共享,并且通常由用户的isp进行维护(如大学或公司)。

现在我们考虑当从alice向bob发送一个电子邮件报文时所取的路径。我们刚才已经知道,在沿着该路径的某些点上,电子邮件报文存放在bob的邮件服务器上。通过让alice的用户代理直接向bob的邮件服务器发送报文,就能够做到这一点。这能够由smtp来完成:实际上,smtp被设计成将电子邮件从一台主机推到另一台主机。然而,通常alice的用户代理和bob的邮件服务器之间并没有一个直接的smtp对话。相反,如图2-18所示,alice的用户代理用smtp将电子邮件报文推入她的邮件服务器,接着她的邮件服务器(作为一个smtp客户)再用smtp将该邮件中继到bob的邮件服务器。为什么该过程要分成两步呢?主要是因为不通过alice的邮件服务器进行中继,alice的用户代理将没有任何办法到达一个不可达的目的地接收服务器。通过首先将邮件存放在自己的邮件服务器中,alice的邮件服务器可以重复地尝试向bob的邮件服务器发送该报文,如每30分钟一次,直到bob的邮件服务器变得运行为止。(并且如果alice的邮件服务器关机,她则能向系统管理员进行申告!)smtp rfc文档定义了如何使用smtp命令经过多个smtp服务器进行报文中继。

但是这里仍然有一个疏漏的环节!像bob这样的接收方,是如何通过运行其本地pc上的用户代理,获得位于他的某isp的邮件服务器上的邮件呢?值得注意的是bob的用户代理不能使用smtp取回报文,因为取报文是一个拉操作,而smtp协议是一个推协议。通过引入一个特殊的邮件访问协议来解决这个难题,该协议将bob邮件服务器上的报文传送给他的本地pc。目前有一些流行的邮件访问协议,包括第三版的邮局协议(post office protocol—version 3,pop3)、因特网邮件访问协议(internet mail access protocol,imap)以及http。

图2-18总结了应用于因特网电子邮件的一些协议:smtp用来将邮件从发送方的邮件服务器传输到接收方的邮件服务器;smtp也用来将邮件从发送方的用户代理传送到发送方的邮件服务器。如pop3这样的邮件访问协议用来将邮件从接收方的邮件服务器传送到接收方的用户代理。

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

1.pop3

pop3是一个极为简单的邮件访问协议,由rfc 1939进行定义。文档rfc 1939简短且可读性强。因为该协议非常简单,故其功能相当有限。当用户代理(客户)打开了一个到邮件服务器(服务器)端口110上的tcp连接后,pop3就开始工作了。随着建立tcp连接,pop3按照三个阶段进行工作:特许(authorization)、事务处理以及更新。在第一个阶段即特许阶段,用户代理发送(以明文形式)用户名和口令以鉴别用户。在第二个阶段即事务处理阶段,用户代理取回报文;同时在这个阶段用户代理还能进行如下操作,对报文做删除标记,取消报文删除标记,以及获取邮件的统计信息。在第三个阶段即更新阶段,它出现在客户发出了quit命令之后,目的是结束该pop3会话;这时,该邮件服务器删除那些被标记为删除的报文。

在pop3的事务处理过程中,用户代理发出一些命令,服务器对每个命令做出回答。回答可能有两种:+ok(有时后面还跟有服务器到客户的数据),被服务器用来指示前面的命令是正常的;-err,被服务器用来指示前面的命令出现了某些差错。

特许阶段有两个主要的命令:user 和pass 。为了举例说明这两个命令,我们建议你直接用telnet登录到pop3服务器的110端口,然后发出这两个命令。假设邮件服务器的名字为mailserver,那么你将看到类似的过程:

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

如果你的命令拼写错了,该pop3服务器将返回一个-err报文。

现在我们来看一下事务处理过程。使用pop3的用户代理通常被用户配置为“下载并删除”或者“下载并保留”方式。pop3用户代理发出的命令序列取决于用户代理程序被配置为这两种工作方式的哪一种。使用下载并删除方式,用户代理发出list、retr和dele命令。举例来说,假设用户在他(她)的邮箱里有两个报文。在下面的对话中,c:(代表客户)是用户代理,s:(代表服务器)是邮件服务器。事务处理过程将类似于如下过程:

《计算机网络:自顶向下方法(原书第6版)》一2.4 因特网中的电子邮件

用户代理首先请求邮件服务器列出所有存储的报文的长度。接着用户代理从邮件服务器取回并删除每封邮件。注意在特许阶段以后,用户代理仅使用四个命令:list、retr、dele和quit,这些命令的语法定义在rfc 1939中。在处理quit命令后,pop3服务器进入更新阶段,从用户的邮箱中删除邮件1和2。

使用下载并删除方式存在的问题是,邮件接收方bob可能是移动的,可能希望从多个不同的机器访问他的邮件报文,如从办公室的pc、家里的pc或他的便携机来访问邮件。下载并删除方式将对bob的邮件报文根据这3台机器进行划分,特别是如果bob最先是在他办公室的pc上收取了一条邮件,那么晚上当他在家里时,通过他的便携机将不能再收取该邮件。使用下载并保留方式,用户代理下载某邮件后,该邮件仍保留在邮件服务器上。这时,bob就能通过不同的机器重新读取这些邮件;他能在工作时收取一封报文,而在工作回家后再次访问它。

在用户代理与邮件服务器之间的pop3会话期间,该pop3服务器保留了一些状态信息;特别是记录了哪些用户报文被标记为删除了。然而,pop3服务器并不在pop3会话过程中携带状态信息。会话中不包括状态信息大大简化了pop3服务的实现。

2.imap

使用pop3访问时,一旦bob将邮件下载到本地主机后,他就能建立邮件文件夹,并将下载的邮件放入该文件夹中。然后bob可以删除报文,在文件夹之间移动报文,并查询报文(通过发送方的名字或报文主题)。但是这种文件夹和报文存放在本地主机上的方式,会给移动用户带来问题,因为他更喜欢使用一个在远程服务器上的层次文件夹,这样他可以从任何一台机器上对所有报文进行访问。pop3不可能做到这一点,pop3协议没有给用户提供任何创建远程文件夹并为报文指派文件夹的方法。

为了解决这个或其他一些问题,由rfc 3501定义的因特网邮件访问协议(imap)应运而生。和pop3一样,imap是一个邮件访问协议,但是它比pop3具有更多的特色,不过也比pop3复杂得多。(因此客户和服务器端的实现也都复杂得多。)

imap服务器把每个报文与一个文件夹联系起来;当报文第一次到达服务器时,它与收件人的inbox文件夹相关联。收件人则能够把邮件移到一个新的、用户创建的文件夹中,阅读邮件,删除邮件等。imap协议为用户提供了创建文件夹以及将邮件从一个文件夹移动到另一个文件夹的命令。imap还为用户提供了在远程文件夹中查询邮件的命令,按指定条件去查询匹配的邮件。值得注意的是,与pop3不同,imap服务器维护了imap会话的用户状态信息,例如,文件夹的名字以及哪些报文与哪些文件夹相关联。

imap的另一个重要特性是它具有允许用户代理获取报文组件的命令。例如,一个用户代理可以只读取一个报文的报文首部,或只是一个多部分mime报文的一部分。当用户代理和其邮件服务器之间使用低带宽连接的时候,这个特性非常有用(如一个低速调制解调器链路)。使用这种低带宽连接时,用户可能并不想取回他邮箱中的所有邮件,尤其要避免可能包含如音频或视频片断的大邮件。

3.基于web的电子邮件

今天越来越多的用户使用他们的web浏览器收发电子邮件。20世纪90年代中期hotmail引入了基于web的接入。今天,谷歌、雅虎以及几乎所有重要的大学或者公司也提供了基于web的电子邮件。使用这种服务,用户代理就是普通的浏览器,用户和他远程邮箱之间的通信则通过http进行。当一个收件人(如bob),想从他的邮箱中访问一个报文时,该电子邮件报文从bob的邮件服务器发送到他的浏览器,使用的是http而不是pop3或者imap协议。当发件人(如alice)要发送一封电子邮件报文时,该电子邮件报文从alice的浏览器发送到她的邮件服务器,使用的是http而不是smtp。然而,alice的邮件服务器在与其他的邮件服务器之间发送和接收邮件时,仍然使用的是smtp。

继续阅读