第一件我們需要知道的事情是,通用電子郵件庫(kù)實(shí)際上是包裹在JavaMail外層的API,所以無(wú)論我們選擇哪種API,我們都需要
JavaMail庫(kù)。您可能還需要JavaBeans激活框架(
JavaBeans Activation Framework (JAF)),該框架將負(fù)責(zé)處理關(guān)于郵件選項(xiàng)的更復(fù)雜的內(nèi)容。最后一個(gè)在“購(gòu)物列表”上的就是通用電子郵件庫(kù)(
Commons Email),您需要從JAF中將JavaMail庫(kù)中的mail.jar、JAF中的activation.jar和通用電子郵件庫(kù)中的commons-email-1.0.jar添加到classpath的設(shè)置中。
我們現(xiàn)在已經(jīng)擁有了支持部件的工具包,讓我們從使用JavaMail發(fā)送簡(jiǎn)單的電子郵件開(kāi)始講解,我們將提出所有的設(shè)置放到一個(gè)單獨(dú)的靜態(tài)類(lèi)MailSettings當(dāng)中,這樣做將在比較代碼的時(shí)候容易些。
在發(fā)送電子郵件之前,您還需要知道SMTP服務(wù)器的主機(jī)名,SMTP服務(wù)器是負(fù)責(zé)將您的郵件發(fā)送到外部世界去的機(jī)器。
JavaMail使用了Session類(lèi)的概念來(lái)保存諸如SMTP主機(jī)和認(rèn)證的信息,主要想法是基于會(huì)話(huà)(Sessions)在Java虛擬機(jī)中可以被隔離,這可以阻止惡意代碼竊取其他用戶(hù)在其他會(huì)話(huà)中的信息,這些信息可能包括用戶(hù)名和密碼等認(rèn)證信息。“但是”,您可能會(huì)說(shuō),“在同一時(shí)間,我只在Java虛擬機(jī)上運(yùn)行一個(gè)應(yīng)用程序,而且我相信我的代碼。”JavaMail的目的是開(kāi)發(fā)大型的郵件系統(tǒng),它有一個(gè)具有復(fù)雜性的關(guān)聯(lián)層,您可以繞過(guò)沒(méi)有經(jīng)驗(yàn)的用戶(hù),我們用以下的例子來(lái)說(shuō)明:
Properties props=new Properties();
props.put("mail.smtp.host",MailSettings.smtpHost);
Session session=Session.getDefaultInstance(props,null);
此處,并沒(méi)有創(chuàng)建新的會(huì)話(huà),您只是從會(huì)話(huà)工廠(session factory)中得到并通過(guò)Properties的實(shí)例來(lái)進(jìn)行設(shè)置,我們只對(duì)SMTP主機(jī)進(jìn)行了設(shè)置和傳送,在得到默認(rèn)的實(shí)例的同時(shí)創(chuàng)建了一個(gè)共享的會(huì)話(huà),現(xiàn)在我們可以使用這個(gè)會(huì)話(huà)來(lái)創(chuàng)建郵件消息了。
Message message=new MimeMessage(session);
JavaMail中有一個(gè)Message類(lèi),各種各樣的消息都是它的子類(lèi),如果查看了JavaMail的API,您會(huì)發(fā)現(xiàn)它只有一個(gè)子類(lèi):MimeMessage。JavaMail是被設(shè)計(jì)為通用的電子郵件框架的,所以顯然存在冗余的抽象。總之,我們已經(jīng)使用會(huì)話(huà)創(chuàng)建了一個(gè)MimeMessage,現(xiàn)在我們需要來(lái)填充這個(gè)消息。
message.setFrom(new InternetAddress (MailSettings.fromAddress, MailSettings.fromName));
再次利用抽象,JavaMail有一個(gè)Address(地址)類(lèi),其他所有的地址類(lèi)型皆源于此,但是我們現(xiàn)在只關(guān)心發(fā)送國(guó)際互聯(lián)網(wǎng)的電子郵件,所以我們制造一個(gè)InternetAddress,這個(gè)地址用來(lái)表示電子郵件的來(lái)源和一個(gè)用于顯示的“個(gè)人”名字。現(xiàn)自我們來(lái)設(shè)置郵件將發(fā)向何方。
message.setRecipient(Message.RecipientType.TO, new InternetAddress(MailSettings.toAddress));
地址的抽象將再次出現(xiàn),我們?cè)O(shè)定接收器和接收器的類(lèi)型,從此處開(kāi)始,至少純文本的電子郵件可以穩(wěn)定地傳送了,我們只需要設(shè)定郵件的標(biāo)題、信文并打上時(shí)間戳。
message.setSubject(MailSettings.messageSubject);
message.setText(MailSettings.messageBody1);
message.setSentDate(new Date());
此時(shí),我們已經(jīng)準(zhǔn)備好發(fā)送消息了。
Transport.send(message);
這個(gè)對(duì)Transport類(lèi)的調(diào)用將會(huì)去查找適當(dāng)?shù)臅?huì)話(huà),并找出如何發(fā)送消息,盡管這樣做看上去有些不直觀。當(dāng)我們完成這一步的時(shí)候,我們的郵件就已經(jīng)發(fā)送出去了。此時(shí),我們還需要添加代碼來(lái)捕獲三種JavaMail可能拋出的異常,它們是AddressException、MessagingException和UnsupportedEncodingException. 但這就是最基本的使用JavaMail發(fā)送郵件的方法。
現(xiàn)在,讓我們來(lái)看看如何使用Apache的通用電子郵件軟件包(參見(jiàn)MailCommons.java)來(lái)完成同樣的工作,通用電子郵件庫(kù)是一系列類(lèi)的集合,它們基于您所要發(fā)送的郵件類(lèi)型,其中最簡(jiǎn)單的是SimpleEmail類(lèi),不需要建立任何會(huì)話(huà)或?qū)傩粤斜恚?/P>
SimpleEmail email=new SimpleEmail();
email.setHostName(MailSettings.smtpHost);
以上代碼創(chuàng)建了我們的郵件并指定它通過(guò)我們選定的SMTP服務(wù)器發(fā)送,因?yàn)橥ㄓ秒娮余]件庫(kù)只處理國(guó)際互聯(lián)網(wǎng)的電子郵件,所以就不必在創(chuàng)建InternetAddress實(shí)例上浪費(fèi)時(shí)間了,我們可以簡(jiǎn)單地設(shè)定來(lái)源地址:
email.setFrom(MailSettings.fromAddress,MailSettings.fromName);
我們只需要添加一個(gè)地址到收信人列表當(dāng)中,而不是發(fā)送接收器的類(lèi)型:
email.addTo(MailSettings.toAddress);
同樣,設(shè)定郵件的標(biāo)題和信文與發(fā)送郵件都很簡(jiǎn)單。
email.setSubject(MailSettings.messageSubject);
email.setMsg(MailSettings.messageBody1);
email.send();
我們所需要去捕獲的異常只有EmailException這一種,所以,您應(yīng)該可以看出通過(guò)隱藏所有的框架和會(huì)話(huà)管理,事情變得非常簡(jiǎn)單并且代碼更容易閱讀。
當(dāng)然,這是我們所能發(fā)送的最簡(jiǎn)單的電子郵件,我們假設(shè)SMTP服務(wù)器不需要認(rèn)證,我們發(fā)送的郵件只有一個(gè)收件人,并沒(méi)有發(fā)送郵件副本。讓我們先來(lái)看看認(rèn)證,SMTP認(rèn)證(SMTP AUTH)需要用戶(hù)名和密碼來(lái)發(fā)送郵件,在JavaMail中(參見(jiàn)MailJavaMail2.java),需要?jiǎng)?chuàng)建一個(gè)認(rèn)證者(Authenticator)來(lái)返回所需的認(rèn)證證書(shū):
class ForcedAuthenticator extends Authenticator {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(MailSettings.smtpUsername,
MailSettings.smtpPassword);
}
}
當(dāng)我們創(chuàng)建會(huì)話(huà)的時(shí)候,就給出這個(gè)認(rèn)證者的一個(gè)實(shí)例。
Session session=Session.getDefaultInstance(props,new ForcedAuthenticator());
然而,這里有一點(diǎn)要注意,這種做法將默認(rèn)的會(huì)話(huà)綁定到了該認(rèn)證者,因此您需要一個(gè)指向它的引用(reference)以再次取得這個(gè)會(huì)話(huà)。當(dāng)然,您也可以轉(zhuǎn)而使用Session.getInstance(),來(lái)創(chuàng)建一個(gè)唯一的不共享的實(shí)例,但是這將依靠您自己來(lái)管理會(huì)話(huà)的實(shí)例。
現(xiàn)在讓我們來(lái)看看如果使用通用電子郵件庫(kù)的方法來(lái)進(jìn)行認(rèn)證(參見(jiàn)MailCommons2.java),您將只看到一行新的語(yǔ)句:
email.setAuthentication(MailSettings.smtpUsername,MailSettings.smtpPassword);這就解決了認(rèn)證過(guò)程的所有痛苦。
還有另外一種認(rèn)證方式,那就是使用在郵件服務(wù)中的POP-before-SMTP,它并沒(méi)有實(shí)現(xiàn)SMTP AUTH,其實(shí)SMTP AUTH是SMTP之后的一種擴(kuò)展,而POP-before-SMTP的工作方式則是將受密碼控制的郵件接收者和發(fā)送郵件的能力進(jìn)行綁定,只有當(dāng)用戶(hù)經(jīng)過(guò)POP協(xié)議訪問(wèn)某個(gè)受密碼保護(hù)的POP郵件服務(wù)器一段時(shí)間之后,此用戶(hù)才能夠發(fā)送郵件。在JavaMail中,為了發(fā)送郵件,你需要編寫(xiě)打開(kāi)POP信箱的代碼,這將涉及JavaMail接收端的工作,我們將在下一篇文章中講解相關(guān)內(nèi)容;而對(duì)于通用電子郵件庫(kù)來(lái)講,事情就容易得多了:
email.setPopBeforeSMTP(true,popHost,popUsername,popPassword);
這使您可以操作與POP-before-SMTP相關(guān)的所有功能,而根本不需要考慮處理與POP相關(guān)的工作。
讓我們?cè)賮?lái)看看如何設(shè)定郵件的抄送收件人,現(xiàn)在JavaMail的Message類(lèi)有一個(gè)setRecipients方法,該方法可以接受一個(gè)InternetAddress的數(shù)組,但這樣做并不精巧,如果您已經(jīng)有了一個(gè)儲(chǔ)存電子郵件地址的字符串?dāng)?shù)組,那就可以結(jié)束這種復(fù)雜方法的考驗(yàn)。
ArrayList ccs=new ArrayList();
for(String s:MailSettings.ccAddresses) ccs.add(new InternetAddress(s));
message.setRecipients(Message.RecipientType.CC,
(InternetAddress[]) ccs.toArray(new InternetAddress[ccs.size()]));
現(xiàn)在讓我們來(lái)看看通用電子郵件庫(kù),我們發(fā)現(xiàn)了兩件事情:首先,setTo、setCc和setBcc方法都使用了InternetAddress的集合作為它們的參數(shù),這樣做更符合Java的現(xiàn)行實(shí)踐;其次,addTo、addCc和addBcc方法將創(chuàng)建和添加收件人列表變得輕松。(參見(jiàn)MailCommons3.java)
for(String s:MailSettings.ccAddresses) email.addCc(s);
這樣的代碼更加清晰。
最后,讓我們來(lái)看看如何發(fā)送包含內(nèi)嵌圖片的HTML格式的電子郵件,在此,JavaBeans激活框架將與JavaMail將協(xié)同工作,來(lái)協(xié)助圖片的編碼。在JavaMail的API中,我們首先創(chuàng)建一個(gè)MimeMultipart的實(shí)例,然后創(chuàng)建MimeBodyParts的實(shí)例,并將它們組裝到MimeMultipart的實(shí)例中,所以,嵌入單個(gè)圖片,比如uk-builder-com.gif這個(gè)圖片文件,并將它顯示在HTML消息中,我們需要完成以下步驟(參見(jiàn)HtmlJavaMail.java)
MimeMultipart multipart=new MimeMultipart();
BodyPart msgBodyPart=new MimeBodyPart();
msgBodyPart.setContent("<H1>Hi! From HtmlJavaMail</H1>
<img src=\"cid:logo\">","text/html");
BodyPart embedImage=new MimeBodyPart();
DataSource ds=new URLDataSource(new URL(MailSettings.inlineImage));
embedImage.setDataHandler(new DataHandler(ds));
embedImage.setHeader("Content-ID","");
multipart.addBodyPart(msgBodyPart);
multipart.addBodyPart(embedImage);
message.setContent(multipart);
第一個(gè)BodyPart將它的內(nèi)容設(shè)置為一個(gè)字符串和“text/html”的內(nèi)容類(lèi)型,注意,在我們?cè)O(shè)置的HTML代碼中,IMG標(biāo)簽指向了一個(gè)內(nèi)容標(biāo)識(shí)符(content-id),這就是MIME(多用途互聯(lián)網(wǎng)郵件擴(kuò)充協(xié)議)消息部分的名稱(chēng),該消息將含有GIF格式的標(biāo)識(shí)圖文件,為了嵌入這個(gè)圖片,我們創(chuàng)建了另一個(gè)BodyPart和一個(gè)JAF的數(shù)據(jù)源(data source),JAF類(lèi)庫(kù)將負(fù)責(zé)管理內(nèi)容的工作;然后我們將使用這個(gè)DataSource在BodyPart上添加一個(gè)DataHandler(數(shù)據(jù)處理器),這樣就可以讀出我們的URL所指向的內(nèi)容了。最后,我們還要在BodyPart的頭部設(shè)定Content-ID,這樣它就可以作為內(nèi)嵌圖片被訪問(wèn)了。我們創(chuàng)建的那些BodyParts將被添加到MimeMultipart的實(shí)例中,為此,我們使用setContent()方法而不是調(diào)用setText()方法。最棘手的部分莫過(guò)于管理這些內(nèi)容標(biāo)識(shí)符了,我們?cè)诖酥煌瓿闪饲度胍粋€(gè)圖片的工作,但今后每添加一個(gè)圖片,您都需要在HTML中加入一個(gè)BodyPart和一個(gè)內(nèi)容標(biāo)識(shí)符。
現(xiàn)在讓我們來(lái)看看使用通用電子郵件庫(kù)方法的版本(參見(jiàn)HtmlMailCommons.java):
HtmlEmail email=new HtmlEmail();…
String cid=email.embed(new URL(MailSettings.inlineImage),"Builder AU Logo");
email.setHtmlMsg("<H1>Hi! From MailJavaMail3</H1><img src=\"cid:"+cid+"\">");
email.setTextMsg("Your email client does not support HTML messages, sorry");
這種方法簡(jiǎn)短了很多,而且這一版本擁有更多的功能:當(dāng)電子郵件客戶(hù)端不能處理HTML時(shí),它將顯示備用的文字。我們從創(chuàng)建一個(gè)SimpleEmail實(shí)例改變?yōu)閯?chuàng)建一個(gè)HtmlEmail實(shí)例。為了嵌入一個(gè)圖片,我們只需要簡(jiǎn)單地調(diào)用HtmlEmail的嵌入方法,這將返回一個(gè)字符串,該字符串含有被生成和管理的內(nèi)嵌圖片內(nèi)容標(biāo)識(shí)符的信息,我們可以直接使用這些信息來(lái)生成HTML內(nèi)容。我們只需要簡(jiǎn)單地對(duì)適當(dāng)?shù)淖址{(diào)用setHtmlMsg方法來(lái)進(jìn)行設(shè)定,setTextMsg將設(shè)定不支持HTML的客戶(hù)端所顯示的文字,然后我們就可以發(fā)送郵件了。
但是,到目前為止,您可能正在想“直接使用JavaMail的意義是什么呢?”答案是,如果您的目的是發(fā)送電子郵件,那么對(duì)于大多數(shù)情況,通用電子郵件庫(kù)僅僅需要少量的復(fù)雜代碼就可以完成您的需求,但是它連一點(diǎn)控制郵件會(huì)話(huà)和接收郵件的功能都沒(méi)有,如果您的應(yīng)用軟件不需要大規(guī)模地進(jìn)行郵件轉(zhuǎn)換或郵件閱讀的操作,那么應(yīng)該不會(huì)造成不便。當(dāng)然,如果您需要進(jìn)行上述操作,那您就已經(jīng)在使用JavaMail庫(kù)了。這里唯一的一個(gè)警告就是,在我寫(xiě)這篇文章之時(shí),通用電子郵件庫(kù)發(fā)布的是1.0版本,其API中可能有一些缺陷和漏洞,但它確實(shí)可以工作。現(xiàn)在您應(yīng)該沒(méi)有借口不讓您的應(yīng)用軟件在工作的時(shí)候發(fā)送狀態(tài)郵件了。
您可以下載這篇文章的源代碼
查看本文的國(guó)際來(lái)源
posted on 2006-03-02 10:54
黑咖啡 閱讀(539)
評(píng)論(0) 編輯 收藏 所屬分類(lèi):
tec