目前的電子郵件基本上都是通過POP3網絡協議接收的。根據POP3的規定,當一個電子郵件程序需要接收電子郵件時,該程序同POP3服務程序需要建立起雙向的傳輸通道。和SMTP類似,當傳輸通道成功建立后,電子郵件程序會向POP3服務程序發送一系列基于ASCII字符的命令,而POP3服務程序會對這些命令產生相應的回應來表明相應的操作是成功還是失敗了。下圖顯示了POP3是如何工作的。

POP3協議中定義了很多命令,其中最常用的是USER,PASS,STAT,RETR,DELE和QUIT。和前面一樣。當一個郵件程序成功地通過套接字連接到POP3服務器后,POP3服務器程序將向郵件程序發送初始化消息。該消息由一個"+OK"回應碼和POP3服務程序的名稱和版本信息構成。POP3中只有兩種回應碼"+OK"和"-ERR",郵件程序只需要根據回應碼做出相應的反應,而回應碼后的文字信息主要是供人查看的。在收到初始化消息后,郵件程序通過發送USER命令開始郵件傳輸過程。USER命令指定了用戶名(郵箱的名稱),作為回應,POP3服務程序需要確認用戶名對應的郵箱。假如成功,郵件程序需要發送PASS命令來向POP3服務程序提供郵箱的密碼。接著需要發送STAT命令來獲得目前在郵箱中電子郵件的數量和每個郵件的大小;或者發送RETR命令提取郵件;也可以發送DELE刪除郵件。最后使用QUIT命令退出郵件傳輸過程。
下面提供了一個基于命令行的例子POP3Demo,這個例子可以幫助你理解基于POP3的郵件傳輸機制。這個程序將利用標準端口110連接到一個POP3服務程序上。為了使程序能夠運行,你需要將home更改為你使用的郵箱的地址。
//POP3Demo.java
importjava.io.*;
importjava.net.*;
classPOP3Demo
{
publicstaticvoidmain(String[]args)
{
StringPOP3Server="mail.gatewest.net";
intPOP3Port=110;
Socketclient=null;
try
{
//創建一個連接到POP3服務程序的套接字。
client=newSocket(POP3Server,POP3Port);
//創建一個BufferedReader對象來讀取用戶輸入。
BufferedReaderstdin;
stdin=newBufferedReader(newInputStreamReader(System.in));
//創建一個BufferedReader對象,以便從套接字讀取輸出。
InputStreamis=client.getInputStream();
BufferedReadersockin;
sockin=newBufferedReader(newInputStreamReader(is));
//創建一個PRintWriter對象,以便向套接字寫入內容。
OutputStreamos=client.getOutputStream();
PrintWritersockout;
sockout=newPrintWriter(os,true);//trueforauto-flush
//顯示POP3握手信息。
System.out.println("S:"+sockin.readLine());
while(true)
{
System.out.print("C:");
//讀取用戶輸入。
Stringcmd=stdin.readLine();
//將命令發送到POP3服務程序。
sockout.println(cmd);
//讀取POP3服務程序的回應消息。
Stringreply=sockin.readLine();
System.out.println("S:"+reply);
//假如輸入了RETR命令并且返回了成功的回應碼,持續從套接字讀取輸出,
//直到碰到<CRLF>.<CRLF>。這時從套接字讀出的輸出就是郵件的內容。
if(cmd.toLowerCase().startsWith("retr")&&
reply.charAt(0)== + )
do
{
reply=sockin.readLine();
System.out.println("S:"+reply);
if(reply!=null&&reply.length()>0)
if(reply.charAt(0)== . )
break;
}
while(true);
//假如用戶輸入了QUIT命令,退出郵件傳輸過程。
if(cmd.toLowerCase().startsWith("quit"))
break;
}
}
catch(IOExceptione)
{
System.out.println(e.toString());
}
finally
{
try
{if(client!=null)
client.close();
}
catch(IOExceptione)
{
}
}
}
}
下面是運行POP3Demo的結果:
S:+OKMicrosoftExchange2000POP3serverversion6.04417.0(home.digital.com)
ready
C:userfr
S:+OK
C;passfr
S:+OKUsersUCcessfullyloggedon.
運行POP3Demo后,郵件服務程序首先返回初始化信息。我們可以看到郵件服務器上安裝的是微軟的Exchange2000作為郵件服務程序。然后輸入USER和PASS命令指定用戶名和密碼。有些郵件服務程序在登錄后會提示用戶當前郵箱中是否有新的郵件,例如在linux下的QPOP會返回類似于這樣的信息:
S:+OKfrhas1message(554octets).。
C:stat
S:+OK11
通過STAT命令可以查看當前郵箱中郵件的數目,POP3服務程序返回了11,表示有一份郵件,一封郵件未讀。
C:retr1
S:+OK
S:Recevied:fromgis02([23.3.54.53])byhome.digital.comwithMicrosoftSMTSVC
(5.0.2195.2966)
S:Fri,13Dec200215:12:37+0800
S:Message-ID001401c2a77$04353900$35fw0217@digital.com
S:From:"=?gb2312?B?t+vuow==?="fr@digital.com
S:To:fr@digital.com
Subject:TestEmail
ThisisthetestEmail.
然后就可以發送RETR命令來接收郵件了。RETR的參數代表了郵件的編號,1代表最新的郵件。這封郵件就是剛才通過SMTPDemo發送的郵件。有一點需要注重,在發送的時候我并沒有指定From:頭,那么From:頭是從哪里來的呢?當發送郵件的時候,假如SMTP服務程序假如沒有檢測到From:頭,會將MAIL命令后的參數作為From:頭的內容。
C:dele1
S:+OK
C:stat
S:+OK00
使用DELE命令可以刪除指定的郵件,這里我刪除了序號為1的郵件。刪除后,在利用STAT命令查看郵件時,就會返回00,表示現在郵箱里沒有郵件。
C:quit
S:+OKMicrosoftExchange2000POP3serverversion6.04417.0signingoff.
最后使用QUIT命令中斷與POP3服務程序的通訊。
小結
Java的網絡API可以用來編寫很多有用的程序,例如收發電子郵件的程序。在這篇文章中,我們了解了電子郵件的結構以及如何使用SMTP和POP3協議來發送和接收郵件,同時也了解了MIME是如何支持附件的。
新聞熱點
疑難解答