posts - 78,  comments - 48,  trackbacks - 0
          第一件我們需要知道的事情是,通用電子郵件庫(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)單的電子郵件開始講解,我們將提出所有的設(shè)置放到一個(gè)單獨(dú)的靜態(tài)類MailSettings當(dāng)中,這樣做將在比較代碼的時(shí)候容易些。

               在發(fā)送電子郵件之前,您還需要知道SMTP服務(wù)器的主機(jī)名,SMTP服務(wù)器是負(fù)責(zé)將您的郵件發(fā)送到外部世界去的機(jī)器。

               JavaMail使用了Session類的概念來(lái)保存諸如SMTP主機(jī)和認(rèn)證的信息,主要想法是基于會(huì)話(Sessions)在Java虛擬機(jī)中可以被隔離,這可以阻止惡意代碼竊取其他用戶在其他會(huì)話中的信息,這些信息可能包括用戶名和密碼等認(rèn)證信息。“但是”,您可能會(huì)說(shuō),“在同一時(shí)間,我只在Java虛擬機(jī)上運(yùn)行一個(gè)應(yīng)用程序,而且我相信我的代碼。”JavaMail的目的是開發(fā)大型的郵件系統(tǒng),它有一個(gè)具有復(fù)雜性的關(guān)聯(lián)層,您可以繞過(guò)沒有經(jīng)驗(yàn)的用戶,我們用以下的例子來(lái)說(shuō)明:

          Properties props=new Properties();
          props.put("mail.smtp.host",MailSettings.smtpHost);
          Session session=Session.getDefaultInstance(props,null);

               此處,并沒有創(chuàng)建新的會(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ì)話,現(xiàn)在我們可以使用這個(gè)會(huì)話來(lái)創(chuàng)建郵件消息了。

          Message message=new MimeMessage(session);

               JavaMail中有一個(gè)Message類,各種各樣的消息都是它的子類,如果查看了JavaMail的API,您會(huì)發(fā)現(xiàn)它只有一個(gè)子類:MimeMessage。JavaMail是被設(shè)計(jì)為通用的電子郵件框架的,所以顯然存在冗余的抽象。總之,我們已經(jīng)使用會(huì)話創(chuàng)建了一個(gè)MimeMessage,現(xiàn)在我們需要來(lái)填充這個(gè)消息。

          message.setFrom(new InternetAddress (MailSettings.fromAddress, MailSettings.fromName));

               再次利用抽象,JavaMail有一個(gè)Address(地址)類,其他所有的地址類型皆源于此,但是我們現(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è)定接收器和接收器的類型,從此處開始,至少純文本的電子郵件可以穩(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類的調(diào)用將會(huì)去查找適當(dāng)?shù)臅?huì)話,并找出如何發(fā)送消息,盡管這樣做看上去有些不直觀。當(dāng)我們完成這一步的時(shí)候,我們的郵件就已經(jīng)發(fā)送出去了。此時(shí),我們還需要添加代碼來(lái)捕獲三種JavaMail可能拋出的異常,它們是AddressException、MessagingException和UnsupportedEncodingException. 但這就是最基本的使用JavaMail發(fā)送郵件的方法。

               現(xiàn)在,讓我們來(lái)看看如何使用Apache的通用電子郵件軟件包(參見MailCommons.java)來(lái)完成同樣的工作,通用電子郵件庫(kù)是一系列類的集合,它們基于您所要發(fā)送的郵件類型,其中最簡(jiǎn)單的是SimpleEmail類,不需要建立任何會(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ā)送接收器的類型:

          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ì)話管理,事情變得非常簡(jiǎn)單并且代碼更容易閱讀。

               當(dāng)然,這是我們所能發(fā)送的最簡(jiǎn)單的電子郵件,我們假設(shè)SMTP服務(wù)器不需要認(rèn)證,我們發(fā)送的郵件只有一個(gè)收件人,并沒有發(fā)送郵件副本。讓我們先來(lái)看看認(rèn)證,SMTP認(rèn)證(SMTP AUTH)需要用戶名和密碼來(lái)發(fā)送郵件,在JavaMail中(參見MailJavaMail2.java),需要?jiǎng)?chuàng)建一個(gè)認(rèn)證者(Authenticator)來(lái)返回所需的認(rèn)證證書:

          class ForcedAuthenticator extends Authenticator {
          public PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication(MailSettings.smtpUsername,
          MailSettings.smtpPassword);
          }
          }

               當(dāng)我們創(chuàng)建會(huì)話的時(shí)候,就給出這個(gè)認(rèn)證者的一個(gè)實(shí)例。

          Session session=Session.getDefaultInstance(props,new ForcedAuthenticator());

               然而,這里有一點(diǎn)要注意,這種做法將默認(rèn)的會(huì)話綁定到了該認(rèn)證者,因此您需要一個(gè)指向它的引用(reference)以再次取得這個(gè)會(huì)話。當(dāng)然,您也可以轉(zhuǎn)而使用Session.getInstance(),來(lái)創(chuàng)建一個(gè)唯一的不共享的實(shí)例,但是這將依靠您自己來(lái)管理會(huì)話的實(shí)例。

               現(xiàn)在讓我們來(lái)看看如果使用通用電子郵件庫(kù)的方法來(lái)進(jìn)行認(rèn)證(參見MailCommons2.java),您將只看到一行新的語(yǔ)句:

          email.setAuthentication(MailSettings.smtpUsername,MailSettings.smtpPassword);這就解決了認(rèn)證過(guò)程的所有痛苦。

               還有另外一種認(rèn)證方式,那就是使用在郵件服務(wù)中的POP-before-SMTP,它并沒有實(shí)現(xiàn)SMTP AUTH,其實(shí)SMTP AUTH是SMTP之后的一種擴(kuò)展,而POP-before-SMTP的工作方式則是將受密碼控制的郵件接收者和發(fā)送郵件的能力進(jìn)行綁定,只有當(dāng)用戶經(jīng)過(guò)POP協(xié)議訪問(wèn)某個(gè)受密碼保護(hù)的POP郵件服務(wù)器一段時(shí)間之后,此用戶才能夠發(fā)送郵件。在JavaMail中,為了發(fā)送郵件,你需要編寫打開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類有一個(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)建和添加收件人列表變得輕松。(參見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消息中,我們需要完成以下步驟(參見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)容類型,注意,在我們?cè)O(shè)置的HTML代碼中,IMG標(biāo)簽指向了一個(gè)內(nèi)容標(biāo)識(shí)符(content-id),這就是MIME(多用途互聯(lián)網(wǎng)郵件擴(kuò)充協(xié)議)消息部分的名稱,該消息將含有GIF格式的標(biāo)識(shí)圖文件,為了嵌入這個(gè)圖片,我們創(chuàng)建了另一個(gè)BodyPart和一個(gè)JAF的數(shù)據(jù)源(data source),JAF類庫(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ù)方法的版本(參見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)電子郵件客戶端不能處理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的客戶端所顯示的文字,然后我們就可以發(fā)送郵件了。

               但是,到目前為止,您可能正在想“直接使用JavaMail的意義是什么呢?”答案是,如果您的目的是發(fā)送電子郵件,那么對(duì)于大多數(shù)情況,通用電子郵件庫(kù)僅僅需要少量的復(fù)雜代碼就可以完成您的需求,但是它連一點(diǎn)控制郵件會(huì)話和接收郵件的功能都沒有,如果您的應(yīng)用軟件不需要大規(guī)模地進(jìn)行郵件轉(zhuǎn)換或郵件閱讀的操作,那么應(yīng)該不會(huì)造成不便。當(dāng)然,如果您需要進(jìn)行上述操作,那您就已經(jīng)在使用JavaMail庫(kù)了。這里唯一的一個(gè)警告就是,在我寫這篇文章之時(shí),通用電子郵件庫(kù)發(fā)布的是1.0版本,其API中可能有一些缺陷和漏洞,但它確實(shí)可以工作。現(xiàn)在您應(yīng)該沒有借口不讓您的應(yīng)用軟件在工作的時(shí)候發(fā)送狀態(tài)郵件了。

          您可以下載這篇文章的源代碼

          查看本文的國(guó)際來(lái)源

          posted on 2006-03-02 10:54 黑咖啡 閱讀(540) 評(píng)論(0)  編輯  收藏 所屬分類: tec

          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          留言簿(2)

          隨筆分類(67)

          文章分類(43)

          Good Article

          Good Blogs

          Open Source

          最新隨筆

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 北海市| 利川市| 晴隆县| 蓝山县| 沂水县| 长顺县| 禄丰县| 且末县| 石泉县| 咸丰县| 宁阳县| 齐齐哈尔市| 斗六市| 礼泉县| 资兴市| 迁安市| 嘉峪关市| 中山市| 勃利县| 清水县| 中方县| 阿克陶县| 青岛市| 昭通市| 特克斯县| 鞍山市| 泌阳县| 乌拉特中旗| 平山县| 泰和县| 湖南省| 南乐县| 南华县| 曲靖市| 琼结县| 宜阳县| 石狮市| 塘沽区| 精河县| 沾化县| 车致|