用 PHP 发送 MIME 邮件(一）
已经厌倦了给你的朋友和客户发送那些单调乏味的文本通知和信件了吗？曾经考虑过发送附件或在邮中嵌入 HTML 吧。

答案就是 MIME。接下来的几页解释了 MIME 的基础知识，创建符合 MIME 的信息，然后用一个可以工作的 PHP 类结束，这个类实现了发送符合 MIME 邮件。注意对调用脚本，调用者等等的引用表示使用了将要开发的类的脚本，客户程序/MUA 等等表示邮件阅读的客户程序或邮件使用代理程序。

一些 MIME 基础
MIME 表示多用途 Internet 邮件扩允协议。MIME 扩允了基本的面向文本的 Internet 邮件系统，以便可以在消息中包含二进制附件。

MIME 利用了一个事实就是，RFC 822 在消息体的内容中做了一点限制：唯一的限制就是只能使用简单的 ASCII 文本。所以，MIME 信息由正常的 Internet 文本邮件组成，文本邮件拥有一些特别的符合 RFC 822 的信息头和格式化过的信息体（用 ASCII 的子集来表示的附件）。这些 MIME 头给出了一种在邮件中表示附件的特别的方法。

MIME 信息的剖析
一个普通的文本邮件的信息包含一个头部分（To: From: Subject: 等等）和一个体部分（Hello Mr., 等等）。在一个符合 MIME 的信息中，也包含一个信息头并不奇怪，邮件的各个部分叫做 MIME 段，每段前也缀以一个特别的头。MIME 邮件只是基于 RFC 822 邮件的一个扩展。然而它有着自已的 RFC 规范集。

头字段
MIME 头根据在邮件包中的位置，大体上分为 MIME 信息头和 MIME 段头。（译者：MIME 信息头指整个邮件的头，而 MIME 段头只每个 MIME 段的头。）

MIME 信息头有：

MIME-Version:
这个头提供了所用 MIME 的版本号。这个值习惯上为 1.0。
Content-Type:
它定义了数据的类型，以便数据能被适当的处理。有效的类型有：text，image，audio，video，applications，multipart 和 message。注意任何一个二进制附件都应该被叫做 application/octet- stream。这个头的一些用例为：image/jpg, application/mswork，multipart/mixed，这只是很少的一部分。
Content-Transfer-Encoding:
这是所有头中最重要的一个，因为它说明了对数据所执行的编码方式，客户/MUA 将用它对附件进行解码。对于每个附件，可以使用 7bit，8bit，binary ，quoted-printable，base64 和 custom 中的一种编码方式。7bit 编码是用在 US ASCII 字符集上的常用的一种编码方式，也就是，保持它的原样。8bit 和 binary 编码一般不用。对人类可读的标准文本，如果传输要经过对格式有影响的网关时对其进行保护，可以使用 quoted printable 。Base64 是一种通用方法，在需要决定使用哪一种编码方法时，它提供了一个不用费脑子的选择；它通常用在二进制，非文本数据上。注意，任何非 7bit 数据必须用一种模式
编码，这样它就可以通过 Internet 邮件网关！
Content-ID:
如果 Content-Type 是 message/external-body 或 multipart/alternative 时，这个头就有用了。它超出了本文的范围。
Content-Description:
这是一个可选的头。它是任何信息段内容的自由文本描述。描述必须使用 us-ascii 码。
Content-Disposition:
一个试验性的头，它用于给客户程序/MUA 提供提示，来决定是否在行内显示附件或作为单独的附件。
MIME 段头（出现在实际的 MIME 附件部分的头），除了 MIME-Version 头，可以拥有以上任何头字段。如果一个 MIME 头是信息块的一部分，它将作用于整个信息体。例如，如果 Content-Transfer-Encoding 显示在信息（指整个信息）头中，它应用于整个信息体，但是如果它显示在一个 MIME 段里，它"只能"用于那个段中。

"好，如何创建符合 MIME 的信息呢？"
通过上面的一般性的描述，让我们现在看一下所谓的 MIME 信息到底是什么！

最简单的 MIME 信息
这个信息没有任何段，也就是，没有附件。然而，因为它是一个 MIME 消息，它必须有必要的头。

From: php@php.net
To: 'Alex (the Great)' <alex@greece.net>
Subject: Bucephalus
MIME-Version: 1.0

Hello Alexander,

How's Bucephalus doing?

这里面没有什么，它只是一个简单的拥有 MIME 头的符合 RFC-822 的信息（文本邮件）。注意，如果没有指定 Content-Type 头，则假设为 Content-Type: text/plain;charset='us-ascii'!当然，它有些简单，复杂一些的如下：

From: 'Alex (the Great)' <alex@greece.net>
To: php@php.net
Subject: re: Bucephalus
MIME-Version: 1.0
Content-Type: image/jpg;
name='buce.jpg'
Content-Transfer-Encoding: base64
Content-Description: Take a look at him yourself

<.....base64 encoded jpg image of Bucephalus...>

"嗨，但是我想发送一个 word 文档和一张我的小狗的图片在同一封邮件中... ！"一个用户说！如果是真的，上面的那个例子就太简单了，并且它没有足够的内容来支持爱好者和现代邮件处理方面的需要。实际上，许多的邮件客户端软件甚至不能显示描述字段！

这就是我们所面临的"多部分信息"。

多部分信息（Multipart Messages）
这个概念允许在一封邮件中发送多条项目。例如，假设 Alexander 想要给 php@php.net 发送一封他的马的照片的邮件，同时还附带有马的家族图谱及精彩的说明！这样一个简单的要求没有多部分消息的概念是无法被满足的。在这种情况下，我们创建了一个使用 Content-Type 的信息头的封装来支持邮件的不同部分，以便收信人得到图片，家族图谱和精彩的说明！

Content-Type 头现在拥有一个"multipart"的值，它表示这是一个完整的邮件信息并且这个头只封装了信息。而且它还有一个"mixed"的子类型（毕竟图片，家族图谱和 7bit 文本信息是不同的类型，对吗？）。

让我们看一下整个图片看上去象：

From: 'Alex (the Great)' <alex@greece.net>
To: php@php.net
Subject: re: Bucephalus
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="XX-1234DED00099A";
Content-Transfer-Encoding: 7bit

This is a MIME Encoded Message

--XX-1234DED00099A
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi PHP,

Attached you will find my horse, Bucephalus', pedigree chart and photo.

Alex

--XX-1234DED00099A
Content-Type: image/jpg;
name="buce.jpg";
Content-Transfer-Encoding: base64
Content-Description: "A photo of Bucephalus"

<.....base64 encoded jpg image of Bucephalus...>

--XX-1234DED00099A
Content-Type: application/octet-stream;
name="pedigree.doc"
Content-Transfer-Encoding: base64
Content-Description: "Pedigree Chart of the great horse"

<.....base64 encoded doc (pedigree.doc) of Bucephalus...>

--XX-1234DED00099A--

哟，看上去很复杂，不是吗？不管怎样，让我们浏览一遍细节吧：

如果你注意到了在 MIME 信息头中的 Content-Transfer-Encoding，为"7bit"。因为 Content-Type 为 multipart/mixed，编码应该是 7bit，8bit 或二进制中的一种，7bit 是一种广泛使用的格式。象这样一条信息包含了多种信息。客户程序是如何知道 JPG 图片，文档和普通文本之间的区别呢？你会注意到在 Content-Type 后面有一个 boundary="XX-1234DED00099A"参数。这个值用来分离邮件中的不同部分。它叫做 MIME 边界标记。边界标记的值必须尽可能的唯一，以免在超出邮件范围时发生混乱。"警告"信息（译者：指"This is a MIME Encoded Message"）在那里是为了让不符合 MIME 的客户程序能够把它显示给用户，否则他们就不理解一个空白邮件是什么意思。现在，回到边界标记。如果你观察这个简单的邮件，会发现边界标记（XX-1234DED00099A 在每一个分都出现了，也就是，在每部分之间都使用了一个边界标记，然而，每个边界标记都以两个连接符开始。很重要的一点需要注意的就是在最后一个 MIME 段的后面，边界标记不仅仅以那两个边接符作为开始，同时也以它俩作为结束。这一点一定不能忘记，因为它定义了邮件的范围。
让我们看一下前两个 MIME 段：
第一段是普通文本信息，因此 Content-Type 为 text/plain，并且编码为 7bit（我们也可以省略它，因为如果不指明它也会默认为如此）。第二个就是 JPEG 图片。相应的表示为 Content-Type: image/jpg。name="buce.jpg"（出现在 Content-Type 的后面，称之为参数），指出了文件的名字；它就是可以在客户程序中看到的附件的名字。如果不给出 name="buce.jpg" ，描述字段（如果给出）将作为附件的名字显示出来（然而，在所有客户程序中它不是统一的做法）。
注意 JPEG 图片可以在邮件件中被显示出来，如果客户程序可以显示行内附件。或者，你可以向客户程指明你想如何显示附件。例如，如果存在 Content-Disposition: attachment 头，JPEG 图片将被显示为一个附件图标。