邮件格式说明
Mutiple Internet Mail Extensions
Refer to Internet Official Protocol Standards RFC 822
1 概述
网络间传递的电子邮件需要公共认同的格式,以便于客户端邮箱软件识别拆解其间的信息。邮件本身是由 ASCII 字符构成,总体上分为邮件头邮件体两部分,其间允许字符编码、附件、压缩等等多样化的格式。本文档参考网络官方协议标准中 , 请求批注的邮件相关条款,总结了邮件结构及其各部分的格式说明,给出部分字符编码的相关解释。
RFC( Require for comment ) 是 Internet Official Protocol Standards 标准所提供的网络协议标准系列。
2 主体结构
邮件结构包括邮件头、邮件体(可无),邮件体实际上是一行行的 ASCII 字符构成的简单序列,它和邮件头是靠一个空行(该行只有一个回车换行符 CRLF )来区分开的。
2.1 邮件头
1) 长字段的断行
邮件头由许多头字段 (header fields) 组成,这些字段包括字段名 (field name) 和字段值 (field body) ;字段值 (field body) 可以分割成多行表述,叫做“可折叠”。
断行的规则是:在一行的线性空格处,可用 CRLF (回车换行)之后至少跟一个 LWSP-char( 空格或 TAB) ,把原来的单行变为多行表示。
RFC 协议中推荐尽量把折叠的断行放置在特定的空格分隔处,比如,地址字段里的多个邮件地址,折叠时尽量在各地址之间,及逗号之后断行。
2) 字段主要结构
包括字段名 (Field name) ,冒号 (colon) ,字段值 (Field body) ,结束符( CRLF );
有些字段属于结构化字段,比如日期 (Date) ,邮件地址 (Address) ,有着特定的表示格式,用于系统识别。而其他字段比如 ”Subject” “Comments” 都被当作简单的字符串处理。
字段表示:
field-name ":" [ field-body ] CRLF
字段值 (Field body) 可断行(见 1 )),内容全部都是 ASCII 码,元素包括句号,引用字符串,特殊 token ,或一般文本。字段的含义参见后文附录。
3) 邮件头构造协议
邮件头字段不是必须按照特定的顺序安排,仅仅是注意要把邮件体放在邮件头之后。邮件协议中推荐的做法是在放置邮件字段时,邮件按照以下顺序安排: ”Return-Path”, “Received”, “Date”, “From”, “Subject”, “Sender”, “To”, “cc”, 等等。
邮件协议中规定邮件由字段和邮件体正文组成,两部分之间由一个空行(该行只有包含 CRLF )分隔,也就是说,在遇见的第一个空行之后所有的内容都被当作邮件体。
Ø 转发 -Forwarding
一些系统允许接受者转发信息,保留原有的邮件头,仅添加些新的字段,这些字段以 ”Resent-” 为前缀。及前缀 ”Resent-” 的字段表示接受者转发的原信息。
Ø 路径字段 -Trace Field
路径信息用来追踪信息的发送者, ”via” “with” 等是记录变量。
“Return-Path” : 该字段由信息的最后发送者添加 , 是关于信息原始来源的地址和回朔路径。 Reply-To 字段是有信息源添加用来直接回复(地址?),而 Return-Path 是一个到信息原始来源的回朔路径。
“Received” : 由每个中继服务站添加,用于帮助追踪传输中出现的错误。字段内容包括,发送、接收的主机和接收时间。参数 via 用于记录信息发送后经过的物理站点, ”with” 指示了使用的邮件、连接的协议。参数 id 用于标识邮件。参数 for 用于记录发送者的分发的目的地址。
Ø 信息源的字段 -Originator Field
“From/Resent-From” : 与 sender 必须至少存在一个。
“Sender/Resent-Sender”
“Reply-To/Resent-Reply-To”
当自动生成回复信息的地址列表时,应当注意:如果没有 ”Sender” ,将会使用 ”From” . 接收者在回复信息时,邮件 sender 中的信息不会被自动使用。如果 ”Reply-To” 字段存在,将使用该字段信息,而不是 ”From” 字段。如果有 ”From” 而没有 ”Reply-To” ,将使用 ”From” 。
Ø 接收者字段 -Receiver Field
“To/Resent-To”
“Cc/Resent-Cc”
“Bcc/Resent-Bcc”
Ø 参考字段
“Message-ID/Resent-Message-ID”
“In-Reply-To”
“Reference”
“Keywords”
4) 重要参数字段
a) “MIME-Version” : 所使用的网络邮件格式标准版本
b) “Content-type”
邮件内容数据的类型,包括类型标识 (type) 和子类型标识 (subtype) ,前者类型标识 (type) 声明了数据的类型,后者子类型标识 (subtype) 为这种数据类型指定了特定的格式。
比如 content-type:image/xyz; 说明数据类型是图像型 (image) 的,图像数据格式是 xyz 。
类型标识 (type) 与子类型标识 (subtype) 由斜杠 ”/” 来分割。
类型之后是参数集合 parameter 。
邮件的数据类型分为七种,分别是 : 文本 (Text) 、多文档 (mulipart) 、消息 (Message) 、图像 (Image) 、音频 (audio) 、视频 (Video) 、应用 (Application) 。
文本 (Text)— 文字类信息,其基本的子类标识是 ”Plain” ,即没有格式的文本。 除了需要支持指定的字符集,获得文本信息不需要特殊的软件。 文本子类用于多信息文本,在其上应用文字处理软件可以美化文本的外观,但文本的内容及涵义无需任何软件。因此子类型包括任何可读得文字处理格式。
多文档 (mulipart) — 包含具有独立数据类型的多个部分。 其中定义了 4 个最原始的子类型: mixed( 基本类型 ), alternative( 具有可供选择的多个格式 ), parallel( 同时阅览的部分 ), digest( 都是消息型的多部内容 ).
消息 (Message) – 未封装的消息。该类型的消息体本身部分或全部都是 RFC822 格式。基本子类是 ” rfc822” 。 ”partial” 表示局部消息,允许邮件传输中可分块进行。 ”External-body” 表示扩展大邮件。
图形 (Image) – 需要有现实设备。子类主要是两种应用广泛的图形格式: jpeg, gif 。
声频 (audio) – 基本子类 ”basic”, 需要声频输出设备。
视频 (Video) – 基本子雷 ”mpeg”, 需要视频显示设备。
应用 (Application) – 其他类型数据,无法解析的二进制数据。基本子类 ”octet-stream” ,用于不可解析的二进制数据情况,为用户提供将信息写入文件的方法。 ”PostScript” 表示传输脚本文档。
Content-type 类型默认为 Content-type : text/plain; charset = us-ascii 。如果 content-type 没有明确制定,那么系统会默认为该类型。
当遇到未知的类型时,将会把未知类型当作 ”application/octet-stream” 对待。
c) Content-Transfer-Encoding 头字段
许多邮件内容是以最原始的格式传输的, 8 位字符或二进制数据,但对于有些协议这种格式数据就不能正确传输了。例如 RFC821 限制 messages 必须为 7 位 US-ASCII 数据,而且每行不能超过 1000 个字符。
因此,有必要定义机制来把数据编码成 7 位短行格式。编码的目的就是用网络可以传输的方式来表达邮件内容。
Content-Transfer-Encoding 实际上就是在类型数据的本地表述和用 7 位邮件传输协议转化的表述之间的一种映射,比如协议 RFC821(SMTP) 。该字段的值就是指定编码类型的一种标识。
其值如下:
“7bit”,”8bit”, “quoted-printable”, “base64”, “binary”, “x-token”
标识不区分大小写,如果没有明确指定,该字段的默认值是 ”7bit” 。
若值是 ”8bit”,”7bit” 或 ”binary” 时,表示没有做任何编码。(继续翻译)
2.2 Content-type 字段 Multipart 类型说明
所有带前缀 ”Content-” 的字段对正文都定义有含义,而其他得头字段一般都被邮件体部分忽略。
协议中指出,在 multipart 的情况下 , 即多个不同的数据集合合并在同一邮件体内,此时头字段中 ”multipart” 参数值必须存在。这时邮件体必定存在一个或多个子部分,每一个子部分都会由边界 (boundary) 封装 , 而且最后一个子部分后面必须跟一个结尾边界。每一部分都会由边界开始,然后包含着邮件子体的头信息( header ),空行,然后是邮件正文。
如果没有填写 content-type 的头字段,那就是暗示相应的邮件体时 US-ASCII 的普通 text/plain 文本。
Boundary 在作为边界值封装邮件时,其使用方法是值前加两个 ”-” 。在一些特殊情况下,这种用法也不一定适用。
封装部分的结尾, boundary 和前面的使用格式一样的情况下, 后面再加两个 ”-” 的形式表示。
Content-type 字段参数的语法是把 boundaries 的值包含在引号之中。也可以没有引号,但又引号是最保险的。有一些非法字符会出现在 boundary 值中,如果不加引号会引起错误。
注意封装边界必须在行的开始,后面是回车换行 CRLF, 开头的 CRLF 会被当作边界的一部分,而不是上一块内容的一部分。边界后面跟一个 CRLF 和下一部分的邮件头字段,或者,两个 CRLF ,这种情况下不会有细一部分的邮件头。
在边界之间(子部分头一个 boundary 和上一部分结尾 boundary 之间或者正文第一个边界之前邮件头之后),会有一些可添加额外信息的空白空间,这些空间邮件解析时会略过。
Multipart 子类型的简要介绍:
Mixed: 表示个子部间互相独立,需要以特定的顺序排列。
Alternative: 每一子部分的是相同信息的不同版本,各部分排序,最优的排在最后,但优先使用。
Digest: 将子部分默认成 message 来处理。
Parallel: 同时显示多个子部
2.3 Content-type 字段 Message 类型说明
在发送邮件时,该类型会频繁使用来封装子 mail 邮件。通常的子类型是 message/rfc822 ,该类型下没有必须添加的参数。额外的子类型 ”partial” 和 ”External-body ” , 需要必要的参数。
编码方面,该类型只允许 ”7bit” “8bit” 或 ”binary” 。 message 的头字段通常是 US_ASCII 的, message 体内可以按照其自身的 content-transfer-encoding 字段值进行编码。
1) message/rfc822
该类型是 rfc822 协议的 message 。但不必和最外层的 rfc822 message 那样有 from, subject, 以及目的字段。该类型可以由高版本的邮件替换,及兼容 MIME message 。
2) message/partial
有些邮件发送机构限制邮件发送的大小,这样,大的邮件对象( vedio 等)必须分成多部分发送。 “message/partial” 说明该邮件体包含了一个大邮件的一段。该类型需要 3 个参数:
Id, 尽可能保持唯一性,为了把各部组合到一起。
Number, 该部分在整体序列中的编号。
Total, 所分部分的总数,该参数一般在最后一部分出现。
发送大邮件诸如 vedio 文件时,由于文件太大,超出单次发送限制,需要把文件分割成多个部分。基本过程是,把 vedio 类型的 message, 分割成多个单独的 vedio 类型的 message, 每个部分再由 ”message/partial” 类型的 message 封装起来,并添加分段信息。
当接收方收到该 message 时,各段落会 ` 根据分割信息重新组合起来,新的信息仅是 vedio 类型,即去掉了外层的 ”message” 类型封装。
组合原则:
(1) 拷贝第一部分的外层 ” message/partial” 的头信息,除了 ”content-” , ”message-id” , ”Encrypted” , ”MIME-Version” ,其它为必拷贝信息
(2) 把内层的封装信息的 ”content-” , ”message-id” , “Encrypted” , “MIME-Version” 的头信息全部拷贝到新 message 中。
(3) 第二部分和以后部分的头信息全部忽略。
名词解释( Word Description )
RFC: Request For Common(Internet Official Protocol Standard)
CRLF:Carriage-return/Line-feed