我们简单地比较一下SMTP和HTTP。这两个协议都是用于从一台主机向另一台主机传送文件;HTTP用于从web服务器向Web用户代理(即浏览器)传送文件(或对象),SMTP用于从一个邮件服务器向另一个邮件服务器传送文件(也就是电子邮件消息)。在传送文件时,SMTP和持久HTTP都使用持久连接。可见,这两个协议具有一些共同的特征,不过它们之间的差别也是显著的。首先,HTTP基本上是一个内拉式协议(pull protocol)——有人把信息上传到web服务器中,用户则在方便的时候使用HTTP把这些信息从服务器上拉过来。更确切地说,TCP连接是由想要接收文件的主机发起的。SMIP则基本上是一个外推式协议(pushProtoco1)——发送端邮件服务器把文件推送给接收端邮件服务器。更确切地说,TCP连接是由想要发送文件的主机发起的。
SMTP和HTTP的第二个重要差别是,SMTP要求包括信体部分在内的每个邮件消息都是7位ASCII文本格式。另外,SMTP RFC还要求每个邮件消息的信体以仅由单个点号构成的一行结束,改用ASCII字符名称来说就是每个邮件消息的信体必须以“CRLF.CRLF“结尾,其中CR和LF分别代表回车符和换行符。这种方式下,当从同一个SMTP客户接收一系列邮件消息时,SMTP服务器可以通过在字节流中搜索“CRLF.CRLF”来分割每个消息。要是信体不是ASCII文本,而是二进制数据(譬如说一幅JPEG图像),那么这些二进制数据字节流中偶尔出现“CRLF.CRLF”这一模式是有可能的。这将导致SMTP服务器不正确地认定当前邮件消息已结束。为避免这样的问题,二进制数据应以一定的方式先编码成ASCII文本,保证其中不使用特定的ASCH字符(包括点号)。HTTP无论是持久的还是非持久的都不需要预先把二进制数据转换成ASCII本。对于持久的HTTP,每个TCP连接只传送一个对象:服务器关闭连接后,客户就知道己接收到一个完整的响应消息。对于非持久的HTTP,每个响应消息中包含一个Content-length:头部,使得客户能够确定每个响应消息的边界。
SMTP和HTTP的第三个重要差别涉及如何处理包含文本和图像或其他媒体类型的文档。HTTP是把每个对象封装在各自的HTTP响应消息中。SMTP(正如接下去要详细讨论的那样)是把同一个邮件内的各个对象置于同一个邮件消息中。
邮件消息格式和MIME
当Alice给Bob发一封普通的邮政信件时,她把这封信装入一个信封里,在信封上写明Bob的地址和自己的回信地址,然后投入邮箱;邮政业务在递送这封信的过程中,也会把表明时间和地点的邮戳盖在信封上。类似地,当电子邮件消息从一个人传送到另——个人时,在信体之前会有一个含有这些外围信息的信头。这些信息实际上由一系列在RFC 822中定义的邮件消息头部及其值构成。邮件消息中构成信头的各个头部和信体之间以一个空行(也就是CRLF)分割。RFC 822详细说明了各个邮件消息头部的格式和含义。与HTTP一样,邮件消息的每个头部都是直观可读的文本,由一个后跟冒号的关键字和相应的值构成。邮件消息的头部有些是必须的,有些则是司选的。每个信头必须有一个From:头部和一个To:头部.还可以有一个Subject:头部和其他头部。需注意的是,这些头部和先前讨论的SMTP命令不是一回事:SMTP命令是SMTP握手协议的一部分,邮件消息头部则属于邮件消息的一部分。
下面是一个典型的电子邮件信头:
From:alice@crepes.fr
To:bob@hamburger.edu
Subject:this is a test
信头之后空一行就是信体。整个消息以只含有一个点号的单独行结束。
非ASCII数据的MlME扩展
RFC 822中说明的邮件消息头部尽管足以满足发送普通ASCII文本邮件的要求,但是在多媒体消息(例如,包含图像、音频或视频数据的消息)的描述和非ASCII文本格式(例如,非英语国家使用的文字)的承载上,却显然不够。要发送非ASCII文本的邮件消息,必须由发送者的用户代理在其中增添额外的头部RFC 2045和RFC 2046定义了这些额外的头部,它们是对RFC 822的多用途因特网邮件扩展(Multipurpose Internet Mail Extensions,简称MIME)。
支持多媒体的两个关键MIME头部是Content-Type:和Content-Tansfer-Encoding:。Content-Type:头部允许接收用户代理对邮件消息采取合适的行动。例如,通过指出信体内容为一个JPG图像,接收用户代理可以把信仲定向到某个JNG解压缩例程。我们已经知道,为确保SMTP正常工作,非ASCII文本消息必须预先编码成ASCH文本格式。
Content-Tansfer-Encoding:头部用于告知接收用户代理信体已被编码咸ASCII格式,并指出具体编码方式。这样,当某个用户代理收到一个包含这两个头部的邮件消息时,它首先使用Content-Tansfer-Encoding:头部的值把信体转换成原始的非AscH文本形式,再使用Content-Type:头部的值确定自己应该对信体采取什么行动。
下面看一个具体的例子。假设Alice想给Bob发送一个JPEG图像,她为此调用自己的用户代理,给出Bob的电子邮件地址和邮件消息的主题,并把这个JPG图像插入这个邮件消息的信体中(这个图像有可能是作为该邮件消息的“附件”插入的,具体取决于Alice所用的用户代理)。Alice填写完邮件消息后让用户代理把它发送出去。Alice的用户代理生成一个大体如下的MIME消息:
From:alice@crepes.fr
To:bob@hamburger.edu
Subject:picture of mine
MIME-Version:1.0
Content-Transfer-Encoding:base64
Content-Type:image/jpeg
{...base64编码数据...)
{...base64编码数据...)
从中我们可以看到,alice的用户代理采用base64编码格式对这个JPEG图像进行编码i而base64是在MIME中标准化的用于转换成某种可接受的7位ASCII格式的编码技术之一[RFC 2045]。另一种流行的内容传送编码技术称为带转义的可打印(叫quoted-printable)编码格式,一般用于把普通的ASCII邮件消息转换成不带非期望字符串(例如由单个点号构成的行)的ASCII文本。
Bob阅读邮件时,其用户代理所操作的是同一个MIME消息。该用户代理看到值为base64的Content-Transfer-Encoding:头部后,知道该邮件消息中还有一个值为image/jpeg的Content-Type:头部,它告知Bob的用户代理应该对信体进行JPEG解压缩。该邮件消息中的MIME-Version:头部自然是在指示本消息所用的MIME版本。需注意的是,邮件消息的其余部分仍然遵循标准的RFC 922/SMTP格式。具体地说,在信头之后有一个空行,接着是信体:在信体结束处是一个仅由单个点号构成的行。
我们接下去深入讨论一下Content-Type;头部。该头部按照MIME规范[RFC 2046]有如下的格式;
Content-Type: type/subtype; parameters
其中parameters(以及其前面的分号)是可选的。通过在Content-Type:头部给出媒体类型名和子类型名,MIME消息信体中数据的性质得以说明。类型名和子类型名之后的其余部分是一组参数。总的说来,顶级类型名用于声明数据的一般类型,子类型名用于指明这类数据中的某种具体格式。参数是对于类型的修饰说明,具体取决于类型和子类型本身,基本上不影响内容性质的指定。MIME是按照可扩展这一目标仔细地设计的,并预期媒体类型/子类型以及它们的相关参数会随时间显著增长。为确保以有秩序的文档完备公开的方式开发这些类型/子类型,MIME建立了一套注册程式,把因特网已分配数值权威(Internet Asigned Numbers Authority,简称IANA)作为MIME各个可扩展域的中心注册处。BFC 2048具体说明了这些可扩展域的注册程式。
当前已定义的MIME顶级类型共有7个,每个类型关联一组子类型,其数量在逐年增长。下面是其中的5个类型;
●text;text类型用于向接收者的用户代理指出消息体为文本。该类型极为普遍的一个类型/子类型对为text/plain。子类型plain指定不含任何格式定义信息的普通文本。plain文本应该不加任何解释地按照原样显示,不需要特殊的软件,能支持给定的字符集就行。在实际的邮件消息中经常能看到值为比text/plain;charset=gb2312或text/plain;charset="ISO—8859—1"的Content-Type:头部,其中的参数指出用于产生相应消息的字符集。另一个变得越来越普遍的类型/子类型对是text/html。子类型html指示接收用户代理解释嵌埋在消息体中的html标记,从而像Web页面那样显示信件内容,其中有可能包含各种字体的文本、超链接、Java小应用程序,等等。
●image:image类型用于向接收用户代理指出消息体为图像。该类型较为流行的两个类型/子类型对为iamge/gif和image/jpeg,接收用户代理碰到这样的类型时,就知道该把消息体作为GIF图像或JPEG图像解码并显示。
●audio:audio类型需要音频输出设备(例如扬声器或电话)来表达内容。这类型中常见的已标准化子类型包括basic(基本8位u-law编码)和32kadpcm(RFC 1911中定义的一种32Kbps格式)。
●video:video类型的子类型包括mpeg和quicktime。
●application:application类型适用于不适合归为其他类别的数据,通常用在必须由某个应用程序预先处理才能为用户所见或所用的数据上。例如.当用户在某个电子邮件消息中附带一个微软word文档时,其用户代理一般把它的类型子类型对指定为application/msword;这将导致接收用户代理启动微软word应用程序,并把该MIME消息的信体传递给它处理。这类型极为重要的一个子类型是octet-stream,它用于指示信体含有任意的二进制数据。收到内容类型为application/octet-stream的邮件消息后,接收用户代理会提示用户是否把信体保存到硬盘中,以便稍后处理。