相信許多人都有MSN聊天工具的帳號,例如[email protected] ,這個賬號其實也是一個郵件地址,可以進行正常的郵件收發功能,你可以通過網址 http://www.hotmail.com 來訪問和操作這個郵箱進行郵件的收發。但是這個郵箱有一個限制就是它並不提供POP3或者SMTP服務,也就是說一般的郵件客戶端工具無法使用這個郵箱,雖然現在有不少的郵件工具可以支持Hotmail郵箱,但是如果我們需要在我們的Java項目中增加對Hotmail郵箱的支持,那往往會不知從什麼地方開始入手,因為SUN公司提供的JavaMail 本身並不提供對除了POP3/IMAP以及SMTP外其他協議的支持。
但事實上,JavaMail只是定義了一組平台無關、獨立於通訊協議的郵件程序框架,或者說是接口,它是作為Java的可選包存在的。因此可以這樣說:JavaMail並不關心所使用的協議,不管是POP3、SMTP、IMAP當然還有Hotmail用的HTTP協議。對於JavaMail的客戶端而言也是這樣的,下圖就是一個最簡單的JavaMail結構圖,通過Transport進行郵件的發送,通過Store實現對郵件的收取,而不同協議的實現,JavaMail裡的概念叫做Provider,只需要根據JavaMail定義的接口實現自己的Provider即可。
為了實現通過JavaMail訪問Hotmail郵箱,我們就需要架起JavaMail接口與Hotmail服務所提供的訪問接口之間的橋梁。在這之前我們必須首先了解Hotmail所使用的接口協議。
Hotmail通過地址 http://services.msn.com/svcs/hotmail/httpmail.asp 提供基於HTTP協議的服務,它不同於我們通過浏覽器訪問 http://www.hotmail.com 的這個地址,後面這個地址是提供給用戶一個基於浏覽器的訪問界面以便對郵箱進行操作,你當然可以通過編寫HTTP客戶端程序來解析頁面並獲取郵件的信息,但是這樣做不僅實現的復雜程度非常高,而且每次頁面風格發生變化後程序都要做相應的調整,因此不具備通用性,顯然是不可行的。而地址 http://services.msn.com/svcs/hotmail/httpmail.asp 則不同,它提供了固定的應用程序接口。當你使用浏覽器訪問該地址的時候,會彈出下面要求登錄的窗體:
而當輸入正確的用戶名和口令後會再彈出一次或兩次該提示窗口,但提示信息不同,操作完成後出現頁面無法顯示的錯誤,錯誤碼是 405 (資源不允許)。因此該服務並不允許通過浏覽器來訪問。
事實上Hotmail使用的是WebDAV來提供基於HTTP協議的應用編程接口,WebDAV(Web 分布式創作和版本控制)已經成為重要的 Web 通訊協議。WebDAV所要解決的問題是:
1.改寫保護:HTTP 1.1 無法確保客戶端可以保護資源,並且可以在其他客戶端同時編輯它們的情況下進行更改。 使用 WebDAV,可以通過多種方式來鎖定資源,以便讓其他客戶端知道您對所討論的資源感興趣,或者防止其他客戶端訪問該資源。
2.資源管理:HTTP 只能直接訪問單個資源。 WebDAV 提供一種更有效地組織數據的方法。 WebDAV 引入了可包含資源 的集合(類似於文件系統文件夾)概念。 通過 WebDAV 進行的資源管理包括如下功能:創建、移動、復制和刪除集合,以及集合中的資源或文件。
3.文檔屬性:不同類型的數據具有唯一的屬性,這有助於描述數據。 例如,在電子郵件中,這些屬性可能是發件人的姓名和接收郵件的時間。 在協作文檔中,這些屬性可能是文檔原始作者的姓名和最後一個編輯者的姓名。 因為人們使用的文檔類型各不相同,所以可能的屬性類型列表也變得無限大。 XML 是 WebDAV 所需的一種可擴展通訊工具。
關於WebDAV的更多資料可以參閱本文最後的參考資料。
相對於自行解析Hotmail的浏覽器頁面而言,基於特定協議WebDAV的接口使Hotmail郵件客戶端程序的實現更加穩定和可靠。在了解了JavaMail API的基本接口以及Hotmail所提供接口的協議,本文的題目就變得非常具體了,就是如果編寫基於WebDAV的JavaMail Provider(JavaMail提供者)並使用這個提供者來實現Hotmail郵件收發功能,但這題目太大而且已經超過了一篇文章所能敘述的范圍,因此我們接下來將引入一個開放源碼項目JDAVMail,並詳細介紹如何通過這個項目實現Hotmail郵件的收發功能。
JDAVMail 是一個開放源碼的JavaMail的提供者項目,可以通過它來訪問基於WebDAV協議的郵件服務,有如Hotmail郵箱。你可以到 http://sourceforge.net/projects/jdavmail 這個網址下載到最新版本的程序。JDAVMail使用了Jakarta上的commons httpclient 作為HTTP客戶端組件與服務器進行通訊,同時使用了jdom進行XML數據的解析,另外由於httpclient項目用到了commons logging進行日記的輸出,因此commons-logging也是必須的,這三個組件都可以在JDAVMail的壓縮包中的lib目錄中找到,壓縮包中同時還包括已編譯的jar文件以及所有的源碼。
為了讓大家對JDAVMail有個大概的認識,下面我們給出兩段代碼用於Hotmail郵件的收發:
1. 郵件收取
/*
* 文件名:HotmailDemo.java
* 創建時間:2004-9-14
* 創建者:liudong
*/
package com.clickcom.mail;
import java.util.Date;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
/**
* Hotmail郵件的收發器
* @author liudong
*/
public class HotmailDemo {
public static void main(String[] args) {
receive();
}
/**
* 郵件接收
*/
protected static void receive() {
try {
Properties prop = new Properties();
Session ses = Session.getInstance(prop);
//使用JDAVMail Provider
Store store = ses.getStore("davmail");
//無需指定服務器地址
store.connect(null, "你的帳號","密碼");
if (store.isConnected()) {
Folder inbox = store.getFolder("INBOX");
if (inbox.exists()) {
inbox.open(Folder.READ_ONLY);
int nCount = inbox.getMessageCount();
System.out.println("Inbox contains " + nCount + " messages");
// 依次顯示收件箱中的每封郵件
for(int i=1;i<=nCount;i++){
MimeMessage msg = (MimeMessage) inbox.getMessage(i);
System.out.println("Subject : " + msg.getSubject());
System.out.println("From : " + msg.getFrom()[0].toString());
System.out.println("Content type : " + msg.getContentType());
System.out.println(msg.getContent());
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
從上面這段代碼我們發現除了 Store store = ses.getStore("davmail"); 這個語句,同時不需要指定服務器地址外,其他的都跟一個普通的JavaMail應用程序沒有兩樣,也沒有引入任何跟JDAVMail有關的類。沒有指定服務器地址這個比較容易理解,因為Hotmail提供HttpMail服務的地址是固定的。事實上僅有getStore這個語句跟常規郵件客戶端程序有點不同的是它使用davmail字符串作為參數,而我們在使用JavaMail連接POP3服務器的時候指定參數值為pop3。怎麼回事呢?因為JavaMail是通過協議名來加載Provider類的。打開JDAVMail.0.9.006.jar這個jar文件就會發現在META-INF目錄下有一個文件javamail.providers,該文件內容如下:
protocol=davmail;
type=store; class=com.posisoft.jdavmail.JDAVMailStore;
vendor=Positive Software;
protocol=davmail_xmit;
type=transport;
class=com.posisoft.jdavmail.JDAVMailTransport;
vendor=Positive Software;
因此當我們指定協議名為davmail時,JavaMail就會自動加載com.posisoft.jdavmail.JDAVMailStore類進行處理,因此通過傳入davmail字符串所得到的store實例實際上是類com.posisoft.jdavmail.JDAVMailStore的一個實例,這樣我想大家應該了解了前面這段程序的工作原理。
我們再來看JDAVMail發送郵件的代碼片段:
/**
* 郵件發送
*/
protected static void send() {
try {
Properties prop = new Properties();
//郵件發送者地址
prop.setProperty("mail.davmail.from","[email protected]");
Session ses = Session.getInstance(prop);
//獲得JDAVMail的郵件發送實例
Transport transport = ses.getTransport("davmail_xmit");
//連接到Hotmail服務器,請替換為自己的用戶名和口令
transport.connect(null, "用戶名","口令");
// 准備要發送的郵件
MimeMessage txMsg = new MimeMessage(ses);
txMsg.setSubject("This is the subject");
//郵件發送者地址
InternetAddress addrFrom = new InternetAddress("[email protected]");
txMsg.setFrom(addrFrom);
//郵件接收者地址
InternetAddress addrTo = new InternetAddress("[email protected]", "cdef");
txMsg.addRecipient(Message.RecipientType.TO, addrTo);
//郵件內容
txMsg.setText("Hello world !");
txMsg.setSentDate(new Date());
//發送郵件
transport.sendMessage(txMsg, txMsg.getAllRecipients());
} catch (Exception ex) {
ex.printStackTrace();
}
}
同樣這段代碼使用了davmail_xmit協議來獲取JDAVMail的郵件發送實例,通過前面提到的javamail.providers文件不難知道JDAVMail使用類com.posisoft.jdavmail.JDAVMailTransport進行郵件的發送處理。
在實際測試中發現不管是JDAVMail還是其他的郵件工具,使用Hotmail進行郵件的發送速度比較慢,差不多有幾分鐘後才能收到相應的信息,因此如果測試中發現該問題請耐心等待。
我想通過本文介紹如何利用JDAVMail收發Hotmail郵件,以及研究JDAVMail的源碼,不僅可以更加深入了解JavaMail的體系結構,對編寫JavaMail Provider也有更加具體的參照。另外希望為正困撓於如何在Java程序中訪問Hotmail郵件的朋友們排憂解難。同時也非常歡迎通過我的網站 http://www.javayou.com 跟我交流在使用中遇到的問題。