一、MIME: Multipurpose Internet Mail Extensions
英國帝國大學計算機在線字典FOLDOC對MIME的解釋為:“多部分(multi-part)、多媒體電子郵件和WWW超文本的一種編碼標准,用於傳送諸如圖形、聲音和傳真等非文本數據。MIME定義於RFC1341,用MIMENCODE的方法將二進制數據轉換成為一種被稱為BASE64的ASCII子集的字符的組合。”
Internet上有專門討論MIME的新聞組: comp.mail.mime。該新聞組的FAQ可以從下面的網點獲得:
http://www.cis.ohio-state.edu/hypertext/faq/usenet/mail/mime-faq/mime0/faq.html
MIMENCODE最早稱為MMENCODE,提出用MIMENCODE代替UUENCODE,是因為UUENCODE使用了一些字符在一些郵件網關(特別是那些轉換ASCII和EBCDIC碼的網關)中造成傳輸障礙,(還有一些軟件不能對所有 UUENCODE 的算法進行正確解碼而導致郵件的閱讀困難),因此 MIME 被設計用於替代UUENCODE,但是結果是這些協議共存。
在MIME出台之前,使用RFC 822只能發送基本的ASCII碼文本信息,郵件內容如果要包括二進制文件、聲音和動畫等,實現起來非常困難。
MIME提供了一種可以在郵件中附加多種不同編碼文件的方法,彌補了原來的信息格式的不足。實際上不僅僅是郵件編碼,現在MIME經成為HTTP協議標准的一個部分。
二、MIME編碼方式簡介
對郵件進行編碼最初的原因是因為 Internet 上的很多網關不能正確傳輸8bit內碼的字符,比如漢字等。編碼的原理就是把8bit的內容轉換成7bit的形式以能正確傳輸,在接收方收到之後,再將其還原成8bit的內容。
在MIME協議之前,郵件的編碼曾經有過UUENCODE等編碼方式 ,但是由於MIME協議算法簡單,並且易於擴展,現在已經成為郵件編碼方式的主流,不僅是用來傳輸8bit的字符,也可以用來傳送二進制的文件,如郵件附件中的圖像、音頻等信息,而且擴展了很多基於MIME 的應用。從編碼方式來說,MIME定義了兩種編碼方法Base64與QP(Quote-Printable)。
1.Base64編碼
Base64是一種通用的方法,其原理很簡單,就是把三個Byte的數據用4個Byte表示。在這四個Byte中,實際用到的都只有前面6bit,這樣就不存在只能傳輸7bit的字符的問題了。Base64的縮寫一般是“B”。
Base64將輸入的字符串或一段數據編碼成只含有{'A'-'Z', 'a'-'z', '0'-'9', '+', '/'}這64個字符的串,'='用於填充。
其編碼的方法是,將輸入數據流每次取6bit,用此6bit的值(0-63)作為索引去查表,輸出相應字符。
這樣,每3個字節將編碼為4個字符(3×8 → 4×6);不滿4個字符的以'='填充。
有的場合,以“=?charset?B?xxxxxxxx?=”表示xxxxxxxx是Base64編碼,且原文的字符集是charset。在段體內則直接編碼,適當時機換行,MIME建議每行最多76個字符。
Base64的算法很簡單,它將字符流順序放入一個24位的緩沖區,缺字符的地方補零。
然後將緩沖區截斷成為4個部分,高位在先,每個部分6位,用64個字符重新表示。如果輸入只有一個或兩個字節,那麼輸出將用等號“=”補足。這可以隔斷附加的信息造成編碼的混亂。
如何進行base64編碼
Base64 使用US-ASCII子集的65個字符, 每個字符用6位表示
對於文本串,編碼過程如下。例如"men":
先轉成US-ASCII值.
"m"十進制 109
"e"十進制 101
"n"十進制 110
二進制 :
m 01101101
e 01100101
n 01101110
三個8位連起來是24位
011011010110010101101110
然後分成4個6位
011011 010110 010101 101110
現在得到4個值,十進制為
27 22 21 46
對應的 Base64 字符是 : b W V u
編碼總是基於3個字符,從而產生4個Base64字符。
如果只是2個字符的數據,使用特殊字符"="補齊Base64的4字。
如,編碼"me"
01101101 01100101
0110110101100101
011011 010110 0101
111111 (與,補足6位)
011011 010110 010100
b W U
b W U = ("=" 補足4字符)
於是 "bWU=" 就是"me"的Base64值.
如果只是2個字符的數據,如編碼 "m"
01101101
011011 01
111111
011011 010000
b Q = =
於是 "bQ==" 就是"m"的Base64值.
2.QP編碼
另一種方法是QP(Quote-Printable) 方法,通常縮寫為“Q”方法,其原理是把一個8bit的字符用兩個16進制數值表示,然後在前面加“=”。所以我們看到經過QP編碼後的文件通常是這個樣子:=B3=C2=BF=A1=C7=E5=A3= AC=C4=FA=BA=C3=A3=A1。
Quoted -printable根據輸入的字符串或字節范圍進行編碼,若是不需編碼的字符,直接輸出。若需要編碼,則先輸出'=',後面跟著以2個字符表示的十六進制字節值。有的場合,以“=?charset?Q?xxxxxxxx?=”表示xxxxxxxx是Quoted-printable編碼,且原文的字符集是charset。在段體內則直接編碼,適當時機換行,換行前額外輸出一個'='。
三、MIME的頭信息
郵件頭
在郵件頭中,有很多從RFC 822沿用的域名,MIME也增加了一些。常見的標准域名和含義如下:
域名 含義 添加者
Received 傳輸路徑 各級郵件服務器
Return-Path 回復地址 目標郵件服務器
Delivered-To 發送地址 目標郵件服務器
Reply-To 回復地址 郵件的創建者
From 發件人地址 郵件的創建者
To 收件人地址 郵件的創建者
Cc 抄送地址 郵件的創建者
Bcc 暗送地址 郵件的創建者
Date 日期和時間 郵件的創建者
Subject 主題 郵件的創建者
Message-ID 消息ID 郵件的創建者
MIME-Version MIME版本 郵件的創建者
Content-Type 內容的類型 郵件的創建者
Content-Transfer-Encoding 內容的傳輸編碼方式 郵件的創建者
非標准的、自定義域名都以X-開頭,例如X-Mailer, X-MSMail-Priority等,通常在接收和發送郵件的是同一程序時才能理解它們的意義。
段頭
在段頭中,大致有如下一些域:
域名 含義
Content-Type 段體的類型
Content-Transfer-Encoding 段體的傳輸編碼方式
Content-Disposition 段體的安排方式
Content-ID 段體的ID
Content-Location 段體的位置(路徑)
Content-Base 段體的基位置
有的域除了值之外,還帶有參數。值與參數、參數與參數之間以“;”分隔。參數名與參數值之間以“=”分隔。
1.MIME-Version
表示使用的MIME的版本號,一般是1.0;
如:
MIME-Version: 1.0
2.Content-Type
Content-Type定義了正文的類型,我們實際上是通過這個標識來知道正文內是什麼類型的文件。比如:text/plain 表示的是無格式的文本正文,text/html 表示的 Html 文檔,image/gif 表示的是 gif 格式的圖片等等。Content-Type都是“主類型/子類型”的形式。主類型有text, image, audio, video, application, multipart, message等,分別表示文本、圖片、音頻、視頻、應用、分段、消息等。每個主類型都可能有多個子類型,如text類型就包含plain, html, xml, css等子類型。以X-開頭的主類型和子類型,同樣表示自定義的類型,未向IANA正式注冊,但大多已經約定成俗了。如application/x-zip-compressed是ZIP文件類型。在Windows中,注冊表的“HKEY_CLASSES_ROOT\MIME\Database\Content Type”內列舉了除multipart之外大部分已知的Content-Type。
關於參數的形式,RFC裡有很多補充規定,有的允許帶幾個參數,較為常見的有:
主類型 參數名 含義
text charset 字符集
image name 名稱
application name 名稱
multipart boundary 邊界
multipart類型
郵件中常用到的復合類型:multipart。
multipart類型表示正文是由多個部分組成的,後面的子類型說明的是這些部分之間的關系。
郵件中用到的三個類型有:
(1).multipart/alternative:表示正文由兩個部分組成,可以選擇其中的任意一個。主要作用是在征文同時有text格式和html格式時,可以在兩個正文中選擇一個來顯示,支持 html 格式的郵件客戶端軟件一般會顯示其 HTML 正文,而不支持的則會顯示其Text正文;
(2).multipart/mixed:表示文檔的多個部分是混合的,指正文與附件的關系。如果郵件的MIME類型是multipart/mixed,即表示郵件帶有附件。
(3).multipart/related:表示文檔的多個部分是相關的,一般用來描述 Html 正文與其相關的圖片。
multipart類型,是MIME郵件的精髓。郵件體被分為多個段,每個段又包含段頭和段體兩部分,這兩部分之間也以空行分隔。它們之間的層次關系可歸納為下圖所示:
+------------------------- multipart/mixed ----------------------------+
| |
| +----------------- multipart/related ------------------+ |
| | | |
| | +----- multipart/alternative ------+ +----------+ | +------+ |
| | | | | 內嵌資源 | | | 附件 | |
| | | +------------+ +------------+ | +----------+ | +------+ |
| | | | 純文本正文 | | 超文本正文 | | | |
| | | +------------+ +------------+ | +----------+ | +------+ |
| | | | | 內嵌資源 | | | 附件 | |
| | +----------------------------------+ +----------+ | +------+ |
| | | |
| +------------------------------------------------------+ |
| |
+----------------------------------------------------------------------+
可以看出,如果在郵件中要添加附件,必須定義multipart/mixed段;如果存在內嵌資源,至少要定義multipart/related段;如果純文本與超文本共存,至少要定義multipart/alternative段。什麼是“至少”?舉個例子說,如果只有純文本與超文本正文,那麼在郵件頭中將類型擴大化,定義為multipart/related,甚至multipart/mixed,都是允許的。
multipart諸類型的共同特征是,在段頭指定“boundary”參數字符串,段體內的每個子段以此串定界。所有的子段都以“--”+boundary行開始,父段則以“--”+boundary+“--”行結束。段與段之間也以空行分隔。在郵件體是multipart類型的情況下,郵件體的開始部分(第一個“--” +boundary行之前)可以有一些附加的文本行,相當於注釋,解碼時應忽略。段間也可以有一些附加的文本行,不會顯示出來。
這些復合類型又是可以嵌套使用的,比如說一個帶有附件的郵件,同時有html與text兩種格式的正文,則郵件的結構是:
Content-Type: multipart/mixed
部分一:
Content Type : multipart/alternative:
Text 正文;
Html 格式的正文
部分二:
附件
郵件結束符;
由於復合類型由多個部分組成,因此,需要一個分隔符來分隔這多個部分,這就是上面的郵件源文件中的boundary所描述的,對於每一個Contect type :multipart/* 的內容,都會有這麼一個說明,表示多個部分之間的分隔。
含有 MIME/BASE64編碼的郵件,你查看它的源碼時一般都含有:“This is a multi-part message in MIME format.”這樣的句子。也可以被絕大多數的email程序進行解碼,包括Netscape、MS Mail、Eudora等。這些程序可以正確識別郵件的正文,恢 MIME/BASE64 編碼的部分為正確的文字或夾帶的二進制文件。
3.Content-Transfer-Encoding
它表示了這個部分文檔的編碼方式。只有識別了這個說明,才能用正確的解碼方式實現對其解碼。
Content-Transfer-Encoding共有Base64, Quoted-printable, 7bit, 8bit, Binary等幾種。
其中7bit是缺省的編碼方式。電子郵件源碼最初設計為全部是可打印的ASCII碼的形式。
非ASCII碼的文本或數據要編碼成要求的格式。
Base64, Quoted-Printable是在非英語國家使用最廣使的編碼方式。
Binary方式只具有象征意義,而沒有任何實用價值。
4.boundary
這個分隔符是正文中不可能出現的一串古字符的組合,在文檔中,以"--"加上這個boundary 來表示一個部分的開始,在文檔的結束,以"--"加boundary再在最後加上"--"來表示文檔的結束。由於復合類型是可以嵌套使用的,因此,郵件中可能會多個boundary。