JavaMail學習(一)理解郵件傳輸協議

 

電子郵件需要在郵件客戶端和郵件服務器之間,以及兩個郵件服務器之間進行傳遞,就必須遵循一定的規則,這些規則就是郵件傳輸協議。SMTP協議定了郵件客戶端與SMTP服務之間,以及兩臺SMTP服務器之間發送郵件的通信規則;POP3/IMAP協議定義了郵件客戶端與POP3服務器之間收發郵件的通信規則。


一、SMTP協議


        SMTP(Simple Mail Transfer Protocol,簡單郵件傳輸協議)定義了郵件客戶端與SMTP服務器之間,以及兩臺SMTP服務器之間發送郵件的通信規則 。SMTP協議屬於TCP/IP協議族,通信雙方採用一問一答的命令/響應形式進行對話,且定了對話的規則和所有命令/響應的語法格式。

    SMTP協議中一共定了18條命令,發送一封電子郵件的過程通常只需要其中的6條命令即可完成發送郵件的功能,下表按照發送命令的先後順序列出了這6條命令,並描述了其語法及功能說明,其中,<SP>代表空格,<CRLF>代表回車和換行。

 

SMTP命令格式 說明
ehlo<SP><domain><CRLF>        ehlo命令是SMTP郵件發送程序與SMTP郵件接收程序建立連接後必須發送的第一條SMTP命令,參數<domain>表示SMTP郵件發送者的主機名。
ehlo命令用於替代傳統SMTP協議中的helo命令。
auth<SP><para><CRLF>       如果SMTP郵件接收程序需要SMTP郵件發送程序進行認證時,它會向SMTP郵件發送程序提示它所採用的認證方式,SMTP郵件發送程序接着應該使用這個命令迴應SMTP郵件接收程序,參數<para>表示迴應的認證方式,通常是SMTP郵件接收程序先前提示的認證方式。
mail<SP>From:<reverse-path><CRLF>     此命令用於指定郵件發送者的郵箱地址,參數<reverse-path>表示發件人的郵箱地址
rcpt<SP>To:<forword-path><CRLF>      此命令用於指定郵件接收者的郵箱地址,參數<forward-path>表示接收者的郵箱地址。如果郵件要發送給多個接收者,那麼應使用多條rcpt<SP>To命令來分別指定每一個接收者的郵箱地址。
data<CRLF>      此命令用於表示SMTP郵件發送程序準備開始輸入郵件內容,在這個命令後面發送的所有數據都將被當做郵件內容,直至遇到“<CRLF>.<CRLF>"標誌符,則表示郵件內容結束。
quit<CRLF>     此命令表示要結束郵件發送過程,SMTP郵件接收程序接收到此命令後,將關閉與SMTP郵件發送程序的網絡連接。

其它SMTP命令的語法及功能描述可以參考RFC821RFC1869文檔。

    對於SMTP郵件發送程序發送的每一條命令,SMTP郵件接收程序都將回應一條響應信息。每條響應信息都以一個響應狀態開頭,如:250  OK。響應狀態用於表示SMTP服務器對請求命令的處理結果和狀態,它是一個三位的十進制數。響應狀態碼的最高位數字代表了不同的分類,當其爲 2 時表示命令執行成功;爲5時表示命令執行失敗;爲3時表示命令沒有完成。關於響應狀態碼所代表的具體含義,可以參考RFC821文檔。

    SMTP協議是一個基於TCP/IP的應用層協議,SMTP服務器默認的網絡監聽端口號爲25,下面將通過telnet程序,手工發送SMTP命令來發送一封電子郵件,從而理解SMTP協議的交互過程。

模擬環境說明:連接sina的SMTP服務器,給163的SMTP服務器發送一封郵件,操作過程如下圖所示:



說明:

