? 今天需要用javamail自動發郵件,結果測試結果一看,發現郵件發是發出去了,就是有一大堆的亂碼,這是郁悶
上網查了下,其實就是多設置一個小地方就可以咯,呵呵
? 看來自己功夫還不到家哦,要多多練習
?
package?email;

import?java.io.File;
import?java.io.FileNotFoundException;
import?java.util.Properties;
import?java.util.Scanner;

import?javax.mail.BodyPart;
import?javax.mail.Message;
import?javax.mail.MessagingException;
import?javax.mail.Session;
import?javax.mail.Transport;
import?javax.mail.internet.AddressException;
import?javax.mail.internet.InternetAddress;
import?javax.mail.internet.MimeBodyPart;
import?javax.mail.internet.MimeMessage;
import?javax.mail.internet.MimeMultipart;


public?class?MailSender?
{

????private?static?Properties?pro?=?new?Properties();


????static?
{
????????pro.put("mail.transport.protocol",?"smtp");
????????pro.put("mail.smtp.auth",?"true");
????????pro.put("mail.smtp.host",?"smtp.126.com");
????????pro.put("mail.host",?"126.com");

????}


????public?MailSender()?
{
????????super();
????????//?TODO?Auto-generated?constructor?stub
????}


????public?static?void?sendWelcomeMail(String?to)?
{

????????try?
{
????????????DyeracAuthenticator?authen?=?new?DyeracAuthenticator();
????????????Session?session?=?Session.getInstance(pro,?authen);
????????????Message?msg?=?new?MimeMessage(session);
????????????msg.setFrom(new?InternetAddress("opencampus@126.com"));
????????????msg.setSubject("歡迎注冊open-campus開源平臺");
????????????msg.setRecipients(Message.RecipientType.TO,?InternetAddress.parse(
????????????????????to,?false));
????????????File?mail=new?File("mail.txt");
????????????StringBuffer?buf=new?StringBuffer();

????????????try?
{
????????????????Scanner?s=new?Scanner(mail);

????????????????while(s.hasNextLine())
{
????????????????????buf.append(s.nextLine());
????????????????}

????????????}?catch?(FileNotFoundException?e)?
{
????????????????//?TODO?Auto-generated?catch?block
????????????????e.printStackTrace();
????????????}
????????????if(buf.length()<1)
????????????????buf.append("no?text");
????????????msg.setContent(buf.toString(),"text/html;charset=utf8");
????????????System.err.println(buf.toString());
????????????Transport.send(msg);

????????}?catch?(AddressException?ae)?
{
????????????//?TODO?Auto-generated?catch?block
????????????ae.printStackTrace();

????????}?catch?(MessagingException?me)?
{
????????????me.printStackTrace();
????????}
????}


????/**?*//**
?????*?@param?args
?????*/

????public?static?void?main(String[]?args)?
{
????????//?TODO?Auto-generated?method?stub
????????MailSender.sendWelcomeMail("dyerac@gmail.com");
????}

}

