Chinese To English     英文 轉(zhuǎn) 中文             
                   
          隨筆-27  評論-53  文章-0  trackbacks-0

          JavaMail API


          1. 復(fù)習(xí)相關(guān)協(xié)議 2. 安裝 3. 使用Java 2企業(yè)版 4. Session類
          5. Message類 6. Address類 7. Authenticator類 8. Transport類
          9. Store和Folder類 10.發(fā)送消息 11.獲取消息 12.刪除消息和標(biāo)志
          13.自我驗證 14.回復(fù)消息 15.轉(zhuǎn)發(fā)消息 16.發(fā)送附件
          17.獲取附件 18.處理HTML消息 19.在消息中包含圖片 20.用SearchTerm搜索
          
                      

                  JavaMail API是一種可選的、能用于讀取、編寫和發(fā)送電子消息的包(標(biāo)準(zhǔn)擴(kuò)展)。您可使用這種包創(chuàng)建郵件用戶代理(Mail User Agent ,MUA)類型的程序,它類似于Eudora、Pine及Microsoft Outlook這些郵件程序。其主要目的不是像發(fā)送郵件或其他郵件傳輸代理(Mail Transfer Agent,MTA)類型的程序那樣用于傳輸、發(fā)送和轉(zhuǎn)發(fā)消息。換句話說,用戶可以與MUA類型的程序交互,以閱讀和撰寫電子郵件。MUA依靠MTA處理實際的發(fā)送任務(wù)。

          JavaMail API的設(shè)計是,為收發(fā)信息提供與協(xié)議無關(guān)的訪問。方式是把該API劃分成兩個部分:

          · 該API的第一個部分是本課程的重點?;旧鲜侨绾伟l(fā)送和接收獨立于提供程序/協(xié)議的消息。

          · 第二個部分則使用特定的協(xié)議語言,如:SMTP、POP、IMAP和NNTP。如果要讓JavaMail API與服務(wù)器通信,就需要為之提供協(xié)議。由于Sun公司對特定協(xié)議提供程序有充分的介紹,用戶可以免費獲取,所以本課程沒有介紹創(chuàng)建特定協(xié)議提供程序的內(nèi)容。

          復(fù)習(xí)相關(guān)協(xié)議

                  在學(xué)習(xí)JavaMail API的深層知識之前,讓我們回過頭來看一看在該API中使用的協(xié)議,本質(zhì)上有4種人們常用的協(xié)議:

          · SMTP
          · POP
          · IMAP
          · MIME

          您還需要了解NNTP及其他一些協(xié)議。理解這些協(xié)議的基本原理有助于您理解如何使用JavaMail API。而該API的設(shè)計要與協(xié)議無關(guān),所以不能克服這些基礎(chǔ)協(xié)議的限制。如果選用的協(xié)議不支持某種功能,那么JavaMail API也無法在其上添加這種功能。(正如您一會兒就會看到的,在操作POP協(xié)議時,常常會碰到這種問題)。

          SMTP

          簡單郵件傳輸協(xié)議(SMTP)是用于傳送電子郵件的機(jī)制。在JavaMail API環(huán)境中,您的基于JavaMail的程序?qū)⑴c您公司或Internet服務(wù)提供商(ISP)的SMTP服務(wù)器通信。該SMTP服務(wù)器將會把消息轉(zhuǎn)發(fā)給用作接收消息的SMTP服務(wù)器,最后用戶可通過POP或IMAP協(xié)議獲取該消息。由于支持身份驗證,所以不需要SMTP服務(wù)器是一種開放的轉(zhuǎn)發(fā)器,但需要確保SMTP服務(wù)器配置正確。JavaMail API中沒有集成用于處理諸如配置服務(wù)器以轉(zhuǎn)發(fā)消息或添加/刪除電子郵件帳戶這一類任務(wù)的功能。

          POP

          POP 的含義是郵局協(xié)議,當(dāng)前的版本為3,也稱作POP3,該協(xié)議是在RFC 1939中定義的。POP是Internet上的大多數(shù)人用來接收郵件的機(jī)制。它為每個用戶的每個郵箱定義支持,這是它所做的全部工作,也是大多數(shù)問題的根源。在使用POP協(xié)議時,人們熟悉的很多功能,如查看收到了多少新郵件消息的功能,POP根本不支持。這些功能都內(nèi)置到諸如Eudora或 Microsoft Outlook之類的郵件程序中,能為您記住接收的上一封郵件,以及計算有多少新郵件這類信息。因此,使用JavaMail API時,如果想獲取這類信息,將需要由自己進(jìn)行計算。

          IMAP

          IMAP是用于接收消息的更加高級的協(xié)議,它是在RFC 2060中定義的。IMAP的含義是“Internet消息訪問協(xié)議”,當(dāng)前版本是第4版,也稱作IMAP4。使用IMAP時,您的郵件服務(wù)器必須支持該協(xié)議。您不能只是簡單地把程序轉(zhuǎn)變?yōu)橹С諭MAP,而不是支持POP,就指望能支持IMAP中的一切。假定您的郵件服務(wù)器支持IMAP,那么基于 JavaMail的程序就可利用在服務(wù)器上擁有多個文件夾的用戶,并且這些文件夾可以被多個用戶共享的功能。

          由于IMAP協(xié)議具有更高級的功能,您也許會想IMAP應(yīng)該被每一個人使用,但事實不是這樣。因為IMAP會加重郵件服務(wù)器的負(fù)荷,它需要服務(wù)器接收新消息,發(fā)送消息給請求的用戶,并在多個文件夾中為每個用戶維護(hù)這些消息。而這要集中備份,因而長期下去用戶的文件夾會變得越來越大,當(dāng)磁盤空間用光了時,每個人都會遭受損失。而使用POP協(xié)議時,已保存消息可以解除服務(wù)器的重負(fù)。

          MIME

          MIME的含義是“多用途的網(wǎng)際郵件擴(kuò)充協(xié)議”。它不是一種郵件傳輸協(xié)議,相反,它定義傳輸?shù)膬?nèi)容:消息的格式、附件等。許多文檔都定義了MIME協(xié)議,包含:RFC 822、RFC 2045、RFC 2046和RFC 2047。作為JavaMail API的用戶,一般不需要擔(dān)心這些格式。但是,這些格式確實存在,并為您的程序所用。

          NNP和其他協(xié)議

          由于JavaMail API分開了提供程序和其他部分,所以您可以輕松地為附加協(xié)議添加支持。Sun公司提供第3方提供程序清單,這些提供程序要利用 Sun公司不支持的少見的協(xié)議。在這份清單中,您將會看到對NNTP(網(wǎng)絡(luò)新聞傳輸協(xié)議)[新聞組]、S/MIME(安全多用途的網(wǎng)際郵件擴(kuò)充協(xié)議)及其他協(xié)議的提供支持的第3方提供程序。

          點擊返回頂端->>>

          安裝

                  目前有兩種版本的JavaMail API最常用:1.2和1.1.3。本課程中的所有例子都適用于這兩種版本。其中JavaMail API 1.2是最新的,而JavaMail API 1.1.3中包含了Java 2企業(yè)版(J2EE)平臺1.2.1版,所以它仍然很常用。使用JavaMail API的版本會對您的下載和安裝產(chǎn)生一些影響。這兩種版本的JavaMail API都能與JDK 1.1.6、Java 2標(biāo)準(zhǔn)版(J2SE)平臺1.2.x和1.3.x協(xié)同工作。

          注意:在安裝了Sun公司的JavaMail工具后,會在演示目錄下看到許多示例程序。

          安裝JavaMail 1.2

          要使用JavaMail 1.2 API,可以下載JavaMail 1.2工具,然后解壓縮javamail-1_2.zip文件,并把mail.jar文件添加到典型安裝路徑下。JavaMail 1.2工具帶有SMTP、IMAP4和POP3提供程序以及核心類。

          安裝完JavaMail 1.2后,再安裝JavaBeans Activation Framework。

          安裝JavaMail 1.1.3

          要使用JavaMail 1.1.3 API,可以下載JavaMail 1.1.3工具,然后解壓縮javamail1_1_3.zip文件,并把mail.jar文件添加到典型安裝路徑下。JavaMail 1.1.3工具帶有SMTP和IMAP4提供程序以及核心類。

          如果您想用JavaMail 1.1.3訪問POP服務(wù)器,需要下載并安裝POP3提供程序。Sun公司擁有一個獨立于 JavaMail 工具的提供程序。在下載并解壓縮pop31_1_1.zip文件后,也還需要把pop3.jar添加到典型安裝路徑下。

          安裝完JavaMail 1.1.3后,再安裝JavaBeans Activation Framework。

          安裝JavaBeans Activation Framework

          JavaMail API的所有版本都需要JavaBeans Activation Framework(JavaBeans激活框架),這種框架提供了對輸入任意數(shù)據(jù)塊的支持,并能相應(yīng)地對其進(jìn)行處理。看上去效果好像不太好,但該框架是在當(dāng)今的許多瀏覽器和郵件工具中可以找到的基本MIME類型支持。下載該框架后,解壓縮jaf1_0_1.zip文件,并將activation.jar 文件添加到典型安裝路徑下。

          對于JavaMail 1.2用戶,現(xiàn)在應(yīng)該把mail.jar和activation.jar文件添加到典型安裝路徑下。

          對于JavaMail 1.1.3用戶,現(xiàn)在應(yīng)該把mail.jar、pop3.jar和activation.jar添加到典型安裝路徑下。如果您不打算使用POP3,就不需要把pop3.jar文件添加到典型安裝路徑下。

          如果您不想更改安裝路徑環(huán)境變量,可以把JAR文件復(fù)制到Java運行時環(huán)境(JRE)目錄下的lib/ext目錄下。例如,對于J2SE 1.3版本,Windows平臺上的默認(rèn)目錄應(yīng)該是C:\jdk1.3\jre\lib\ext。

          點擊返回頂端->>>

          使用Java 2企業(yè)版

                  如果您使用的是J2EE,則在使用基本JavaMail API時,不需要做什么特殊的工作;JavaMail API帶有J2EE類。只要確保j2ee.jar文件位于典型安裝路徑下,并完成了所有的設(shè)置工作。

          對于J2EE 1.2.1,POP3提供程序是單獨提供的,因此需要下載該提供程序,并按安裝JavaMail 1.1.3的步驟,在J2EE 1.2.1中包含POP3提供程序。J2EE 1.3的用戶會獲得J2EE和POP3提供程序,因而不需要對POP3提供程序執(zhí)行獨立安裝。使用這兩種版本的J2EE用戶,都不需要安裝 JavaBeans Activation Framework。

          復(fù)習(xí)核心類

          在開始深入研究JavaMail類之前,首先讓用戶瀏覽一下構(gòu)成API的核心類:會話、消息、地址、驗證程序、傳輸,存儲和文件夾。所有這些類都可以在 JavaMail API即javax.mail的頂層包中找到,盡管您將頻繁地發(fā)現(xiàn)您自己使用的子類是在javax.mail.internet包中找到的。

          點擊返回頂端->>>

          Session類

                  Session類定義了一個基本的郵件會話。通過該會話可讓別的工作順利執(zhí)行。Session對象利用java.util.Properties對象獲取諸如郵件服務(wù)器、用戶名、密碼等信息,以及其他可在整個應(yīng)用程序中共享的信息。

          Session類的構(gòu)造器是私有的。您可以獲得一個可被getDefaultInstance()方法共享的單一的默認(rèn)會話:

          Properties props = new Properties();

          // fill props with any information

          Session session = Session.getDefaultInstance(props, null);

          或者,您可以用getInstance()方法創(chuàng)建一個獨特的會話:

          Properties props = new Properties();

          // fill props with any information

          Session session = Session.getInstance(props, null);

          這兩種情形下的null參數(shù)都是一種Authenticator對象,它不是在此時使用的。詳細(xì)信息請參閱其后的“Autherticator”一節(jié)。

          在大多數(shù)情況下,使用共享會話就足夠了,即使為多個用戶郵箱處理郵件會話也是如此。您可以在通信過程的后面一步添加上用戶名和密碼的組合,并保持所有的一切是獨立的。

          點擊返回頂端->>>

          Message類

                  一旦創(chuàng)建了自己的Session對象,就是該去創(chuàng)建要發(fā)送的消息的時候了。這時就要用到消息類型。作為一個抽象類,您必須操作一個子類,在大多數(shù)情況下,該子類是javax.mail.internet.MimeMessage。一個MimeMessage是一種理解MIME類型和報頭(在不同的RFC文檔中均有定義)的消息。消息的報頭被嚴(yán)格限制成只能使用US-ASCII字符,盡管非ASCII字符可以被編碼到某些報頭字段中。

          可以通過將Session對象傳遞給MimeMessage構(gòu)造器的方法來創(chuàng)建消息:

          MimeMessage message = new MimeMessage(session);
          注意:還有其他的構(gòu)造器,像用于創(chuàng)建消息的源于RFC822格式化的輸入流的構(gòu)造器。

          一旦創(chuàng)建了消息,就可以設(shè)置其各個部分,如Message(消息)實現(xiàn)Part(部分)接口(以MimeMessage實現(xiàn)MimePart)。設(shè)置內(nèi)容的基本機(jī)制是setContent()方法,它帶有表示內(nèi)容和MIME類型的參數(shù):

          message.setContent("Hello", "text/plain");

          但是,如果正在使用 MimeMessage,并且您的消息是純文本,那么您就可以使用setText()方法。該方法只需要一個表示實際內(nèi)容的參數(shù),默認(rèn)的MIME類型為純文本:

          message.setText("Hello");

          對于純文本消息,setText()方法更常常被用來設(shè)置內(nèi)容。要發(fā)送其他類型的消息,如HTML消息,就要使用setContent方法()?,F(xiàn)在用的更多的是HTML消息。

          要設(shè)置主題,可以使用setSubject()方法:

          message.setSubject("First");

          點擊返回頂端->>>

          Address類

                  一旦創(chuàng)建了會話和消息,并為消息填充了內(nèi)容,就需要用Address類為您的信件標(biāo)上地址了。同Message類一樣,Address類也是一種抽象類。您可以使用javax.mail.internet.InternetAddress類。

          要創(chuàng)建只帶有電子郵件地址的地址,可以把電子郵件地址傳遞給Address類的構(gòu)造器:

          Address address = new InternetAddress("president@whitehouse.gov");

          如果想讓一個名字出現(xiàn)在電子郵件地址后,也可以將其傳遞給構(gòu)造器:

          Address address = new InternetAddress("president@whitehouse.gov", "George Bush");

          您要為消息的from(發(fā)送者)字段和to(接收者)字段創(chuàng)建地址對象。除非您的郵件服務(wù)器阻止這樣做,否則要在發(fā)送的消息中注明該消息的發(fā)送者。

          一旦創(chuàng)建好了地址,有兩種方法可讓您將地址與消息連接起來。為了鑒別發(fā)送者,您可以使用setFrom()和setReplyTo()方法。

          message.setFrom(address)

          如果您的消息需要顯示多個地址來源,則可以使用addFrom()方法:

          Address address[] = ...;
          message.addFrom(address);

          為了鑒別消息接收者,您可以使用addRecipient()方法。該方法除了需要一個地址參數(shù)外,還需要一個Message.RecipientType屬性(消息的接收類型)。

          message.addRecipient(type, address)

          地址的3種預(yù)定義類型如下:

          · Message.RecipientType.TO
          · Message.RecipientType.CC
          · Message.RecipientType.BCC

          因此,如果一條消息將發(fā)送給副總統(tǒng),同時還將發(fā)送該消息的副本給第一夫人,則采用下面的代碼:

          Address toAddress = new InternetAddress("vice.president@whitehouse.gov");
          Address ccAddress = new InternetAddress("first.lady@whitehouse.gov");
          message.addRecipient(Message.RecipientType.TO, toAddress);
          message.addRecipient(Message.RecipientType.CC, ccAddress);

          JavaMail API沒有提供檢查電子郵件地址有效性的機(jī)制。您可以自己編寫支持掃描有效字符(在RFC 822文檔中所定義的)的程序或檢驗MX(郵件交換)記錄,這些都超越了JavaMail API的范圍。

          點擊返回頂端->>>

          Authenticator類

                  與java.net 類一樣,JavaMail API可以利用Authenticator(驗證程序)類通過用戶名和密碼來訪問受保護(hù)的資源。對于JavaMail API來說,這種受保護(hù)的資源是指郵件服務(wù)器。JavaMail的Authenticator類可以在javax.mail包中找到,并有別于同名的 java.net類。當(dāng)JavaMail API在Java 1.1下工作時,JavaMail和java.net不會共享同一個Authenticator類名稱,這是因為Java 1.1中不含有java.net。

          要使用Authenticator類,您可以使用該抽象類的子類,并通過 getPasswordAuthentication()方法返回一個PasswordAuthentication實例。在創(chuàng)建時,您必須用會話記錄 Authentication類。其后,當(dāng)需要進(jìn)行身份驗證時,會通知您的Authenticator。會彈出一個窗口,或從一個配置文件(盡管不加密就不安全)中讀取用戶名和密碼,并把它們作為一個PasswordAuthentication對象返回給調(diào)用程序。

          Properties props = new Properties();
          // fill props with any information
          Authenticator auth = new MyAuthenticator();
          Session session = Session.getDefaultInstance(props, auth);

          點擊返回頂端->>>

          Transport類

                  發(fā)送消息的最后一步操作是使用Transport類。該類使用特定于協(xié)議(通常是SMTP)的語言來發(fā)送消息。它是一個抽象類,其操作與Session類有些相似。您可以通過只調(diào)用靜態(tài)的send()方法來使用該類的默認(rèn)版本:

          Transport.send(message);

          或者,您可以從用于您的協(xié)議的會話中獲取一個特定的實例,然后傳遞用戶名和密碼(不必要時可以為空)并發(fā)送消息,最后關(guān)閉連接:

          message.saveChanges(); // implicit with send()

          Transport transport = session.getTransport("smtp");
          transport.connect(host, username, password);
          transport.sendMessage(message, message.getAllRecipients());
          transport.close();

          當(dāng)您需要發(fā)送多個消息時,建議采用后一種方法,因為它將保持消息間活動服務(wù)器的連接。而基本的send()機(jī)制會為每一個方法調(diào)用都建立一條獨立的連接。

          注意:要查看經(jīng)過郵件服務(wù)器郵件命令,可以用session.setDebug(true)方法設(shè)置調(diào)試標(biāo)志。

          點擊返回頂端->>>

          Store和Folder類

                  使用Session類來獲取消息,開始時與發(fā)送消息很相似。但是,在獲取會話后,很有可能使用用戶名和密碼或Authenticator類來連接Store類。與Transport類一樣,您要告訴Store類將使用什么協(xié)議:

          // Store store = session.getStore("imap");
          Store store = session.getStore("pop3");
          store.connect(host, username, password);

          在連接Store類后,就可以獲取一個Folder類,在讀取其中的消息前必須先打開該類。

          Folder folder = store.getFolder("INBOX");
          folder.open(Folder.READ_ONLY);
          Message message[] = folder.getMessages();

          對于POP3協(xié)議,惟一可用的文件夾是INBOX。如果使用的是IMAP協(xié)議,則可以使用其他的文件夾。

          注意:Sun公司的提供程序本來想提供方便。而Message message[]=folder.getMessages();這條語句卻是一種從服務(wù)器逐條讀取消息的緩慢操作,所以僅當(dāng)您確實需要獲取消息部分(該內(nèi)容是所檢索消息的內(nèi)容)時可以使用這條語句。

          一旦讀取消息,就可以使用getContent()方法獲取其內(nèi)容,或使用writeTo()方法將其內(nèi)容寫到一個流中。getContent()方法只獲取消息內(nèi)容,而writeTo()方法則還會輸出報頭。

          System.out.println(((MimeMessage)message).getContent());

          一旦您閱讀完郵件,就可以關(guān)閉對文件夾和存儲的連接。

          folder.close(aBoolean);
          store.close();

          傳遞給文件夾的close()方法的布爾變量指定了是否通過清除已刪除的消息來更新文件夾。

          繼續(xù)前進(jìn)

          實際上,理解使用這7個類的方式,是使用JavaMail API處理幾乎所有事情所需要的全部內(nèi)容。用這7個類以外的方式構(gòu)建的JavaMail API,其大多數(shù)功能都是以幾乎完全相同或特定的方式來執(zhí)行任務(wù)的,就好像內(nèi)容是附件。特定的任務(wù),如:搜索、隔離等將在后面進(jìn)行介紹。

          使用JavaMail API

          您已經(jīng)看到了如何操作JavaMail API的核心部分。在下面幾節(jié)中,您將學(xué)習(xí)如何連接幾個部分以執(zhí)行特定的任務(wù)。

          點擊返回頂端->>>

          發(fā)送消息

                  發(fā)送電子郵件消息涉及到獲取會話、創(chuàng)建和填充消息并發(fā)送消息這些操作。您可以在獲取Session時,通過為要傳遞的Properties對象設(shè)置mail.smtp.host屬性來指定您的SMTP服務(wù)器。

          String host = ...;
          String from = ...;
          String to = ...;
          // Get system properties
          Properties props = System.getProperties();
          // Setup mail server
          props.put("mail.smtp.host", host);
          // Get session
          Session session = Session.getDefaultInstance(props, null);
          // Define message
          MimeMessage message = new MimeMessage(session);
          message.setFrom(new InternetAddress(from));
          message.addRecipient(Message.RecipientType.TO,
          new InternetAddress(to));
          message.setSubject("Hello JavaMail");
          message.setText("Welcome to JavaMail");
          // Send message
          Transport.send(message);
          您應(yīng)該在try-catch塊中編寫代碼,以在創(chuàng)建消息并發(fā)送它時可以拋出一個異常。

          點擊返回頂端->>>

          獲取消息

                  對于閱讀郵件來說,首先您要獲取一個會話,然后獲取并連接到一個相應(yīng)的用于您的收件箱的存儲上,接著打開相應(yīng)的文件夾,再獲取消息。同時,不要忘記了操作完成后關(guān)閉連接。

          String host = ...;
          String username = ...;
          String password = ...;
          // Create empty properties
          Properties props = new Properties();
          // Get session
          Session session = Session.getDefaultInstance(props, null);
          // Get the store
          Store store = session.getStore("pop3");
          store.connect(host, username, password);
          // Get folder
          Folder folder = store.getFolder("INBOX");
          folder.open(Folder.READ_ONLY);
          // Get directory
          Message message[] = folder.getMessages();
          for (int i=0, n=message.length; i<n; i++) {
          System.out.println(i + ": " + message[i].getFrom()[0]
          + "\t" + message[i].getSubject());
          }
          // Close connection
          folder.close(false);
          store.close();

          每一條消息執(zhí)行何種操作取決于自己決定。上面的代碼塊只是顯示了消息的發(fā)送者和主題。從技術(shù)上講,發(fā)送者地址列表可以為空,此時getFrom()[0]調(diào)用會拋出一個異常。

          為了顯示整條消息,您可以提示用戶在看完消息的發(fā)送者和主題字段后,如果想看到消息的內(nèi)容,可以再調(diào)用消息的writeTo()方法。

          BufferedReader reader = new BufferedReader (
          new InputStreamReader(System.in));
          // Get directory
          Message message[] = folder.getMessages();
          for (int i=0, n=message.length; i<n; i++) {
          System.out.println(i + ": " + message[i].getFrom()[0]
          + "\t" + message[i].getSubject());
          System.out.println("Do you want to read message? " +
          "[YES to read/QUIT to end]");
          String line = reader.readLine();
          if ("YES".equals(line)) {
          message[i].writeTo(System.out);
          } else if ("QUIT".equals(line)) {
          break;
          }
          }

          點擊返回頂端->>>

          刪除消息和標(biāo)志

                  刪除消息涉及到操作與消息關(guān)聯(lián)的標(biāo)志。對不同的狀態(tài)有不同的標(biāo)志,有些標(biāo)志是系統(tǒng)定義的,有些則是由用戶定義的。預(yù)定義的標(biāo)志都是在內(nèi)部類Flags.Flag中定義的,如下所示:

          · Flags.Flag.ANSWERED
          · Flags.Flag.DELETED
          · Flags.Flag.DRAFT
          · Flags.Flag.FLAGGED
          · Flags.Flag.RECENT
          · Flags.Flag.SEEN
          · Flags.Flag.USER

          僅僅因為標(biāo)志存在,并不表示標(biāo)志為所有的郵件服務(wù)器/提供程序所支持。例如,除了刪除消息外,POP協(xié)議對它們都不支持。檢查新郵件不是POP的任務(wù),但它已內(nèi)置到郵件客戶程序中。要搞清楚什么標(biāo)志受到支持,可以使用getPermanentFlags()方法來詢問文件夾。

          要刪除消息,需要為消息設(shè)置DELETE標(biāo)志:

          message.setFlag(Flags.Flag.DELETED, true);

          第一次以READ_WRITE(讀-寫)模式打開文件夾:

          folder.open(Folder.READ_WRITE);

          然后,處理完了所有的消息,請關(guān)閉文件夾,并傳遞true值以擦去刪除的消息。

          folder.close(true);

          用戶可使用Folder類的expunge()方法來刪除消息。但是,該方法對Sun公司的POP3提供程序不起作用。其他提供程序或許能也或許不能實現(xiàn)其功能。它更有可能適用于IMAP提供程序。由于POP只支持對收件箱的簡單訪問,使用Sun公司的提供程序時,您將不得不關(guān)閉文件夾以刪除消息。

          要移去標(biāo)志,只需傳遞一個false值給setFlag()方法。要看看是否設(shè)置了某個標(biāo)志,可以使用isSet()進(jìn)行檢查。

          點擊返回頂端->>>

          自我驗證

                  先前學(xué)到的是使用Authenticator類,以在需要時提示輸入用戶名和密碼,而不是以字符串的形式傳入它們。這里,您將真正看到如何更加充分地使用驗證。

          不需使用主機(jī)、用戶名和密碼連接到Store,您可以配置Properties帶有主機(jī),并告訴Session關(guān)于您自定義的Authenticator實例,如下所示:

          // Setup properties
          Properties props = System.getProperties();
          props.put("mail.pop3.host", host);
          // Setup authentication, get session
          Authenticator auth = new PopupAuthenticator();
          Session session = Session.getDefaultInstance(props, auth);
          // Get the store
          Store store = session.getStore("pop3");
          store.connect();

          然后您可以使用Authenticator類的子類,并通過getPasswordAuthentication()方法返回一個 PasswordAuthentication對象。下面是這種實現(xiàn)的一個例子,其中一個字段同時適用于兩部分內(nèi)容。它不是一個Project Swing指南,只是在一個字段中輸入了兩部分內(nèi)容,它們是用逗號隔開的。

          import javax.mail.*;
          import javax.swing.*;
          import java.util.*;
          public class PopupAuthenticator extends Authenticator {
          public PasswordAuthentication getPasswordAuthentication() {
          String username, password;
          String result = JOptionPane.showInputDialog(
          "Enter 'username,password'");
          StringTokenizer st = new StringTokenizer(result, ",");
          username = st.nextToken();
          password = st.nextToken();
          return new PasswordAuthentication(username, password);
          }
          }

          由于PopupAuthenticator依賴于Swing,因而將會啟動用于AWT的事件處理線程。這在本質(zhì)上要求您在代碼中添加一個對System.exit()的調(diào)用,以終止程序的執(zhí)行。

          點擊返回頂端->>>

          回復(fù)消息

                  Message 類包含一個reply()方法,以用正確的接收者和主題(添加“Re::”,如果沒有的話)配置一條新消息。該方法不會為消息添加任何內(nèi)容,只是為新的接收者復(fù)制發(fā)送者或回復(fù)到的報頭。該方法使用一個布爾型參數(shù),提示是否只回復(fù)給發(fā)送者(false)或回復(fù)給所有人(true)。

          MimeMessage reply = (MimeMessage)message.reply(false);
          reply.setFrom(new InternetAddress("president@whitehouse.gov"));
          reply.setText("Thanks");
          Transport.send(reply);
          在發(fā)送消息時要配置回復(fù)到地址,可使用setReplyTo()方法。

          點擊返回頂端->>>

          轉(zhuǎn)發(fā)消息

                  轉(zhuǎn)發(fā)消息涉及的內(nèi)容要稍微多一點,沒有一個專門用于轉(zhuǎn)發(fā)消息的方法,您可以通過處理組成消息的各個部分來創(chuàng)建要轉(zhuǎn)發(fā)的消息。

          一條郵件消息可由多個部分組成,每一部分是一個BodyPart(報文部分),或更特殊一點,在操作MIME消息時則是MimeBodyPart。不同的報文部分組合到一個稱為Multipart的容器中,或者又更特殊一點,是一個MimeMultipart容器。要轉(zhuǎn)發(fā)消息,您要創(chuàng)建一個用于消息文本的部分,和用于要轉(zhuǎn)發(fā)的消息的第二個部分,并將這兩個部分組合成一個multipart(多個部分)。然后您可以把這個multipart添加到一個合適的注明地址的消息中并發(fā)送它。

          這就是轉(zhuǎn)發(fā)消息的本質(zhì)。要把一條消息的內(nèi)容復(fù)制給另一條消息,只需通過它的DataHandler類復(fù)制即可,它是出自于JavaBeans Activation Framework的一個類。

          // Create the message to forward
          Message forward = new MimeMessage(session);
          // Fill in header
          forward.setSubject("Fwd: " + message.getSubject());
          forward.setFrom(new InternetAddress(from));
          forward.addRecipient(Message.RecipientType.TO,
          new InternetAddress(to));
          // Create your new message part
          BodyPart messageBodyPart = new MimeBodyPart();
          messageBodyPart.setText(
          "Here you go with the original message:\n\n");
          // Create a multi-part to combine the parts
          Multipart multipart = new MimeMultipart();
          multipart.addBodyPart(messageBodyPart);
          // Create and fill part for the forwarded content
          messageBodyPart = new MimeBodyPart();
          messageBodyPart.setDataHandler(message.getDataHandler());
          // Add part to multi part
          multipart.addBodyPart(messageBodyPart);
          // Associate multi-part with message
          forward.setContent(multipart);
          // Send message
          Transport.send(forward);

          操作附件

          附件是與郵件消息關(guān)聯(lián)的資源,通常保存在消息之外,如:一個文本文件,電子表格或圖片。對于像Eudora和Pine之類的常用郵件程序,您可以通過JavaMail API把資源附加到郵件消息上,并在您接收消息時獲取附件。

          點擊返回頂端->>>

          發(fā)送附件

                  發(fā)送附件與轉(zhuǎn)發(fā)消息非常相似,您要創(chuàng)建組成完整消息的各個部分。在創(chuàng)建好第一個部分即消息文本之后,您添加的用DataHandler類處理的其他部分就是您的附件,而不是轉(zhuǎn)發(fā)消息中的共享處理程序。當(dāng)您從一個文件讀取附件時,附件的數(shù)據(jù)資源是FileDataSource;從URL讀取時,則是 URLDataSource。一旦您有了自己的DataSource,在將其通過setDataHandler()方法最終附加到BodyPart上之前,只需將其傳遞給DataHandler類的構(gòu)造器即可。假定您想保留附件的原始文件名,要做的最后一件事就是用BodyPart類的 setFileName()方法設(shè)置與附件關(guān)聯(lián)的文件名。所有這些操作如下所示:

          // Define message
          Message message = new MimeMessage(session);
          message.setFrom(new InternetAddress(from));
          message.addRecipient(Message.RecipientType.TO,
          new InternetAddress(to));
          message.setSubject("Hello JavaMail Attachment");
          // Create the message part
          BodyPart messageBodyPart = new MimeBodyPart();
          // Fill the message
          messageBodyPart.setText("Pardon Ideas");
          Multipart multipart = new MimeMultipart();
          multipart.addBodyPart(messageBodyPart);
          // Part two is attachment
          messageBodyPart = new MimeBodyPart();
          DataSource source = new FileDataSource(filename);
          messageBodyPart.setDataHandler(new DataHandler(source));
          messageBodyPart.setFileName(filename);
          multipart.addBodyPart(messageBodyPart);
          // Put parts in message
          message.setContent(multipart);
          // Send the message
          Transport.send(message);

          在消息中包含附件時,如果您的程序是一個servlet,您的用戶就必須上傳附件,并告訴您要把消息發(fā)送到什么位置。上傳的每一個文件都可以用一個表單來處理,該表單是以multipart/表單數(shù)據(jù)(form-data)來編碼的。

          <FORM ENCTYPE="multipart/form-data"
          method=post action="/myservlet">
          <INPUT TYPE="file" /> <INPUT TYPE="submit" VALUE="Upload">
          </FORM>

          注意:消息的大小要受到您的SMTP服務(wù)器的限制,而不是由JavaMail API限制的。如果出現(xiàn)了問題,可以通過設(shè)置ms和mx參數(shù)來考慮增加Java堆區(qū)的空間尺寸。

          點擊返回頂端->>>

          獲取附件

                  從消息中取出附件比發(fā)送附件涉及的操作要稍微多一點,而MIME沒有簡單的附件概念。當(dāng)消息帶有附件時,消息的內(nèi)容就是一個Multipart對象。然后需要處理各個部分,以獲取主要內(nèi)容和附件。通過part.getDisposition()方法標(biāo)記上Part.ATTACHMENT配置的部分顯然就是附件。同時,附件也可以不帶有配置(和非文本MIME類型)或Part.INLINE配置。當(dāng)配置是Part.ATTACHMENT或 Part.INLINE時,您可以脫離該消息部分的內(nèi)容將其保存起來。只需通過getFileName()方法獲取原始文件名,并通過 getInputStream()方法獲取輸入流即可。

          Multipart mp = (Multipart)message.getContent();
          for (int i=0, n=multipart.getCount(); i<n; i++) {
          Part part = multipart.getBodyPart(i));
          String disposition = part.getDisposition();
          if ((disposition != null) &&
          ((disposition.equals(Part.ATTACHMENT) ||

          (disposition.equals(Part.INLINE))) {

          saveFile(part.getFileName(), part.getInputStream());
          }
          }

          saveFile()方法只用于根據(jù)文件名創(chuàng)建一個文件,從輸入流中讀取字節(jié),并將它們寫入一個文件中去。如果文件已存在,將在文件名后添加一個編號,直到找到一個不存在的文件為止。

          // from saveFile()

          File file = new File(filename);
          for (int i=0; file.exists(); i++) {
          file = new File(filename+i);
          }

          上面的代碼介紹了消息的各個部分被標(biāo)上相應(yīng)的標(biāo)志的一個最簡單的例子。要想包含所有的情況,還要對disposition值為null及消息部分為MIME類型的情況作相應(yīng)處理。

          if (disposition == null) {
          // Check if plain
          MimeBodyPart mbp = (MimeBodyPart)part;
          if (mbp.isMimeType("text/plain")) {
          // Handle plain
          } else {
          // Special non-attachment cases here of image/gif, text/html, ...
          }
          ...
          }

          點擊返回頂端->>>

          處理HTML消息

                  發(fā)送基于HTML的消息比發(fā)送純文本消息要稍微復(fù)雜一點,盡管它不需要做大量的工作。它全部取決于您特定的需求。

          發(fā)送HTML消息

          如果您所要做的全部工作是發(fā)送一個等價的HTML文件作為消息,并讓郵件閱讀者憂心于取出任何嵌入的圖片或相關(guān)片段,那么就可以使用消息的setContent()方法,以字符串形式傳遞消息內(nèi)容,并把內(nèi)容類型設(shè)置為text/html。

          String htmlText = "<H1>Hello</H1>" +
          "<img src=\"http://www.jguru.com/images/logo.gif\">";
          message.setContent(htmlText, "text/html"));

          在接收端,如果您用JavaMail API獲取消息,在該API中沒有內(nèi)置任何用于以HTML格式顯示消息的功能。JavaMail API只以字節(jié)流的形式來查看消息。要以HTML格式顯示消息,您必須使用Swing JeditorPane或某些第3方HTML閱讀器組件。

          if (message.getContentType().equals("text/html")) {
          String content = (String)message.getContent();
          JFrame frame = new JFrame();
          JEditorPane text = new JEditorPane("text/html", content);
          text.setEditable(false);
          JScrollPane pane = new JScrollPane(text);
          frame.getContentPane().add(pane);
          frame.setSize(300, 300);
          frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          frame.show();
          }

          點擊返回頂端->>>

          在消息中包含圖片

                  另一方面,如果您的HTML消息中嵌入了作為消息一部分的圖片,并且您想保持消息內(nèi)容的完整,就必須把圖片看作附件,并用特殊的通信標(biāo)識符URL引用該圖片,該通信標(biāo)識符引用的是圖片附件的內(nèi)容ID報文。

          嵌入圖片的處理與附加一個文件到消息上非常相似,惟一的不同之處在于:您必須區(qū)分MimeMultipart中,哪些部分是在構(gòu)造器(或通過 setSubType()方法)通過設(shè)置其子類型而使之相關(guān)的,以及將圖片的內(nèi)容ID報頭設(shè)置成任意字符串,它將在img標(biāo)記中用作圖片的源路徑。下面顯示了一個完整的示例:

          String file = ...;
          // Create the message
          Message message = new MimeMessage(session);
          // Fill its headers
          message.setSubject("Embedded Image");
          message.setFrom(new InternetAddress(from));
          message.addRecipient(Message.RecipientType.TO,
          new InternetAddress(to));
          // Create your new message part
          BodyPart messageBodyPart = new MimeBodyPart();
          String htmlText = "<H1>Hello</H1>" +
          "<img src=\"cid:memememe\">";
          messageBodyPart.setContent(htmlText, "text/html");
          // Create a related multi-part to combine the parts
          MimeMultipart multipart = new MimeMultipart("related");
          multipart.addBodyPart(messageBodyPart);
          // Create part for the image
          messageBodyPart = new MimeBodyPart();
          // Fetch the image and associate to part
          DataSource fds = new FileDataSource(file);
          messageBodyPart.setDataHandler(new DataHandler(fds));
          messageBodyPart.setHeader("Content-ID","memememe");
          // Add part to multi-part
          multipart.addBodyPart(messageBodyPart);
          // Associate multi-part with message
          message.setContent(multipart);

          點擊返回頂端->>>

          用SearchTerm搜索

                  JavaMail API包含一種可用于創(chuàng)建SearchTerm(搜索條件)的篩選機(jī)制,它可以在javax.mail.search包中找到。一旦創(chuàng)建了SearchTerm,您就可以詢問某個文件夾匹配的消息,并檢索出消息對象數(shù)組:

          SearchTerm st = ...;
          Message[] msgs = folder.search(st);

          有22種不同的類可用于幫助創(chuàng)建搜索條件。

          · AND條件(AndTerm類)

          · OR條件(OrTerm類)

          · NOT條件(NotTerm類)

          · SENT DATE條件(SentDateTerm類)

          · CONTENT條件(BodyTerm類)

          · HEADER條件(FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)

          本質(zhì)上,您可以為匹配的消息創(chuàng)建一個邏輯表達(dá)式,然后進(jìn)行搜索。例如,下面顯示了一條消息的條件搜索示例,該消息帶有(部分帶有)一個ADV主題字符串,其發(fā)送者字段為friend@public.com。您可能考慮定期運行該查詢,并自動刪除任何返回的消息。

          SearchTerm st =
          new OrTerm(
          new SubjectTerm("ADV:"),
          new FromStringTerm("friend@public.com"));
          Message[] msgs = folder.search(st);

          點擊返回頂端->>>

           



          杰森 
          郵箱:json.shen(at)gmail.com
          網(wǎng)站:www.shenjia.org
          posted on 2008-05-28 19:04 杰森 閱讀(622) 評論(3)  編輯  收藏 所屬分類: JavaEE

          評論:
          # re: JavaMail API 詳解 2008-05-29 08:20 | JAVA_START
          哈!寫得真不錯!有心了!  回復(fù)  更多評論
            
          # re: JavaMail API 詳解 2008-05-29 17:45 | 懶人
          真的好詳細(xì),謝謝樓主  回復(fù)  更多評論
            
          # re: JavaMail API 詳解 2008-05-31 16:47 | Jak.Shen
          @懶人
          多謝支持!  回復(fù)  更多評論
            
          嗨117
          主站蜘蛛池模板: 繁峙县| 碌曲县| 汽车| 忻城县| 江口县| 吴旗县| 峨眉山市| 藁城市| 阿瓦提县| 灌阳县| 青州市| 左权县| 丹巴县| 崇信县| 广丰县| 东城区| 三亚市| 霞浦县| 叶城县| 和林格尔县| 积石山| 邵阳县| 山丹县| 峨边| 清苑县| 仙游县| 泰宁县| 台江县| 崇州市| 尼木县| 略阳县| 德格县| 威远县| 宝丰县| 万年县| 海兴县| 米林县| 罗定市| 江陵县| 凌海市| 曲水县|