1、連接SMTP服務器的用戶名和密碼需要經過base64編碼,下面是對用戶名和密碼進行base64編碼的JAVA程序:

  1. package org.yangxin.study.jm.util; 
  2.  
  3. import java.io.BufferedReader; 
  4. import java.io.IOException; 
  5. import java.io.InputStreamReader; 
  6.  
  7. import sun.misc.BASE64Encoder; 
  8.  
  9. public class Base64Util { 
  10.  
  11.     public static void main(String[] args) throws IOException { 
  12.         BASE64Encoder encoder = new BASE64Encoder(); 
  13.         System.out.println("請輸入用戶名:"); 
  14.         String username = new BufferedReader(new InputStreamReader(System.in)).readLine(); 
  15.         System.out.println(encoder.encode(username.getBytes())); 
  16.         System.out.println("請輸入密碼:"); 
  17.         String password = new BufferedReader( 
  18.                 new InputStreamReader(System.in)) 
  19.                 .readLine();         
  20.         System.out.println(encoder.encode(password.getBytes())); 
  21.     } 
package org.yangxin.study.jm.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import sun.misc.BASE64Encoder;

public class Base64Util {

	public static void main(String[] args) throws IOException {
		BASE64Encoder encoder = new BASE64Encoder();
		System.out.println("請輸入用戶名:");
		String username = new BufferedReader(new InputStreamReader(System.in)).readLine();
		System.out.println(encoder.encode(username.getBytes()));
		System.out.println("請輸入密碼:");
		String password = new BufferedReader(
				new InputStreamReader(System.in))
				.readLine();		
		System.out.println(encoder.encode(password.getBytes()));
	}
}


2、紅色箭頭指向的文字表示我在telnet程序中輸入的命令,以2、3、5數字開頭的行表示SMTP服務器對命令的響應。通過上表中的6個SMTP命令就完成了一封簡單電子郵件的發送。當然一封複雜的郵件不只包含這些信息,還應包括主題、發送日期、抄送和附件等消息頭。


二、POP3協議


        郵件服務提供商專門爲每個用戶申請的電子郵箱提供了專門的郵件存儲空間,SMTP服務器將接收到的電子郵件保存到相應用戶的電子郵箱中。用戶要從郵件服務提供商提供的電子郵箱中獲取自己的電子郵件,就需要通過郵件服務提供商的POP3郵件服務器來幫助完成。POP3(Post Office Protocol 郵局協議的第三版本)協議定義了郵件客戶端程序與POP3服務器進行通信的具體規則和細節。
    POP3協議在RFC 1939文檔中定義,它採用的網絡監聽端口號默認爲110。POP3協議共定義了 12 條POP3命令,郵件客戶端程序通過這些命令來檢索和獲取用戶電子郵箱中的郵件信息。下表列舉出了這12條POP3命令及其說明,其中,<SP>代表空格,<CRLF>代表回車和換行。
POP3命令格式 說明
user<SP>username<CRLF>      user 命令是POP3客戶端程序與POP3郵件服務器建立連接後通常發送的第一條命令,參數 username 表示收件人的帳戶名稱。
pass<SP>password<CRLF>       pass 命令是在user命令成功通過後,POP3客戶端程序接着發送的命令,它用於傳遞帳戶的密碼,參數 password 表示帳戶的密碼。
apop<SP>name,digest<CRLF>       apop 命令用於替代user和pass命令,它以MD5 數字摘要的形式向POP3郵件服務器提交帳戶密碼。
stat<CRLF>      stat 命令用於查詢郵箱中的統計信息,例如:郵箱中的郵件數量和郵件佔用的字節大小等。
uidl<SP>msg#<CRLF>      uidl 命令用於查詢某封郵件的唯一標誌符,參數msg#表示郵件的序號,是一個從1開始編號的數字。
list<SP>[MSG#]<CRLF>      list 命令用於列出郵箱中的郵件信息,參數 msg#是一個可選參數,表示郵件的序號。當不指定參數時,POP3服務器列出郵箱中所有的郵件信息;當指定參數msg#時,POP3服務器只返回序號對應的郵件信息。
retr<SP>msg#<CRLF>     retr 命令用於獲取某封郵件的內容,參數 msg#表示郵件的序號。
dele<SP>msg#<CRLF>     dele 命令用於在某封郵件上設置刪除標記,參數msg#表示郵件的序號。POP3服務器執行dele命令時,只是爲郵件設置了刪除標記,並沒有真正把郵件刪除掉,只有POP3客戶端發出quit命令後,POP3服務器纔會真正刪除所有設置了刪除標記的郵件。
rest<CRLF>     rest 命令用於清除所有郵件的刪除標記。
top<SP>msg#<SP>n<CRLF>     top 命令用於獲取某封郵件的郵件頭和郵件體中的前n行內容,參數msg#表示郵件的序號,參數n表示要返回郵件的前幾行內容。使用這條命令以提高 Web Mail系統(通過Web站點上收發郵件)中的郵件列表顯示的處理效率,因爲這種情況下不需要獲取每封郵件的完整內容,而是僅僅需要獲取每封郵件的郵件頭信息。
noop<CRLF>     noop 命令用於檢測POP3客戶端與POP3服務器的連接情況。
quit<CRLF>     quit 命令表示要結束郵件接收過程,POP3服務器接收到此命令後,將刪除所有設置了刪除標記的郵件,並關閉與POP3客戶端程序的網絡連接。

        對於POP3客戶程序發送的每一條POP3命令,POP3服務器都將回應一些響應信息。響應信息由一行或多行文本信息組成,其中的第一行始終以“+OK” 或 “-ERR” 開頭,它們分別表示當前命令執行成功或執行失敗。

下面通過telnet程序連接163的POP3服務器,來分析郵件的接收過程。操作步聚見下圖:




交互過程:
1、首先用tlenet程序連接到163的pop3郵箱,telnet pop3.163.com 110。
2、執行user命令指定用戶名,user xyang0917。
3、執行pass命令輸入密碼,pass 123456abc。
驗證成功後,提示郵箱中有一封郵件,佔1822字節郵箱空間。
4、執行stat命令統計郵箱中的信息,結果顯示郵箱中有一封郵件,佔1822字節的郵箱空間。
5、執行list命令列出郵箱中的所有郵件,結果顯示1 1822,1代表郵件編號,1822代表郵件的大小,如果有多封郵件,編號從1開始向上累加依次列出來。
6、執行retr 1命令查看第一封郵件的內容。
7、執行dele 1命令將第一封郵件設置刪除標誌。
8、執行rset命令重置所有郵件的刪除標誌。
9、執行quit命令退出郵件接收程序,POP3服務器接收到客戶端發送的quit命令後,將刪除所有設置了刪除標記的郵件,並斷開與客戶端的網絡連接。並且Telnet程序自動結束運行,退回到Window命令行窗口狀態。


三、IMAP協議


       IMAP(Internet Message Access Protocol)協議是對POP3協議的一種擴展,定了郵件客戶端軟件與郵件服務器的通信規則。IMAP協議在RFC2060文檔中定義,目前使用的是第4個版本,所以也稱爲IMAP4。IMAP協議相對於POP3協議而言,它定了更爲強大的郵件接收功能,主要體現在以下一些方面:
  1. IMAP具有摘要瀏覽功能,可以讓用戶在讀完所有郵件的主題、發件人、大小等信息後,再由用戶做出是否下載或直接在服務器上刪除的決定。
  2. IMAP可以讓用戶有選擇性地下載郵件附件。例如一封郵件包含3個附件,如果用戶確定其中只有2個附件對自已有用,就可只下載這2個附件,而不必下載整封郵件,從而節省了下載時間。
  3. IMAP可以讓用戶在郵件服務器上創建自己的郵件夾,分類保存各個郵件。
疑問:那麼POP3協議與IMAP協議都有哪些區別呢?


四、MIME協議


    早期人們在使用電子郵件時,都是使用普通文本內容的電子郵件內容進行交流,由於互聯網的迅猛發展,人們已不滿足電子郵件僅僅是用來交換文本信息,而希望使用電子郵件來交換更爲豐富多彩的多媒體信息,例如,在郵件中嵌入圖片、聲音、動畫和附件等二進制數據。但在以往的郵件發送協議RFC822文檔中定義,只能發送文本信息,無法發送非文本的郵件,針對這個問題,人們後來專門爲此定義了MIME(Multipurpose Internet Mail Extension,多用途Internet郵件擴展)協議。

    MIME協議用於定義複雜的郵件體格式,它可以表達多段平行的文本內容和非文本的郵件內容,例如,在郵件體中內嵌的圖像數據和郵件附件等。另外,MIME協議的數據格式也可以避免郵件內容在傳輸過程發生信息丟失。對於表示某個具體資源的MIME消息,它的消息頭中需要指定資源的數據類型;對於MIME組合消息,它的消息中需要指定組合關係。具體資源的數據類型和組合消息的組合關係,都是通過消息頭中的Content-Type頭字段來指定的。Content-Type字段中的內容以“主類型/子類型”的形式出現,主類型有text、image、audio、video、application、multipart、message等,分別表示文本、圖片、音頻、視頻、應用程序、組合結構、消息等。每個主類型下面都有多個子類型,例如text類型包含plain、html、xml、css等子類型。multipart主類型用於表示MIME組合消息,它是MIME協議中最重要的一種類型。一封MIME郵件中的MIME消息可以有三種組合關係:混合、關聯、選擇,它們對應MIME類型如下:

  • multipart/mixed
表示消息體中的內容是混和組合類型,內容可以是文本、聲音和附件等不同郵件內容的混和體。比如一封郵件中即包含附件,郵件內容還引用內嵌的圖片或附件資源,這種類型郵件的MIME類型就必須定義爲multipart/mixed。
  • multipart/related
表示消息體中的內容是關聯(依賴)組合類型。比如:郵件內容有一個img標籤,這個標籤的src屬性指向的是郵件內部的一個圖片資源,所以這封郵件MIME類型就應該定義爲multipart/related
  • multipart/alternative
表示消息體中的內容是選擇組合類型,例如一封郵件的郵件正文同時採用HTML格式和普通文本格式進行表達時,就可以將它們嵌套在一個multipart/alterntive類型的組合消息中。這種做法的好處在於如果郵件閱讀程序不支持HTML格式時,可以採用其中的文本格式進行替代。
    一封最複雜的電子郵件的基本情況爲:含有郵件正文和郵件附件,郵件正文可以同時使用HTML格式和普通文本格式表示,並且HTML格式的正文中又引用了其它的內嵌資源。對於這種最複雜的電子郵件,可以採用下圖所示的MIME消息結構進行描述:

    從上圖中可以看出,如果在郵件中要添加附件,就必須將整封郵件的MIME類型定義爲multipart/mixed;如果要在HTML格式的正文中引用內嵌資源,那就要定義multipart/related類型的MIME消息;如果普通文本內容與HTML文本內容共存,那就要定義multipart/alternative類型的MIME消息。
    注意:如果整封郵件中只有普通文本內容與HTML文本內容,那麼整封郵件的MIME類型則應定義爲multipart/alternative;如果整封郵件中包含有HTML文本內容和內嵌資源,但不包含附件,那麼整封郵件的MIME類型則應該定義爲multipart/related。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章