RFC 2045:MIME 第一部分 — 互联网信件体格式
存在的原因
RFC 5322(及其前身RFC 822)将电子邮件定义为纯US-ASCII文本,最大行长度为998个字符。这在1982年还可以,但对于现代电子邮件来说已不适用,现代电子邮件需要支持:
- 非ASCII字符集文本(UTF-8、ISO-8859-*等)
- 带内联样式和图像的HTML内容
- 文件附件(PDF、图像、压缩包)
- 多个正文部分(一条消息中包含文本+HTML+附件)
MIME(多用途互联网邮件扩展)是由五份RFC组成的套件,它扩展了电子邮件的功能以支持所有这些内容,同时保持与原始纯ASCII基础设施的向后兼容性。RFC 2045是第1部分:它定义了使其他一切成为可能的头字段和编码机制。
工作原理
RFC 2045引入了三个关键头字段和两种编码方案。
MIME-Version头
每条MIME消息必须包含:
MIME-Version: 1.0
这向接收邮件客户端表明该消息使用MIME约定。没有此头字段,该消息将按照RFC 5322作为纯US-ASCII文本处理。该版本自1996年以来一直是1.0,从未改变。
Content-Type头
声明正文的媒体类型和子类型,以及可选参数:
Content-Type: type/subtype; parameter=value
示例:
; 纯文本电子邮件(UTF-8) Content-Type: text/plain; charset=utf-8 ; HTML电子邮件 Content-Type: text/html; charset=utf-8 ; PDF附件 Content-Type: application/pdf; name="invoice.pdf" ; 多部分消息(文本+HTML+附件) Content-Type: multipart/mixed; boundary="----=_Part_123"
如果不存在Content-Type,默认值为text/plain; charset=us-ascii——保持与前MIME消息的向后兼容性。
Content-Transfer-Encoding头
SMTP被设计用来传送7位ASCII文本,行长度不超过998个字符。二进制数据(图像、PDF)和8位文本(UTF-8)必须编码才能符合这些限制。RFC 2045定义了五种传输编码:
| 编码 | 用途 | 开销 |
|---|---|---|
7bit |
US-ASCII文本(默认)。无需编码。 | 无 |
8bit |
8位文本(如UTF-8)。需要8BITMIME SMTP扩展。 | 无 |
binary |
任意二进制数据。需要BINARYMIME SMTP扩展。 | 无 |
quoted-printable |
主要是ASCII文本,包含一些非ASCII字符。 | 约5-10% |
base64 |
二进制数据(图像、文件)或大量非ASCII文本。 | 约33% |
Quoted-Printable编码
为主要是ASCII但偶尔包含非ASCII字符的文本设计。每个非ASCII字节编码为=XX,其中XX是十六进制值。超过76个字符的行用末尾的=进行软换行。
; 原始文本:"René sent the café menu" Content-Transfer-Encoding: quoted-printable Ren=C3=A9 sent the caf=C3=A9 menu
=C3=A9是é(U+00E9)的UTF-8编码,每个字节都进行了十六进制编码。
Base64编码
将任意二进制数据编码为ASCII字符(A-Z、a-z、0-9、+、/)。每3个输入字节变成4个ASCII字符。行在76个字符处换行。
Content-Type: image/png; name="logo.png" Content-Transfer-Encoding: base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34 AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB zN+OGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBl
关键技术细节
Content-Disposition头
虽然不是RFC 2045本身的一部分(来自RFC 2183),Content-Disposition与MIME密切相关,且普遍使用:
; 内联显示(例如嵌入图像) Content-Disposition: inline ; 作为可下载附件提供 Content-Disposition: attachment; filename="report.pdf"
完整的MIME消息
综合一切——一条具有文本和HTML正文以及附件的消息:
MIME-Version: 1.0 From: sender@example.com To: recipient@example.com Subject: Invoice attached Content-Type: multipart/mixed; boundary="----=_outer" ------=_outer Content-Type: multipart/alternative; boundary="----=_inner" ------=_inner Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Please find your invoice attached. ------=_inner Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable <p>Please find your invoice attached.</p> ------=_inner-- ------=_outer Content-Type: application/pdf; name="invoice.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="invoice.pdf" JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PCAvVHlwZSAv Q2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCg== ------=_outer--
注意结构:multipart/mixed包含正文和附件。正文本身是multipart/alternative,包含文本和HTML版本。详见RFC 2046了解多部分类型的完整细节。
Charset参数
text/*类型上的charset参数声明字符编码。对于现代电子邮件,始终使用utf-8:
Content-Type: text/plain; charset=utf-8 Content-Type: text/html; charset=utf-8
iso-8859-1、windows-1252和shift_jis等旧字符集仍然存在,但不应在新消息中使用。
常见错误
-
缺少
MIME-Version: 1.0。没有此头字段,某些邮件客户端会忽略Content-Type,将正文作为纯ASCII文本处理。你的HTML电子邮件将显示为原始源代码。 -
二进制数据使用错误的Content-Transfer-Encoding。使用
7bit编码发送二进制附件会破坏它——空字节和高位字符会被破坏。二进制内容始终使用base64。 -
缺少或错误的
charset参数。省略charset会默认为us-ascii。如果文本包含UTF-8字符,它们将显示为乱码。始终声明charset=utf-8。 - 行超过998个字符。RFC 5322规定最大行限制为998个字符。Base64在76个字符处换行。Quoted-printable使用软换行符。原始8bit文本也必须遵守此限制,否则中间服务器可能会截断或拒绝消息。
-
不检查服务器支持就使用
8bit。8bit编码要求接收服务器在其EHLO响应中通告8BITMIME。如果它不这样做,请使用quoted-printable或base64。 - 边界字符串出现在正文内容中。多部分边界不得出现在任何正文部分中。使用长的随机边界字符串以避免冲突。
可投递性影响
- 正确的MIME结构是不可协商的。格式错误的MIME会触发垃圾邮件过滤器。缺少MIME-Version、不正确的边界或错误的编码都是垃圾邮件过滤器寻找的危险信号。
-
始终发送multipart/alternative。包含
text/plain和text/html部分。仅包含HTML的消息会被许多垃圾邮件过滤器惩罚。文本部分还充当纯文本客户端的备选方案。 - 为附件使用base64,为文本使用quoted-printable。这是通用兼容的组合。它适用于所有SMTP服务器和邮件客户端。
- 保持附件大小合理。Base64编码增加33%的开销。7.5 MB的文件变成10 MB的电子邮件。许多服务器拒绝超过25 MB的消息。有些超过10 MB。
-
字符集正确性防止呈现错误。声明
charset=utf-8并实际用UTF-8编码确保你的电子邮件在全球范围内正确呈现。不匹配的字符集声明会导致乱码和支持投诉。