? 要設置的地方就是msg.setContent(buf.toString(),"text/html;charset=utf8");必須設置一個字符集,不然估計對方就會按默認的us-ascii來處理了吧
? 為了不浪費我在網上的搜索結果,我把別人寫的也轉在后面:
?
?? 可能顯得比較凌亂,sorry咯
LIST:
??? JavaMail API簡介
??? JavaMail 之 杜絕郵件亂碼
??? JavaMailAPI及其應用——一個郵件列表服務器的實現
??? JavaMail操作的總結
??? JavaMail的標題的中文問題最新版已經解決
??? JavaMail訪問Hotmail郵箱
??? Javamail中的常見中文亂碼問題與解決辦法
??? 使用javamail發送html郵件
--------------------------------------------------------------------------------------------------
javamai
原文:javamai
?
JavaMail API簡介
JavaMail API是一種可選的、能用于讀取、編寫和發送電子消息的包(標準擴展)。您可使用這種包創建郵件用戶代理(Mail User Agent ,MUA) 類型的程序,它類似于Eudora、Pine及Microsoft Outlook這些郵件程序。其主要目的不是像發送郵件或其他郵件傳輸代理(Mail Transfer Agent,MTA)類型的程序那樣用于傳輸、發送和轉發消息。換句話說,用戶可以與MUA類型的程序交互,以閱讀和撰寫電子郵件。MUA依靠MTA處理實際的發送任務。
JavaMail API的設計是,為收發信息提供與協議無關的訪問。方式是把該API劃分成兩個部分:
· 該API的第一個部分是本課程的重點。基本上是如何發送和接收獨立于提供程序/協議的消息。
· 第二個部分則使用特定的協議語言,如:SMTP、POP、IMAP和NNTP。如果要讓JavaMail API與服務器通信,就需要為之提供協議。由于Sun公司對特定協議提供程序有充分的介紹,用戶可以免費獲取,所以本課程沒有介紹創建特定協議提供程序的內容。
復習相關協議
在學習JavaMail API的深層知識之前,讓我們回過頭來看一看在該API中使用的協議,本質上有4種人們常用的協議:
· SMTP
· POP
· IMAP
· MIME
您還需要了解NNTP及其他一些協議。理解這些協議的基本原理有助于您理解如何使用JavaMail API。而該API的設計要與協議無關,所以不能克服這些基礎協議的限制。如果選用的協議不支持某種功能,那么JavaMail API也無法在其上添加這種功能。(正如您一會兒就會看到的,在操作POP協議時,常常會碰到這種問題)。
SMTP
簡單郵件傳輸協議(SMTP)是用于傳送電子郵件的機制。在JavaMail API環境中,您的基于JavaMail的程序將與您公司或Internet服務提供商(ISP)的SMTP服務器通信。該SMTP服務器將會把消息轉發給用作接收消息的SMTP服務器,最后用戶可通過POP或IMAP協議獲取該消息。由于支持身份驗證,所以不需要SMTP服務器是一種開放的轉發器,但需要確保SMTP服務器配置正確。JavaMail API中沒有集成用于處理諸如配置服務器以轉發消息或添加/刪除電子郵件帳戶這一類任務的功能。
POP
POP的含義是郵局協議,當前的版本為3,也稱作POP3,該協議是在RFC 1939中定義的。POP是Internet上的大多數人用來接收郵件的機制。它為每個用戶的每個郵箱定義支持,這是它所做的全部工作,也是大多數問題的根源。在使用POP協議時,人們熟悉的很多功能,如查看收到了多少新郵件消息的功能,POP根本不支持。這些功能都內置到諸如Eudora或Microsoft Outlook之類的郵件程序中,能為您記住接收的上一封郵件,以及計算有多少新郵件這類信息。因此,使用JavaMail API時,如果想獲取這類信息,將需要由自己進行計算。
IMAP
IMAP是用于接收消息的更加高級的協議,它是在RFC 2060中定義的。IMAP的含義是“Internet消息訪問協議”,當前版本是第4版,也稱作IMAP4。使用IMAP時,您的郵件服務器必須支持該協議。您不能只是簡單地把程序轉變為支持IMAP,而不是支持POP,就指望能支持IMAP中的一切。假定您的郵件服務器支持IMAP,那么基于JavaMail的程序就可利用在服務器上擁有多個文件夾的用戶,并且這些文件夾可以被多個用戶共享的功能。
由于IMAP協議具有更高級的功能,您也許會想IMAP應該被每一個人使用,但事實不是這樣。因為IMAP會加重郵件服務器的負荷,它需要服務器接收新消息,發送消息給請求的用戶,并在多個文件夾中為每個用戶維護這些消息。而這要集中備份,因而長期下去用戶的文件夾會變得越來越大,當磁盤空間用光了時,每個人都會遭受損失。而使用POP協議時,已保存消息可以解除服務器的重負。
MIME
MIME的含義是“多用途的網際郵件擴充協議”。它不是一種郵件傳輸協議,相反,它定義傳輸的內容:消息的格式、附件等。許多文檔都定義了MIME協議,包含:RFC 822、RFC 2045、RFC 2046和RFC 2047。作為JavaMail API的用戶,一般不需要擔心這些格式。但是,這些格式確實存在,并為您的程序所用。
NNP和其他協議
由于JavaMail API分開了提供程序和其他部分,所以您可以輕松地為附加協議添加支持。Sun公司提供第3方提供程序清單,這些提供程序要利用 Sun公司不支持的少見的協議。在這份清單中,您將會看到對NNTP(網絡新聞傳輸協議)[新聞組]、S/MIME(安全多用途的網際郵件擴充協議)及其他協議的提供支持的第3方提供程序。
安裝
目前有兩種版本的JavaMail API最常用:1.2和1.1.3。本課程中的所有例子都適用于這兩種版本。其中JavaMail API 1.2是最新的,而JavaMail API 1.1.3中包含了Java 2企業版(J2EE)平臺1.2.1版,所以它仍然很常用。使用JavaMail API的版本會對您的下載和安裝產生一些影響。這兩種版本的JavaMail API都能與JDK 1.1.6、Java 2標準版(J2SE)平臺1.2.x和1.3.x協同工作。
注意:在安裝了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服務器,需要下載并安裝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激活框架),這種框架提供了對輸入任意數據塊的支持,并能相應地對其進行處理。看上去效果好像不太好,但該框架是在當今的許多瀏覽器和郵件工具中可以找到的基本MIME類型支持。下載該框架后,解壓縮jaf1_0_1.zip文件,并將activation.jar文件添加到典型安裝路徑下。
對于JavaMail 1.2用戶,現在應該把mail.jar和activation.jar文件添加到典型安裝路徑下。
對于JavaMail 1.1.3用戶,現在應該把mail.jar、pop3.jar和activation.jar添加到典型安裝路徑下。如果您不打算使用POP3,就不需要把pop3.jar文件添加到典型安裝路徑下。
如果您不想更改安裝路徑環境變量,可以把JAR文件復制到Java運行時環境(JRE)目錄下的lib/ext目錄下。例如,對于J2SE 1.3版本,Windows平臺上的默認目錄應該是C:\jdk1.3\jre\lib\ext。
使用Java 2企業版
如果您使用的是J2EE,則在使用基本JavaMail API時,不需要做什么特殊的工作;JavaMail API帶有J2EE類。只要確保j2ee.jar文件位于典型安裝路徑下,并完成了所有的設置工作。
對于J2EE 1.2.1,POP3提供程序是單獨提供的,因此需要下載該提供程序,并按安裝JavaMail 1.1.3的步驟,在J2EE 1.2.1中包含POP3提供程序。J2EE 1.3的用戶會獲得J2EE和POP3提供程序,因而不需要對POP3提供程序執行獨立安裝。使用這兩種版本的J2EE用戶,都不需要安裝JavaBeans Activation Framework。
練習
設置您的 JavaMail 環境。
復習核心類
在開始深入研究JavaMail類之前,首先讓用戶瀏覽一下構成API的核心類:會話、消息、地址、驗證程序、傳輸,存儲和文件夾。所有這些類都可以在JavaMail API即javax.mail的頂層包中找到,盡管您將頻繁地發現您自己使用的子類是在javax.mail.internet包中找到的。
Session類
Session類定義了一個基本的郵件會話。通過該會話可讓別的工作順利執行。Session對象利用java.util.Properties對象獲取諸如郵件服務器、用戶名、密碼等信息,以及其他可在整個應用程序中共享的信息。
Session類的構造器是私有的。您可以獲得一個可被getDefaultInstance()方法共享的單一的默認會話:
Properties props = new Properties();
// fill props with any information
Session session = Session.getDefaultInstance(props, null);
或者,您可以用getInstance()方法創建一個獨特的會話:
Properties props = new Properties();
// fill props with any information
Session session = Session.getInstance(props, null);
這兩種情形下的null參數都是一種Authenticator對象,它不是在此時使用的。詳細信息請參閱其后的“Autherticator”一節。
在大多數情況下,使用共享會話就足夠了,即使為多個用戶郵箱處理郵件會話也是如此。您可以在通信過程的后面一步添加上用戶名和密碼的組合,并保持所有的一切是獨立的。
Message類
一旦創建了自己的Session對象,就是該去創建要發送的消息的時候了。這時就要用到消息類型。作為一個抽象類,您必須操作一個子類,在大多數情況下,該子類是javax.mail.internet.MimeMessage。一個MimeMessage是一種理解MIME類型和報頭(在不同的RFC文檔中均有定義)的消息。消息的報頭被嚴格限制成只能使用US-ASCII字符,盡管非ASCII字符可以被編碼到某些報頭字段中。
可以通過將Session對象傳遞給MimeMessage構造器的方法來創建消息:
MimeMessage message = new MimeMessage(session);
注意:還有其他的構造器,像用于創建消息的源于RFC822格式化的輸入流的構造器。
一旦創建了消息,就可以設置其各個部分,如Message(消息)實現Part(部分)接口(以MimeMessage實現MimePart)。設置內容的基本機制是setContent()方法,它帶有表示內容和MIME類型的參數:
message.setContent("Hello", "text/plain");
但是,如果正在使用 MimeMessage,并且您的消息是純文本,那么您就可以使用setText()方法。該方法只需要一個表示實際內容的參數,默認的MIME類型為純文本:
message.setText("Hello");
對于純文本消息,setText()方法更常常被用來設置內容。要發送其他類型的消息,如HTML消息,就要使用setContent方法()。現在用的更多的是HTML消息。
要設置主題,可以使用setSubject()方法:
message.setSubject("First");
Address類
一旦創建了會話和消息,并為消息填充了內容,就需要用Address類為您的信件標上地址了。同Message類一樣,Address類也是一種抽象類。您可以使用javax.mail.internet.InternetAddress類。
要創建只帶有電子郵件地址的地址,可以把電子郵件地址傳遞給Address類的構造器:
Address address = new InternetAddress("president@whitehouse.gov");
如果想讓一個名字出現在電子郵件地址后,也可以將其傳遞給構造器:
Address address = new InternetAddress("president@whitehouse.gov", "George Bush");
您要為消息的from(發送者)字段和to(接收者)字段創建地址對象。除非您的郵件服務器阻止這樣做,否則要在發送的消息中注明該消息的發送者。
一旦創建好了地址,有兩種方法可讓您將地址與消息連接起來。為了鑒別發送者,您可以使用setFrom()和setReplyTo()方法。
message.setFrom(address)
如果您的消息需要顯示多個地址來源,則可以使用addFrom()方法:
Address address[] = ...;
message.addFrom(address);
為了鑒別消息接收者,您可以使用addRecipient()方法。該方法除了需要一個地址參數外,還需要一個Message.RecipientType屬性(消息的接收類型)。
message.addRecipient(type, address)
地址的3種預定義類型如下:
· Message.RecipientType.TO
· Message.RecipientType.CC
· Message.RecipientType.BCC
因此,如果一條消息將發送給副總統,同時還將發送該消息的副本給第一夫人,則采用下面的代碼:
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沒有提供檢查電子郵件地址有效性的機制。您可以自己編寫支持掃描有效字符(在RFC 822文檔中所定義的)的程序或檢驗MX(郵件交換)記錄,這些都超越了JavaMail API的范圍。
Authenticator類
與java.net類一樣,JavaMail API可以利用Authenticator(驗證程序)類通過用戶名和密碼來訪問受保護的資源。對于JavaMail API來說,這種受保護的資源是指郵件服務器。JavaMail的Authenticator類可以在javax.mail包中找到,并有別于同名的java.net類。當JavaMail API在Java 1.1下工作時,JavaMail和java.net不會共享同一個Authenticator類名稱,這是因為Java 1.1中不含有java.net。
要使用Authenticator類,您可以使用該抽象類的子類,并通過getPasswordAuthentication()方法返回一個PasswordAuthentication實例。在創建時,您必須用會話記錄Authentication類。其后,當需要進行身份驗證時,會通知您的Authenticator。會彈出一個窗口,或從一個配置文件(盡管不加密就不安全)中讀取用戶名和密碼,并把它們作為一個PasswordAuthentication對象返回給調用程序。
Properties props = new Properties();
// fill props with any information
Authenticator auth = new MyAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
Transport類
發送消息的最后一步操作是使用Transport類。該類使用特定于協議(通常是SMTP)的語言來發送消息。它是一個抽象類,其操作與Session類有些相似。您可以通過只調用靜態的send()方法來使用該類的默認版本:
Transport.send(message);
或者,您可以從用于您的協議的會話中獲取一個特定的實例,然后傳遞用戶名和密碼(不必要時可以為空)并發送消息,最后關閉連接:
message.saveChanges(); // implicit with send()
Transport transport = session.getTransport("smtp");
transport.connect(host, username, password);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
當您需要發送多個消息時,建議采用后一種方法,因為它將保持消息間活動服務器的連接。而基本的send()機制會為每一個方法調用都建立一條獨立的連接。
注意:要查看經過郵件服務器郵件命令,可以用session.setDebug(true)方法設置調試標志。
Store和Folder類
使用Session類來獲取消息,開始時與發送消息很相似。但是,在獲取會話后,很有可能使用用戶名和密碼或Authenticator類來連接Store類。與Transport類一樣,您要告訴Store類將使用什么協議:
// 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協議,惟一可用的文件夾是INBOX。如果使用的是IMAP協議,則可以使用其他的文件夾。
注意:Sun公司的提供程序本來想提供方便。而Message message[]=folder.getMessages();這條語句卻是一種從服務器逐條讀取消息的緩慢操作,所以僅當您確實需要獲取消息部分(該內容是所檢索消息的內容)時可以使用這條語句。
一旦讀取消息,就可以使用getContent()方法獲取其內容,或使用writeTo()方法將其內容寫到一個流中。getContent()方法只獲取消息內容,而writeTo()方法則還會輸出報頭。
System.out.println(((MimeMessage)message).getContent());
一旦您閱讀完郵件,就可以關閉對文件夾和存儲的連接。
folder.close(aBoolean);
store.close();
傳遞給文件夾的close()方法的布爾變量指定了是否通過清除已刪除的消息來更新文件夾。
繼續前進
實際上,理解使用這7個類的方式,是使用JavaMail API處理幾乎所有事情所需要的全部內容。用這7個類以外的方式構建的JavaMail API,其大多數功能都是以幾乎完全相同或特定的方式來執行任務的,就好像內容是附件。特定的任務,如:搜索、隔離等將在后面進行介紹。
使用JavaMail API
您已經看到了如何操作JavaMail API的核心部分。在下面幾節中,您將學習如何連接幾個部分以執行特定的任務。
發送消息
發送電子郵件消息涉及到獲取會話、創建和填充消息并發送消息這些操作。您可以在獲取Session時,通過為要傳遞的Properties對象設置mail.smtp.host屬性來指定您的SMTP服務器。
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);
您應該在try-catch塊中編寫代碼,以在創建消息并發送它時可以拋出一個異常。
練習
發送您的第一個消息
獲取消息
對于閱讀郵件來說,首先您要獲取一個會話,然后獲取并連接到一個相應的用于您的收件箱的存儲上,接著打開相應的文件夾,再獲取消息。同時,不要忘記了操作完成后關閉連接。
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();
每一條消息執行何種操作取決于自己決定。上面的代碼塊只是顯示了消息的發送者和主題。從技術上講,發送者地址列表可以為空,此時getFrom()[0]調用會拋出一個異常。
為了顯示整條消息,您可以提示用戶在看完消息的發送者和主題字段后,如果想看到消息的內容,可以再調用消息的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;
}
}
練習
檢查郵件
刪除消息和標志
刪除消息涉及到操作與消息關聯的標志。對不同的狀態有不同的標志,有些標志是系統定義的,有些則是由用戶定義的。預定義的標志都是在內部類Flags.Flag中定義的,如下所示:
· Flags.Flag.ANSWERED
· Flags.Flag.DELETED
· Flags.Flag.DRAFT
· Flags.Flag.FLAGGED
· Flags.Flag.RECENT
· Flags.Flag.SEEN
· Flags.Flag.USER
僅僅因為標志存在,并不表示標志為所有的郵件服務器/提供程序所支持。例如,除了刪除消息外,POP協議對它們都不支持。檢查新郵件不是POP的任務,但它已內置到郵件客戶程序中。要搞清楚什么標志受到支持,可以使用getPermanentFlags()方法來詢問文件夾。
要刪除消息,需要為消息設置DELETE標志:
message.setFlag(Flags.Flag.DELETED, true);
第一次以READ_WRITE(讀-寫)模式打開文件夾:
folder.open(Folder.READ_WRITE);
然后,處理完了所有的消息,請關閉文件夾,并傳遞true值以擦去刪除的消息。
folder.close(true);
用戶可使用Folder類的expunge()方法來刪除消息。但是,該方法對Sun公司的POP3提供程序不起作用。其他提供程序或許能也或許不能實現其功能。它更有可能適用于IMAP提供程序。由于POP只支持對收件箱的簡單訪問,使用Sun公司的提供程序時,您將不得不關閉文件夾以刪除消息。
要移去標志,只需傳遞一個false值給setFlag()方法。要看看是否設置了某個標志,可以使用isSet()進行檢查。
自我驗證
先前學到的是使用Authenticator類,以在需要時提示輸入用戶名和密碼,而不是以字符串的形式傳入它們。這里,您將真正看到如何更加充分地使用驗證。
不需使用主機、用戶名和密碼連接到Store,您可以配置Properties帶有主機,并告訴Session關于您自定義的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對象。下面是這種實現的一個例子,其中一個字段同時適用于兩部分內容。它不是一個Project Swing指南,只是在一個字段中輸入了兩部分內容,它們是用逗號隔開的。
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的事件處理線程。這在本質上要求您在代碼中添加一個對System.exit()的調用,以終止程序的執行。
回復消息
Message類包含一個reply()方法,以用正確的接收者和主題(添加“Re::”,如果沒有的話)配置一條新消息。該方法不會為消息添加任何內容,只是為新的接收者復制發送者或回復到的報頭。該方法使用一個布爾型參數,提示是否只回復給發送者(false)或回復給所有人(true)。
MimeMessage reply = (MimeMessage)message.reply(false);
reply.setFrom(new InternetAddress("president@whitehouse.gov"));
reply.setText("Thanks");
Transport.send(reply);
在發送消息時要配置回復到地址,可使用setReplyTo()方法。
練習
回復郵件
轉發消息
轉發消息涉及的內容要稍微多一點,沒有一個專門用于轉發消息的方法,您可以通過處理組成消息的各個部分來創建要轉發的消息。
一條郵件消息可由多個部分組成,每一部分是一個BodyPart(報文部分),或更特殊一點,在操作MIME消息時則是MimeBodyPart。不同的報文部分組合到一個稱為Multipart的容器中,或者又更特殊一點,是一個MimeMultipart容器。要轉發消息,您要創建一個用于消息文本的部分,和用于要轉發的消息的第二個部分,并將這兩個部分組合成一個multipart(多個部分)。然后您可以把這個multipart添加到一個合適的注明地址的消息中并發送它。
這就是轉發消息的本質。要把一條消息的內容復制給另一條消息,只需通過它的DataHandler類復制即可,它是出自于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);
操作附件
附件是與郵件消息關聯的資源,通常保存在消息之外,如:一個文本文件,電子表格或圖片。對于像Eudora和Pine之類的常用郵件程序,您可以通過JavaMail API把資源附加到郵件消息上,并在您接收消息時獲取附件。
發送附件
發送附件與轉發消息非常相似,您要創建組成完整消息的各個部分。在創建好第一個部分即消息文本之后,您添加的用DataHandler類處理的其他部分就是您的附件,而不是轉發消息中的共享處理程序。當您從一個文件讀取附件時,附件的數據資源是FileDataSource;從URL讀取時,則是URLDataSource。一旦您有了自己的DataSource,在將其通過setDataHandler()方法最終附加到BodyPart上之前,只需將其傳遞給DataHandler類的構造器即可。假定您想保留附件的原始文件名,要做的最后一件事就是用BodyPart類的setFileName()方法設置與附件關聯的文件名。所有這些操作如下所示:
// 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,您的用戶就必須上傳附件,并告訴您要把消息發送到什么位置。上傳的每一個文件都可以用一個表單來處理,該表單是以multipart/表單數據(form-data)來編碼的。
<FORM ENCTYPE="multipart/form-data"
method=post action="/myservlet">
<INPUT TYPE="file" NAME="thefile">
<INPUT TYPE="submit" VALUE="Upload">
</FORM>
注意:消息的大小要受到您的SMTP服務器的限制,而不是由JavaMail API限制的。如果出現了問題,可以通過設置ms和mx參數來考慮增加Java堆區的空間尺寸。
練習
發送附件
獲取附件
從消息中取出附件比發送附件涉及的操作要稍微多一點,而MIME沒有簡單的附件概念。當消息帶有附件時,消息的內容就是一個Multipart對象。然后需要處理各個部分,以獲取主要內容和附件。通過part.getDisposition()方法標記上Part.ATTACHMENT配置的部分顯然就是附件。同時,附件也可以不帶有配置(和非文本MIME類型)或Part.INLINE配置。當配置是Part.ATTACHMENT或Part.INLINE時,您可以脫離該消息部分的內容將其保存起來。只需通過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()方法只用于根據文件名創建一個文件,從輸入流中讀取字節,并將它們寫入一個文件中去。如果文件已存在,將在文件名后添加一個編號,直到找到一個不存在的文件為止。
// from saveFile()
File file = new File(filename);
for (int i=0; file.exists(); i++) {
file = new File(filename+i);
}
上面的代碼介紹了消息的各個部分被標上相應的標志的一個最簡單的例子。要想包含所有的情況,還要對disposition值為null及消息部分為MIME類型的情況作相應處理。
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消息
發送基于HTML的消息比發送純文本消息要稍微復雜一點,盡管它不需要做大量的工作。它全部取決于您特定的需求。
發送HTML消息
如果您所要做的全部工作是發送一個等價的HTML文件作為消息,并讓郵件閱讀者憂心于取出任何嵌入的圖片或相關片段,那么就可以使用消息的setContent()方法,以字符串形式傳遞消息內容,并把內容類型設置為text/html。
String htmlText = "<H1>Hello</H1>" +
"<img src=http://www.chinaitpower.com/"message.setContent(htmlText, "text/html"));
在接收端,如果您用JavaMail API獲取消息,在該API中沒有內置任何用于以HTML格式顯示消息的功能。JavaMail API只以字節流的形式來查看消息。要以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消息中嵌入了作為消息一部分的圖片,并且您想保持消息內容的完整,就必須把圖片看作附件,并用特殊的通信標識符URL引用該圖片,該通信標識符引用的是圖片附件的內容ID報文。
嵌入圖片的處理與附加一個文件到消息上非常相似,惟一的不同之處在于:您必須區分MimeMultipart中,哪些部分是在構造器(或通過setSubType()方法)通過設置其子類型而使之相關的,以及將圖片的內容ID報頭設置成任意字符串,它將在img標記中用作圖片的源路徑。下面顯示了一個完整的示例:
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);
練習
發送帶有圖片的 HTML 消息
用SearchTerm搜索
JavaMail API包含一種可用于創建SearchTerm(搜索條件)的篩選機制,它可以在javax.mail.search包中找到。一旦創建了SearchTerm,您就可以詢問某個文件夾匹配的消息,并檢索出消息對象數組:
SearchTerm st = ...;
Message[] msgs = folder.search(st);
有22種不同的類可用于幫助創建搜索條件。
· AND條件(AndTerm類)
· OR條件(OrTerm類)
· NOT條件(NotTerm類)
· SENT DATE條件(SentDateTerm類)
· CONTENT條件(BodyTerm類)
· HEADER條件(FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)
本質上,您可以為匹配的消息創建一個邏輯表達式,然后進行搜索。例如,下面顯示了一條消息的條件搜索示例,該消息帶有(部分帶有)一個ADV主題字符串,其發送者字段為friend@public.com。您可能考慮定期運行該查詢,并自動刪除任何返回的消息。
SearchTerm st =
new OrTerm(
new SubjectTerm("ADV:"),
new FromStringTerm("friend@public.com"));
Message[] msgs = folder.search(st);
?
CNBIE BLOG
--------------------------------------------------------------------------------
JavaMail API簡介
原文:JavaMail API簡介
JavaMail API簡介
JavaMail API是一種可選的、能用于讀取、編寫和發送電子消息的包(標準擴展)。您可使用這種包創建郵件用戶代理(Mail User Agent ,MUA) 類型的程序,它類似于Eudora、Pine及Microsoft Outlook這些郵件程序。其主要目的不是像發送郵件或其他郵件傳輸代理(Mail Transfer Agent,MTA)類型的程序那樣用于傳輸、發送和轉發消息。換句話說,用戶可以與MUA類型的程序交互,以閱讀和撰寫電子郵件。MUA依靠MTA處理實際的發送任務。
JavaMail API的設計是,為收發信息提供與協議無關的訪問。方式是把該API劃分成兩個部分:
· 該API的第一個部分是本課程的重點。基本上是如何發送和接收獨立于提供程序/協議的消息。
· 第二個部分則使用特定的協議語言,如:SMTP、POP、IMAP和NNTP。如果要讓JavaMail API與服務器通信,就需要為之提供協議。由于Sun公司對特定協議提供程序有充分的介紹,用戶可以免費獲取,所以本課程沒有介紹創建特定協議提供程序的內容。
復習相關協議
在學習JavaMail API的深層知識之前,讓我們回過頭來看一看在該API中使用的協議,本質上有4種人們常用的協議:
· SMTP
· POP
· IMAP
· MIME
您還需要了解NNTP及其他一些協議。理解這些協議的基本原理有助于您理解如何使用JavaMail API。而該API的設計要與協議無關,所以不能克服這些基礎協議的限制。如果選用的協議不支持某種功能,那么JavaMail API也無法在其上添加這種功能。(正如您一會兒就會看到的,在操作POP協議時,常常會碰到這種問題)。
SMTP
簡單郵件傳輸協議(SMTP)是用于傳送電子郵件的機制。在JavaMail API環境中,您的基于JavaMail的程序將與您公司或Internet服務提供商(ISP)的SMTP服務器通信。該SMTP服務器將會把消息轉發給用作接收消息的SMTP服務器,最后用戶可通過POP或IMAP協議獲取該消息。由于支持身份驗證,所以不需要SMTP服務器是一種開放的轉發器,但需要確保SMTP服務器配置正確。JavaMail API中沒有集成用于處理諸如配置服務器以轉發消息或添加/刪除電子郵件帳戶這一類任務的功能。
POP
POP的含義是郵局協議,當前的版本為3,也稱作POP3,該協議是在RFC 1939中定義的。POP是Internet上的大多數人用來接收郵件的機制。它為每個用戶的每個郵箱定義支持,這是它所做的全部工作,也是大多數問題的根源。在使用POP協議時,人們熟悉的很多功能,如查看收到了多少新郵件消息的功能,POP根本不支持。這些功能都內置到諸如Eudora或Microsoft Outlook之類的郵件程序中,能為您記住接收的上一封郵件,以及計算有多少新郵件這類信息。因此,使用JavaMail API時,如果想獲取這類信息,將需要由自己進行計算。
IMAP
IMAP是用于接收消息的更加高級的協議,它是在RFC 2060中定義的。IMAP的含義是“Internet消息訪問協議”,當前版本是第4版,也稱作IMAP4。使用IMAP時,您的郵件服務器必須支持該協議。您不能只是簡單地把程序轉變為支持IMAP,而不是支持POP,就指望能支持IMAP中的一切。假定您的郵件服務器支持IMAP,那么基于JavaMail的程序就可利用在服務器上擁有多個文件夾的用戶,并且這些文件夾可以被多個用戶共享的功能。
由于IMAP協議具有更高級的功能,您也許會想IMAP應該被每一個人使用,但事實不是這樣。因為IMAP會加重郵件服務器的負荷,它需要服務器接收新消息,發送消息給請求的用戶,并在多個文件夾中為每個用戶維護這些消息。而這要集中備份,因而長期下去用戶的文件夾會變得越來越大,當磁盤空間用光了時,每個人都會遭受損失。而使用POP協議時,已保存消息可以解除服務器的重負。
MIME
MIME的含義是“多用途的網際郵件擴充協議”。它不是一種郵件傳輸協議,相反,它定義傳輸的內容:消息的格式、附件等。許多文檔都定義了MIME協議,包含:RFC 822、RFC 2045、RFC 2046和RFC 2047。作為JavaMail API的用戶,一般不需要擔心這些格式。但是,這些格式確實存在,并為您的程序所用。
NNP和其他協議
由于JavaMail API分開了提供程序和其他部分,所以您可以輕松地為附加協議添加支持。Sun公司提供第3方提供程序清單,這些提供程序要利用 Sun公司不支持的少見的協議。在這份清單中,您將會看到對NNTP(asp.cn/ class=wordstyle>網絡新聞傳輸協議)[新聞組]、S/MIME(安全多用途的網際郵件擴充協議)及其他協議的提供支持的第3方提供程序。
安裝
目前有兩種版本的JavaMail API最常用:1.2和1.1.3。本課程中的所有例子都適用于這兩種版本。其中JavaMail API 1.2是最新的,而JavaMail API 1.1.3中包含了Java 2企業版(J2EE)平臺1.2.1版,所以它仍然很常用。使用JavaMail API的版本會對您的下載和安裝產生一些影響。這兩種版本的JavaMail API都能與JDK 1.1.6、Java 2標準版(J2SE)平臺1.2.x和1.3.x協同工作。
注意:在安裝了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服務器,需要下載并安裝POP3提供程序。Sun公司擁有
CNBIE BLOG
--------------------------------------------------------------------------------
JavaMail 之 杜絕郵件亂碼
原文:JavaMail 之 杜絕郵件亂碼
??????? 我一直想不通,RFC822 標準都發布多少年了,為什么還有那么多不符合規范的email 出現呢?一來也許是服務器的問題,二來就是不負責任的程序員的錯了。所以我突然意識到,不是只有冷血無情的老板和咄咄逼人的客戶讓程序員的身心飽受摧殘,同行的不經意或經意也在加劇著傷害。
??????? 我面對著一份郵件原文發出以上的感慨,客戶抱怨該郵件收到的時候在系統中正文顯示是亂碼。這是一份典型的不合規范的郵件:? Content-Type : text/plain ,沒有說明 charset,而接下來的正文直接就是未進行任何編碼的中文文字。不過 Subject 卻是符合規范的(=?gb2312?B?xxxxxxx?=)。
??????? 行行色色的不合規范的郵件見過不少,最常見的就是某些header未編碼,還有的可能就是,Body編碼了而Subject 未編碼,最討厭的就是整份Email都沒有編碼信息。
??????? 恨歸恨,問題還是得解決,我修改了代碼,處理邏輯如下:
??????? 1. 在最開始解析郵件的時候,先解析某些可能帶有編碼信息的header,并記錄為 headerCharset;部分代碼如下:
??? private static Pattern encodeStringPattern = Pattern.compile("=\\?(.+)\\?(B|Q)\\?(.+)\\?=", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
??? private final String[] CHARTSET_HEADER = new String[] { "Subject", "From", "To", "Cc", "Delivered-To" };
??? ..........
??? Enumeration enum = message.getMatchingHeaderLines(CHARTSET_HEADER);
??????????? while (enum.hasMoreElements()) {
??????????????? String header = (String) enum.nextElement();
??????????????? Matcher m = encodeStringPattern.matcher(header);
??????????????? if (m.find()) {
??????????????????? this.headCharset = m.group(1);
??????????????????? log.debug("guess mail charset is " + this.headCharset);
??????????????????? break;
??????????????? }
??????????? }
??????? 2. 接著解析郵件體,找到 Body 的時候,看看是否指明 charset 信息;如果指定了,記錄為 bodyCharset;如果沒有,使用 headerCharset,如果 headerCharset 也是 null,使用默認charset。通常是 ISO-8859-1。
??????? 3. 最后再處理郵件 header,如果沒有charset 信息,使用 bodyCharset,否則使用默認charset。
???????
??????? 以上的解決方案,只要郵件的Body或者Header中的一個提供了編碼信息,那么都可能可以避免亂碼的產生,如果哪份遭千殺的郵件,Body 用 gb2312 編碼,Subject 卻是未編碼的日文,那我只能長嘆被擊敗了。如果整份郵件都沒有編碼信息的話,除非你確定郵件都是指定的編碼并進行轉碼,否則只有聽天由命。
???????
??????? 最后還是要呼吁一聲,請遵循規范!
CNBIE BLOG
--------------------------------------------------------------------------------
JavaMailAPI及其應用——一個郵件列表服務器的實現(三)(轉貼)
原文:JavaMailAPI及其應用——一個郵件列表服務器的實現(三)(轉貼)
?
相關資源
1.Java Mail API軟件包下載(版本1.1.2)
ftp://usmt.java.sun.com/pub/javamail/tyo39/javamail1_1_2.zip
缺省POP3實現軟件包下載:
ftp://usmt.java.sun.com/pub/javamial/tyo39/pop31_1.zip
以上文件也可以從Sun的Java Mail API主頁下載
http://java.sun.com/products/javamail/
2.JavaBeans Activation Framework(JAF)主頁
http://java.sun.com/beans/glasgow/jaf.html
3.用Java Mail API開發的第三方產品列表,部分可以下載源代碼
http://java.sun.com/products/javamail/Third_Party.html
4.Java meets e-mail
http://www.developer.com/journal/techworkshop/112498_jmail.html
5.Cutting Edge Java Technology: The JavaMail API
http://www.sigs.com/
6.訂閱由Sun維護的關于Java Mail API的郵件列表
發信給listserv@java.sun.com,內容:
subscribe javamail-interest
??
CNBIE BLOG
--------------------------------------------------------------------------------
JavaMail操作的總結(2)
原文:JavaMail操作的總結(2)
?
//此段代碼用來進行服務器對用戶的認證
public class Email_Autherticator extends Authenticator
{
public Email_Autherticator()
{
super();
}
public PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(username,password);
}
}
//該程序為接收郵件
void jButton2_actionPerformed(ActionEvent e) {
try
{
Properties props = System.getProperties(); //獲取系統變量
Authenticator auth = new Email_Autherticator();
props.put("mail.smtp.host",host);
props.put("mail.smtp.auth","true");
Session session = Session.getDefaultInstance(props,auth); //建立session
Store store = session.getStore("pop3");
store.connect(host,username,password);
//After connecting to the Store,you can get a Folder,which must be opened before you can read messages from it:
Folder folder = store.getFolder("INBOX");//連接到Store后,取得一個文件夾,一般默認的是INDEX
folder.open(Folder.READ_WRITE);//READ_ONLY為打開方式
Message message[] = folder.getMessages();//從文件夾獲取郵件信息
//可以用兩種方式去獲得郵件信息,getContent()用來獲得郵件的主體信息。而WriteTo()可以用來獲得郵件的全部信息,包括頭部信息
// System.out.println(((MimeMessage)message).getContent());
for (int i=0,n=message.length;i {
String out_from_person = ((InternetAddress)message[i].getFrom()[0]).getPersonal();
String out_from_address = ((InternetAddress)message[i].getFrom()[0]).getAddress();
System.out.println("From:"+out_from_person+" ");
System.out.println("Address:"+out_from_address+" ");
String out_subject = message[i].getSubject();
System.out.println("Subject:"+out_subject+" ");
//以下代碼用來獲得郵件的正文信息
Part messagePart = message[i];
Object out_content = messagePart.getContent();
if (out_content instanceof Multipart)
{
messagePart = ((Multipart)out_content).getBodyPart(0);
System.out.println("[ Multipart Message ]");
}
String out_content_type = messagePart.getContentType();
System.out.println("CONTENT:"+out_content_type);
if (out_content_type.startsWith("text/plain") | | out_content_type.startsWith("text/html"))
{
InputStream ipstm = messagePart.getInputStream();
BufferedReader bufreader = new BufferedReader(new InputStreamReader(ipstm));
String thisLine = bufreader.readLine();
while (thisLine != null)
{
System.out.println("thisLine: "+thisLine);
thisLine = bufreader.readLine();
}
}
System.out.println("------------------------------------------------------------");
message[i].setFlag(Flags.Flag.DELETED,true);//最后刪除服務器端的郵件
}
//DELETED,ANSWERED,DRAFT,FLAGGED,RECENT,SEEN,USER
folder.close(true);//true的話,徹底刪除已經標記為DELETE的郵件,如果為false的話,就不刪除
store.close();//關閉
}
catch(Exception ej2)
{
System.out.println(ej2);
}
}
void jButton4_actionPerformed(ActionEvent e) {
try
{//該程序為回復郵件
Properties props = System.getProperties(); //獲取系統變量
Authenticator auth = new Email_Autherticator(); //取得?uFFFD衿魅現?
props.put("mail.smtp.host",host);
props.put("mail.smtp.auth","true");
Session session = Session.getDefaultInstance(props,auth); //建立session
Store store = session.getStore("pop3");
store.connect(host,username,password);
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
Message message[] = folder.getMessages();
for (int i=0,n=message.length;i {
// String out_from_person = ((InternetAddress)message[i].getFrom()[0]).getPersonal();//獲取郵件發信人的署名
String out_from_address = ((InternetAddress)message[i].getFrom()[0]).getAddress();
System.out.println(out_from_address);
Message forward = new MimeMessage(session);
forward.setSubject("Fwd:"+message[i].getSubject());
forward.setFrom(new InternetAddress(mail_to));
forward.addRecipient(Message.RecipientType.TO,new InternetAddress(out_from_address));
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText("Here you go with the original message: ");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(message[i].getDataHandler());
multipart.addBodyPart(messageBodyPart);
forward.setContent(multipart);
Transport.send(forward);
message[i].setFlag(Flags.Flag.DELETED,true);//DELETED,ANSWERED,DRAFT,FLAGGED,RECENT,SEEN,USER
}
folder.close(true);
store.close();//關閉
}
catch(Exception ej2)
{
System.out.println(ej2);
}
}
void jButton5_actionPerformed(ActionEvent e) {
try
{
Properties props = new Properties();
Authenticator auth = new Email_Autherticator();
props.put("mail.smtp.host",host);
props.put("mail.smtp.auth","true");
Session session = Session.getDefaultInstance(props,auth);
MimeMessage message = new MimeMessage(session);
message.setContent("Hello","text/plain");
message.setSubject(mail_subject);
message.setText(mail_body);
message.setHeader(mail_head_name,mail_head_value);
message.setSentDate(new Date());
message.setFrom(new InternetAddress(mail_from,"sunxiaoming")); //to signal man ?
CNBIE BLOG
--------------------------------------------------------------------------------
JavaMail的標題的中文問題最新版已經解決
原文:JavaMail的標題的中文問題最新版已經解決
記得老版本的標題(發送/接收)中有中文會出現編碼的問題,現在用新的JavaMail版本沒有這個問題了。
另外如果內容為HTML的話,一般要設置編碼為GBK,即在addPart的時候要addPart(part, "text/html; charset=\"GBK\"");asp?id=34339" width="1" height="1">
?
CNBIE BLOG
--------------------------------------------------------------------------------
JavaMail訪問Hotmail郵箱
原文:JavaMail訪問Hotmail郵箱
?
相信許多人都有MSN聊天工具的帳號,例如abc@hotmail.com ,這個賬號其實也是一個郵件地址,可以進行正常的郵件收發功能,你可以通過網址 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","abc@hotmail.com");
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("abc@hotmail.com");
txMsg.setFrom(addrFrom);
//郵件接收者地址
InternetAddress addrTo = new InternetAddress("cdef@hotmail.com", "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 跟我交流在使用中遇到的問題。
CNBIE BLOG
--------------------------------------------------------------------------------
JavaMail郵件主題亂碼的解決方法
原文:JavaMail郵件主題亂碼的解決方法
很多朋友都使用過JavaMail進行郵件發送,在郵件正文中的亂碼容易解決。但郵件主題的亂碼無論怎樣轉碼總是顯示一堆亂碼。到底應該怎么處理
?
CNBIE BLOG
--------------------------------------------------------------------------------
JavaMail之杜絕郵件亂碼
原文:JavaMail之杜絕郵件亂碼
?
??????? 我一直想不通,RFC822 標準都發布多少年了,為什么還有那么多不符合規范的email 出現呢?一來也許是服務器的問題,二來就是不負責任的程序員的錯了。所以我突然意識到,不是只有冷血無情的老板和咄咄逼人的客戶讓程序員的身心飽受摧殘,同行的不經意或經意也在加劇著傷害。
??????? 我面對著一份郵件原文發出以上的感慨,客戶抱怨該郵件收到的時候在系統中正文顯示是亂碼。這是一份典型的不合規范的郵件:? Content-Type : text/plain ,沒有說明 charset,而接下來的正文直接就是未進行任何編碼的中文文字。不過 Subject 卻是符合規范的(=?gb2312?B?xxxxxxx?=)。
??????? 行行色色的不合規范的郵件見過不少,最常見的就是某些header未編碼,還有的可能就是,Body編碼了而Subject 未編碼,最討厭的就是整份Email都沒有編碼信息。
??????? 恨歸恨,問題還是得解決,我修改了代碼,處理邏輯如下:
??????? 1. 在最開始解析郵件的時候,先解析某些可能帶有編碼信息的header,并記錄為 headerCharset;部分代碼如下:
??? private static Pattern encodeStringPattern = Pattern.compile("=\\?(.+)\\?(B|Q)\\?(.+)\\?=", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
??? private final String[] CHARTSET_HEADER = new String[] { "Subject", "From", "To", "Cc", "Delivered-To" };
??? ..........
??? Enumeration enum = message.getMatchingHeaderLines(CHARTSET_HEADER);
??????????? while (enum.hasMoreElements()) {
??????????????? String header = (String) enum.nextElement();
??????????????? Matcher m = encodeStringPattern.matcher(header);
??????????????? if (m.find()) {
??????????????????? this.headCharset = m.group(1);
??????????????????? log.debug("guess mail charset is " + this.headCharset);
??????????????????? break;
??????????????? }
??????????? }
??????? 2. 接著解析郵件體,找到 Body 的時候,看看是否指明 charset 信息;如果指定了,記錄為 bodyCharset;如果沒有,使用 headerCharset,如果 headerCharset 也是 null,使用默認charset。通常是 ISO-8859-1。
??????? 3. 最后再處理郵件 header,如果沒有charset 信息,使用 bodyCharset,否則使用默認charset。
???????
??????? 以上的解決方案,只要郵件的Body或者Header中的一個提供了編碼信息,那么都可能可以避免亂碼的產生,如果哪份遭千殺的郵件,Body 用 gb2312 編碼,Subject 卻是未編碼的日文,那我只能長嘆被擊敗了。如果整份郵件都沒有編碼信息的話,除非你確定郵件都是指定的編碼并進行轉碼,否則只有聽天由命。
???????
??????? 最后還是要呼吁一聲,請遵循規范!
?
Javamail中的常見中文亂碼問題與解決辦法(綜合)
JSP教程-Java技巧及代碼
在使用javamail api開發郵件服務系統時,我們常常會碰到很多中文亂碼問題,下面就分別介紹如何解決這些問題。
1.發送名稱含中文的附件到郵件服務器,用別的郵件接收程序接收到的附件名顯示為亂碼
解決辦法:
在調用MimeBodyPart的setFileName()時使用Base64編碼。例如:
BASE64Encoder enc = new BASE64Encoder();//該類位于jre/lib/rt.jar中
//fds為FileDataSource實例
mbp.setFileName("=?GBK?B?"+enc.encode((fds.getName()).getByte ())+"?=");
2.接收郵件時,獲取某些郵件發送程序發送的email地址,發送地址顯示為亂碼
解決辦法:
對含有中文的發送地址,使用MimeUtility.decodeTex方法,對其他則把地址從ISO8859_1編碼轉換成gbk編碼,見下例
public static String getFrom(Message msg){
??? String from="";
??? try{
????? if(msg.getFrom()[0]!=null)
??????? from=msg.getFrom()[0].toString();
????? if(from.startsWith("=?GB")||from.startWith(“=?gb”)){
??????? from=MimeUtility.decodeText(from);
????? }else{
??????? from=StringUtil.toChinese(from);
????? }
??? }catch(Exception e){
????? e.printStackTrace();
??? }
??? from=StringUtil.replaceStr(from,“<”,“<”);// replaceStr為字符串替換函數
??? from=StringUtil.replaceStr(from,">",">");
??? return from;
? }
///////////////////StringUtil的toChinese方法//////////////////////////
public static String toChinese(String strvalue){
??? try{
????? if(strvalue==null)
??????? return null;
????? else{
??????? strvalue = new String(strvalue.getBytes("ISO8859_1"), "GBK");
??????? return strvalue;
????? }
??? }catch(Exception e){
????? return null;
??? }
? }
3.接收郵件時,獲取某個郵件的中文附件名,出現亂碼
解決辦法:
對于用base64編碼過的中文,則采用base64解碼,否則對附件名進行ISO8859_1到gbk的編碼轉換,例如:
String temp=part.getFileName();//part為Part實例
if((temp.startsWith("=?GBK?B?")&&temp.endsWith("?="))
?? ||(temp.startsWith("=?gbk?b?")&&temp.endsWith("?="))){
??? temp=StringUtil.getFromBASE64(temp.substring(8,temp.indexOf("?=")-1));
}else{
??? temp=StringUtil.toChinese(temp);//該方法如前所敘
}
/////////////StringUtil的getFromBASE64方法/////////?
public static String getFromBASE64(String s) {
??? if (s == null) return null;
??? BASE64Decoder decoder = new BASE64Decoder();
??? try {
????? byte[] b = decoder.decodeBuffer(s);
????? return new String(b);
??? } catch (Exception e) {
????? return null;
??? }
? }
?
亂碼問題的調試步驟總結:
基本上在javamail中碰到的中文亂碼問題就這么多了,如果你的程序出現了中文亂碼,首先不要驚慌,可用多個其他的郵件發送或接收程序進行驗證,看是在哪個環節出現了問題,然后再仔細對照原文和亂碼,調用相應的編碼解碼方法就行了。
?
------------------------------------------------------------------------------------------------------------------
使用javamail發送html郵件比較復雜
package org.tatan.mail;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import javax.mail.Session;
import javax.mail.MessagingException;
import javax.mail.Transport;
public class SendHtmlMail {
??? public static void sendMessage(String smtpHost,
?????????????????????????????????? String from, String to,
?????????????????????????????????? String subject, String messageText)
??????????? throws MessagingException,java.io.UnsupportedEncodingException {
??????? // Step 1:? Configure the mail session
??????? System.out.println("Configuring mail session for: " + smtpHost);
??????? java.util.Properties props = new java.util.Properties();
??????? props.setProperty("mail.smtp.auth", "true");//指定是否需要SMTP驗證
??????? props.setProperty("mail.smtp.host", smtpHost);//指定SMTP服務器
??????? props.put("mail.transport.protocol", "smtp");
??????? Session mailSession = Session.getDefaultInstance(props);
??????? mailSession.setDebug(true);//是否在控制臺顯示debug信息
??????? // Step 2:? Construct the message
??????? System.out.println("Constructing message -? from=" + from + "? to=" + to);
??????? InternetAddress fromAddress = new InternetAddress(from);
??????? InternetAddress toAddress = new InternetAddress(to);
??????? MimeMessage testMessage = new MimeMessage(mailSession);
??????? testMessage.setFrom(fromAddress);
??????? testMessage.addRecipient(javax.mail.Message.RecipientType.TO, toAddress);
??????? testMessage.setSentDate(new java.util.Date());
??????? testMessage.setSubject(MimeUtility.encodeText(subject,"gb2312","B"));
??????? testMessage.setContent(messageText, "text/html;charset=gb2312");
??????? System.out.println("Message constructed");
??????? // Step 3:? Now send the message
??????? Transport transport = mailSession.getTransport("smtp");
??????? transport.connect(smtpHost, "webmaster", "password");
??????? transport.sendMessage(testMessage, testMessage.getAllRecipients());
??????? transport.close();
??????? System.out.println("Message sent!");
??? }
??? public static void main(String[] args) {
??????? String smtpHost = "localhost";
??????? String from = "webmaster@mymail.com";
??????? String to = "mfc42d@sohu.com";
??????? String subject = "html郵件測試"; //subject javamail自動轉碼
??????? StringBuffer theMessage = new StringBuffer();
??????? theMessage.append("<h2><font color=red>這倒霉孩子</font></h2>");
??????? theMessage.append("<hr>");
??????? theMessage.append("<i>年年失望年年望</i>");
??????? try {
??????????? SendHtmlMail.sendMessage(smtpHost, from, to, subject, theMessage.toString());
??????? }
??????? catch (javax.mail.MessagingException exc) {
??????????? exc.printStackTrace();
??????? }
??????? catch (java.io.UnsupportedEncodingException exc) {
??????????? exc.printStackTrace();
??????? }
??? }
}
郵件頭(參見RFC822,RFC2047)只能包含US-ASCII字符。
郵件頭中任何包含非US-ASCII字符的部分必須進行編碼,使其只包含US-ASCII字符。
但是java mail可以根據JVM發送中文郵件自行編碼,,用它自帶的MimeUtility類的encodeText方法對中文信息進行編碼也可以。
郵件正文必須有charset=gb2312否則為
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit
打開郵件為亂碼,設置charset=gb2312后
Content-Type: text/html;charset=gb2312
Content-Transfer-Encoding: quoted-printable
它不能用MimeUtility里的方法來編碼。
郵件正文的編碼方式的信息是要放在Content-Transfer-Encoding這個郵件頭參數中的,
而MimeUtility里面的方法是將編碼方式的信息放在編碼后的正文內容中。
所以如果你對正文也用MimeUtility進行處理,那么其他郵件程序就不會正常顯示你編碼的郵件,
因為其他郵件軟件如outlook,foxmail只會根據Content-Transfer-Encoding這個里面的信息來對郵件正文進行解碼。