日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

JavaMail发送和接收邮件

發(fā)布時(shí)間:2024/4/17 java 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaMail发送和接收邮件 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、JavaMail概述:

?????? JavaMail是由Sun定義的一套收發(fā)電子郵件的API,不同的廠商可以提供自己的實(shí)現(xiàn)類。但它并沒有包含在JDK中,而是作為JavaEE的一部分。

?????? 廠商所提供的JavaMail服務(wù)程序可以有選擇地實(shí)現(xiàn)某些郵件協(xié)議,常見的郵件協(xié)議包括:

???????? SMTP:簡(jiǎn)單郵件傳輸協(xié)議,用于發(fā)送電子郵件的傳輸協(xié)議;

???????? POP3:用于接收電子郵件的標(biāo)準(zhǔn)協(xié)議;

???????? IMAP:互聯(lián)網(wǎng)消息協(xié)議,是POP3的替代協(xié)議。

這三種協(xié)議都有對(duì)應(yīng)SSL加密傳輸?shù)膮f(xié)議,分別是SMTPS,POP3S和IMAPS。

除JavaMail服務(wù)提供程序之外,JavaMail還需要JAF(JavaBeans Activation Framework)來處理不是純文本的郵件內(nèi)容,這包括MIME(多用途互聯(lián)網(wǎng)郵件擴(kuò)展)、URL頁(yè)面和文件附件等內(nèi)容。下圖描述了JavaMail的體系結(jié)構(gòu)。

?

?

mail.jar:此JAR文件包含JavaMail API和Sun提供的SMTP、IMAP和POP3服務(wù)提供程序;

activation.jar:此JAR文件包含JAF API和Sun的實(shí)現(xiàn)。

?

二、對(duì)相關(guān)協(xié)議的回顧:

?????? 1、介紹

?????? 在研究 JavaMail API 的細(xì)則之前,讓我們回顧用于 API 的協(xié)議。基本上,您會(huì)逐漸熟悉并喜愛的協(xié)議有四個(gè):

?

??? * SMTP

??? * POP

??? * IMAP

??? * MIME

?

您還將碰到 NNTP 和其它協(xié)議。理解所有協(xié)議的基本知識(shí)將有助于您理解如何使用 JavaMail API。雖然不了解這些協(xié)議您照樣可以用這個(gè) API,卻不能夠克服那些基礎(chǔ)協(xié)議的局限性。如果我們精選的協(xié)議不能支持某種性能,JavaMail API 決不能魔術(shù)般的將這種性能添加上去。(您很快就會(huì)看到,在處理 POP 時(shí)這將成為一個(gè)難題。)

??????

?????? 2SMTP

?????? 簡(jiǎn)單郵件傳輸協(xié)議(Simple Mail Transfer Protocol,SMTP)由 RFC 821 定義。它定義了發(fā)送電子郵件的機(jī)制。在 JavaMail API 環(huán)境中,您基于 JavaMail 的程序?qū)⒑湍墓净蛞蛱鼐W(wǎng)服務(wù)供應(yīng)商的(Internet Service Provider's,ISP's)SMTP 服務(wù)器通信。SMTP 服務(wù)器會(huì)中轉(zhuǎn)消息給接收方 SMTP 服務(wù)器以便最終讓用戶經(jīng)由 POP 或 IMAP 獲得。這不是要求 SMTP 服務(wù)器成為開放的中繼,盡管 SMTP 服務(wù)器支持身份驗(yàn)證,不過還是得確保它的配置正確。像配置服務(wù)器來中繼消息或添加刪除郵件賬號(hào)這類任務(wù)的實(shí)現(xiàn),JavaMail API 中并不支持。

?

?????? 3POP

?????? POP 代表郵局協(xié)議(Post Office Protocol)。目前用的是版本 3,也稱 POP3,RFC 1939 定義了這個(gè)協(xié)議。POP 是一種機(jī)制,因特網(wǎng)上大多數(shù)人用它得到郵件。它規(guī)定每個(gè)用戶一個(gè)郵箱的支持。這就是它所能做的,而這也造成了許多混淆。使用 POP 時(shí),用戶熟悉的許多性能并不是由 POP 協(xié)議支持的,如查看有幾封新郵件消息這一性能。這些性能內(nèi)建于如 Eudora 或 Microsoft Outlook 之類的程序中,它們能記住一些事,諸如最近一次收到的郵件,還能計(jì)算出有多少是新的。所以當(dāng)使用 JavaMail API 時(shí),如果您想要這類信息,您就必須自己算。

?

?????? 4IMAP

?????? IMAP 是更高級(jí)的用于接收消息的協(xié)議。在 RFC 2060 中被定義,IMAP 代表因特網(wǎng)消息訪問協(xié)議(Internet Message Access Protocol),目前用的是版本 4,也稱 IMAP4。在用到 IMAP 時(shí),郵件服務(wù)器必需支持這個(gè)協(xié)議。不能僅僅把使用 POP 的程序用于 IMAP,并指望它支持 IMAP 所有性能。假設(shè)郵件服務(wù)器支持 IMAP,基于 JavaMail 的程序可以利用這種情況 — 用戶在服務(wù)器上有多個(gè)文件夾(folder),并且這些文件夾可以被多個(gè)用戶共享。

?????? 因?yàn)橛羞@一更高級(jí)的性能,您也許會(huì)認(rèn)為所有用戶都會(huì)使用 IMAP。事實(shí)并不是這樣。要求服務(wù)器接收新消息,在用戶請(qǐng)求時(shí)發(fā)送到用戶手中,還要在每個(gè)用戶的多個(gè)文件夾中維護(hù)消息。這樣雖然能將消息集中備份,但隨著用戶長(zhǎng)期的郵件夾越來越大,到磁盤空間耗盡時(shí),每個(gè)用戶都會(huì)受到損失。使用 POP,就能卸載郵件服務(wù)器上保存的消息了。

??????

?????? 5MIME

?????? MIME 代表多用途因特網(wǎng)郵件擴(kuò)展標(biāo)準(zhǔn)(Multipurpose Internet Mail Extensions)。它不是郵件傳輸協(xié)議。但對(duì)傳輸內(nèi)容的消息、附件及其它的內(nèi)容定義了格式。這里有很多不同的有效文檔:RFC 822、RFC 2045、RFC 2046 和 RFC 2047。作為一個(gè) JavaMail API 的用戶,您通常不必對(duì)這些格式操心。無論如何,一定存在這些格式而且程序會(huì)用到它。

?

?????? 6NNTP及其他

?????? 因?yàn)?JavaMail API 將供應(yīng)商和所有其它的東西分開了,您就能輕松添加額外的協(xié)議支持。Sun 保留了一張第三方供應(yīng)商列表,他們利用了 Sun 不提供超出(out-of-the-box)支持范圍的協(xié)議。您會(huì)找到 NNTP(網(wǎng)絡(luò)新聞傳輸協(xié)議)[新聞組]、S/MIME(安全多用途因特網(wǎng)郵件擴(kuò)展)及其它支持。

?

?

??????

??????

三、JavaMail的關(guān)鍵對(duì)象:

?????? JavaMail對(duì)收發(fā)郵件進(jìn)行了高級(jí)的抽象,形成了一些關(guān)鍵的的接口和類,它們構(gòu)成了程序的基礎(chǔ),下面我們分別來了解一下這些最常見的對(duì)象。

Properties:屬性對(duì)象

?????? 由于JavaMail需要和郵件服務(wù)器進(jìn)行通信,這就要求程序提供許多諸如服務(wù)器地址、端口、用戶名、密碼等信息,JavaMail通過Properties對(duì)象封裝這些屬性西信息。如下面的代碼封裝了兩個(gè)屬性信息:

?????? Properties props = new Properties();

??? props.put("mail.smtp.host", "smtp.sina.com.cn");

??? props.put("mail.smtp.auth", "true");

???

??? 針對(duì)不同的的郵件協(xié)議,JavaMail規(guī)定了服務(wù)提供者必須支持一系列屬性,下表是針對(duì)SMTP協(xié)議的一些常見屬性(屬性值都以String類型進(jìn)行設(shè)置,屬性類型欄僅表示屬性是如何被解析的):

屬性名

屬性類型

說明

mail.stmp.host

String

SMTP服務(wù)器地址,如smtp.sina.com.cn

mail.stmp.port

int

SMTP服務(wù)器端口號(hào),默認(rèn)為25

mail.stmp.auth

boolean

SMTP服務(wù)器是否需要用戶認(rèn)證,默認(rèn)為false

mail.stmp.user

String

SMTP默認(rèn)的登陸用戶名

mail.stmp.from

String

默認(rèn)的郵件發(fā)送源地址

mail.stmp.socketFactory.class

String

socket工廠類類名,通過設(shè)置該屬性可以覆蓋提供者默認(rèn)的實(shí)現(xiàn),必須實(shí)現(xiàn)javax.net.SocketFactory接口

mail.stmp.socketFactory.port

int

指定socket工廠類所用的端口號(hào),如果沒有規(guī)定,則使用默認(rèn)的端口號(hào)

mail.smtp.socketFactory.fallback

boolean

設(shè)置為true時(shí),當(dāng)使用指定的socket類創(chuàng)建socket失敗后,將使用java.net.Socket創(chuàng)建socket,默認(rèn)為true

mail.stmp.timeout

int

I/O連接超時(shí)時(shí)間,單位為毫秒,默認(rèn)為永不超時(shí)

?????? 其他幾個(gè)協(xié)議也有類似的一系列屬性,如POP3的mail.pop3.host、mail.pop3.port以及IMAP的mail.imap.host、mail.imap.port等。更詳細(xì)的信息請(qǐng)查看com.sun.mail.smtp、com.sun.mail.pop3和com.sun.mail.imap這三個(gè)包的Javadoc:http://java.sun.com/products/javamail/javadocs/index.html。

?

Session:會(huì)話對(duì)象

?????? Session是一個(gè)很容易被誤解的類,這歸咎于混淆視聽的類名。千萬不要以為這里的Session像HttpSession一樣代表真實(shí)的交互會(huì)話,但創(chuàng)建Session對(duì)象時(shí),并沒有對(duì)應(yīng)的物理連接,它只不過是一對(duì)配置信息的集合。Session的主要作用包括兩個(gè)方面:

?????? 1)接收各種配置屬性信息:通過Properties對(duì)象設(shè)置的屬性信息;

?????? 2)初始化JavaMail環(huán)境:根據(jù)JavaMail的配置文件,初始化JavaMail環(huán)境,以便通過Session對(duì)象創(chuàng)建其他重要類的實(shí)例。

?????? 所以,如果把Session更名為Configure也許更容易理解一些。JavaMail提供者在Jar包的META-INF目錄下,通過以下文件提供了基本配置信息,以便session能夠根據(jù)這個(gè)配置文件加載提供者的實(shí)現(xiàn)類:

l???????? javamail.providers和javamail.default.providers;

l???????? javamail.address.map和javamail.default.address.map。

?????? 下面是Sun提供者java.mail.default.providers文件的配置信息(位于mail.jar中):

??? # JavaMail IMAP provider Sun Microsystems, Inc

??? protocol=imap; type=store; class="com".sun.mail.imap.IMAPStore; vendor=Sun Microsystems, Inc;

??? protocol=imaps; type=store; class="com".sun.mail.imap.IMAPSSLStore; vendor=Sun Microsystems, Inc;

??? # JavaMail SMTP provider Sun Microsystems, Inc

??? protocol=smtp; type=transport; class="com".sun.mail.smtp.SMTPTransport; vendor=Sun Microsystems, Inc;

??? protocol=smtps; type=transport; ?? class="com".sun.mail.smtp.SMTPSSLTransport; vendor=Sun Microsystems, Inc;

??? # JavaMail POP3 provider Sun Microsystems, Inc

??? protocol=pop3; type=store; class="com".sun.mail.pop3.POP3Store; vendor=Sun Microsystems, Inc;

??? protocol=pop3s; type=store; class="com".sun.mail.pop3.POP3SSLStore; vendor=Sun Microsystems, Inc;

?????? 這個(gè)配置文件提供了以下四個(gè)方面的信息:

?????? protocol:協(xié)議名稱;

?????? type:協(xié)議類型;

?????? class:對(duì)應(yīng)該操作類型的實(shí)現(xiàn)類;

?????? vendor:廠商名稱。

?????? Session在加載配置文件時(shí)會(huì)按照以下優(yōu)先級(jí)順序進(jìn)行:

?????? 1)首先使用<JAVA_HOME>/lib中的javamail.providers;

?????? 2)如果1)不存在相應(yīng)的配置文件,使用類路徑下mail.jar中META-INF目錄下的javamail.providers;

?????? 3)如果2)不存在相應(yīng)的配置文件,使用類路徑下的mail.jar中META-INF目錄下的javamail.default.providers;

?????? 所以開發(fā)者可以在<JAVA_HOME>/lib目錄下提供配置文件覆蓋mail.jar/META-INF目錄中廠商的配置。但是,一般情況下,我們無須這樣做。

?????? Session通過JavaMail配置文件以及程序中設(shè)置的Properties對(duì)象構(gòu)建一個(gè)郵件處理環(huán)境,后續(xù)的處理將在Session基礎(chǔ)上進(jìn)行。Session擁有多個(gè)靜態(tài)工廠方法用于創(chuàng)建Session實(shí)例。

l???????? static Session getDefaultInstance(Properties props, Authenticator authenticator):當(dāng)JVM中已經(jīng)存在默認(rèn)的Session實(shí)例中,直接返回這個(gè)實(shí)例,否則創(chuàng)建一個(gè)新的Session實(shí)例,并將其作為JVM中默認(rèn)Session實(shí)例。這個(gè)API很詭異,我們將對(duì)它進(jìn)行詳細(xì)的講解。由于這個(gè)默認(rèn)Session實(shí)例可以被同一個(gè)JVM所有的代碼訪問到,而Session中本身又可能包括密碼、用戶名等敏感信息在內(nèi)的所有屬性信息,所以后續(xù)調(diào)用也必須傳入和第一次相同的Authenticator實(shí)例,否則將拋出java.lang.SecurityException異常。如果第一次調(diào)用時(shí)Authenticator入?yún)閚ull,則后續(xù)調(diào)用通過null的Authenticator入?yún)⒒蛑苯邮褂胓etDefaultInstance(Properties props)即可返回這個(gè)默認(rèn)的Session實(shí)例。值得一提的是,雖然后續(xù)調(diào)用也會(huì)傳入Properties,但新屬性并不會(huì)起作用,如果希望采用新的屬性值,則可以通過getDefaultInstance(Properties props)創(chuàng)建一個(gè)新的Session實(shí)例達(dá)到目的。Authenticator在這里承當(dāng)了兩個(gè)功能:首先,對(duì)JVM中默認(rèn)Session實(shí)例進(jìn)行認(rèn)證保護(hù),后續(xù)調(diào)用執(zhí)行g(shù)etDefaultInstance(Properties props, Authenticator authenticator)方法時(shí)必須和第一次一樣;其次,在具體和郵件服務(wù)器交互時(shí),又作為認(rèn)證的信息;

l???????? static Session getDefaultInstance(Properties props):返回JVM中默認(rèn)的Session實(shí)例,如果第一次創(chuàng)建Session未指定Authenticator入?yún)?#xff0c;后續(xù)調(diào)用可以使用該訪問獲取Session;

l???????? static Session getInstance(Properties props, Authenticator authenticator):創(chuàng)建一個(gè)新的Session實(shí)例,它不會(huì)在JVM中被作為默認(rèn)實(shí)例共享;

l???????? static Session getInstance(Properties props):根據(jù)相關(guān)屬性創(chuàng)建一個(gè)新的Session實(shí)例,未使用安全認(rèn)證信息;

?????? Session是JavaMail提供者配置文件以及設(shè)置屬性信息的“容器”,Session本身不會(huì)和郵件服務(wù)器進(jìn)行任何的通信。所以在一般情況下,我們僅需要通過getDefaultInstance()獲取一個(gè)共享的Session實(shí)例就可以了,下面的代碼創(chuàng)建了一個(gè)Session實(shí)例:

?????? Properties props = System.getProperties();

??? props.setProperty("mail.transport.protocol", "smtp");????????????? …

??? Session session = Session.getDefaultInstance(props);

?

TransportStore:傳輸和存儲(chǔ)

?????? 郵件操作只有發(fā)送或接收兩種處理方式,JavaMail將這兩種不同操作描述為傳輸(javax.mail.Transport)和存儲(chǔ)(javax.mail.Store),傳輸對(duì)應(yīng)郵件的發(fā)送,而存儲(chǔ)對(duì)應(yīng)郵件的接收。

?????? Session提供了幾個(gè)用于創(chuàng)建Transport和Store實(shí)例的方法,在具體講解這些方法之前,我們事先了解一下Session創(chuàng)建Transport和Store的內(nèi)部機(jī)制。我們知道提供者在javamail.providers配置文件中為每一種支持的郵件協(xié)議定義了實(shí)現(xiàn)類,Session根據(jù)協(xié)議類型(stmp、pop3等)和郵件操作方式(傳輸和存儲(chǔ))這兩個(gè)信息就可以定位到一個(gè)實(shí)例類上。比如,指定stmp協(xié)議和transport類型后,Session就會(huì)使用com.sun.mail.smtp.SMTPTransport實(shí)現(xiàn)類創(chuàng)建一個(gè)Transport實(shí)例,而指定pop3協(xié)議和store類型時(shí),則會(huì)使用com.sun.mail.pop3.POP3Store實(shí)例類創(chuàng)建一個(gè)Store實(shí)例。Session提供了多個(gè)重載的getTransport()和getStore()方法,這些方法將根據(jù)Session中Properties屬性設(shè)置情況進(jìn)行工作,影響這兩套方法工作的屬性包括:

屬性名

說明

mail.transport.protocol

默認(rèn)的郵件傳輸協(xié)議,例如,smtp

mail.store.protocol

默認(rèn)的存儲(chǔ)郵件協(xié)議,例如:pop3

mail.host

默認(rèn)的郵件服務(wù)地址,例如:192.168.67.1

mail.user

默認(rèn)的登陸用戶名,例如:zapldy

下面,我們?cè)倩仡^來了解Session的getTransport()和getStore()的重載方法。

l???????? Transport getTransport():當(dāng)Session實(shí)例設(shè)置了mail.transport.protocol屬性時(shí),該方法返回對(duì)應(yīng)的Transport實(shí)例,否則拋出javax.mail.NoSuchProviderException。

l???????? Transport getTransport(String protocol):如果Session沒有設(shè)置mail.transport.protocol屬性,可以通過該方法返回指定類型的Transport,如transport = session.getTransport(“smtp”)。

如果Session中未包含Authenticator,以上兩方法創(chuàng)建的Transport實(shí)例和郵件服務(wù)器交互時(shí)必須顯示提供用戶名/密碼的認(rèn)證信息。如果Authenticator非空,則可以在和郵件服務(wù)器交互時(shí)被作為認(rèn)證信息使用。除了以上兩種提供認(rèn)證信息的方式外,Session還可以使用以下的方法為Transport提供認(rèn)證信息。

Transport getTransport(URLName url):用戶可以通過URLName入?yún)⒅付ㄠ]件協(xié)議、郵件服務(wù)器、端口、用戶名和密碼信息,請(qǐng)看下面的代碼:

?????? URLName urln = new URLName(“smtp”, “smtp.sina.com.cn”, 25, null, “masterspring2”, “spring”);

?????? Transport transport = session.getTransport(urln);

?????? 這里,指定了郵件協(xié)議為smtp,郵件服務(wù)器是smtp.sina.com.cn,端口為25,用戶名/密碼為masterspring2/spring。

??????

?????? 消息發(fā)送的最后一部分是使用 Transport 類。這個(gè)類用協(xié)議指定的語言發(fā)送消息(通常是 SMTP)。它是抽象類,它的工作方式與 Session 有些類似。僅調(diào)用靜態(tài) send() 方法,就能使用類的 缺省 版本:

Transport.send(message);

或者,您也可以從針對(duì)您的協(xié)議的會(huì)話中獲得一個(gè)特定的實(shí)例,傳遞用戶名和密碼(如果不必要就不傳),發(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();

后面這種方法在您要發(fā)送多條消息時(shí)最好,因?yàn)樗鼙3粥]件服務(wù)器在消息間的活動(dòng)狀態(tài)。基本 send() 機(jī)制為每個(gè)方法的調(diào)用設(shè)置與服務(wù)器獨(dú)立的連接。

?????? 注意:要觀察傳到郵件服務(wù)器上的郵件命令,請(qǐng)用 session.setDebug(true) 設(shè)置調(diào)試標(biāo)志。

?

?????? 用 Session 獲取消息與發(fā)送消息開始很相似。但是,在 session 得到后,很可能使用用戶名和密碼或使用 Authenticator 連接到一個(gè) Store。類似于 Transport ,您告知 Store 使用什么協(xié)議:

// Store store = session.getStore("imap");

Store store = session.getStore("pop3");

store.connect(host, username, password);

?

連接到 Store 之后,接下來,您就可以獲取一個(gè) Folder,您必需先打開它,然后才能讀里面的消息。

Folder folder = store.getFolder("INBOX");

folder.open(Folder.READ_ONLY);

Message message[] = folder.getMessages();

POP3 唯一可以用的文件夾是 INBOX。如果使用 IMAP,還可以用其它文件夾。

注意:Sun 的供應(yīng)商有意變得聰明。雖然 Message message[] = folder.getMessages(); 看上去是個(gè)很慢的操作,它從服務(wù)器上讀取每一條消息,但僅在你實(shí)際需要消息的一部分時(shí),消息的內(nèi)容才會(huì)被檢索。

一旦有了要讀的 Message,您可以用 getContent() 來獲取其內(nèi)容,或者用 writeTo() 將內(nèi)容寫入流。getContent() 方法只能得到消息內(nèi)容,而 writeTo() 的輸出卻包含消息頭。

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

一旦讀完郵件,要關(guān)閉與 folder 和 store 的連接。

folder.close(aBoolean);

store.close();

傳遞給 folder 的 close() 方法的 boolean 表示是否清除已刪除的消息從而更新 folder。

??????

Message:消息對(duì)象

?????? 一旦獲得 Session 對(duì)象,就可以繼續(xù)創(chuàng)建要發(fā)送的消息。這由 Message 類來完成。因?yàn)?Message 是個(gè)抽象類,您必需用一個(gè)子類,多數(shù)情況下為 javax.mail.internet.MimeMessage。MimeMessage 是個(gè)能理解 MIME 類型和頭的電子郵件消息,正如不同 RFC 中所定義的。雖然在某些頭部域非 ASCII 字符也能被譯碼,但 Message 頭只能被限制為用 US-ASCII 字符。

?

要?jiǎng)?chuàng)建一個(gè) Message,請(qǐng)將 Session 對(duì)象傳遞給 MimeMessage 構(gòu)造器:

?

MimeMessage message = new MimeMessage(session);

?

注意:還存在其它構(gòu)造器,如用按 RFC822 格式的輸入流來創(chuàng)建消息。

?

一旦獲得消息,您就可以設(shè)置各個(gè)部分,因?yàn)?Message 實(shí)現(xiàn) Part 接口(且 MimeMessage 實(shí)現(xiàn) MimePart )。設(shè)置內(nèi)容的基本機(jī)制是 setContent() 方法,同時(shí)使用參數(shù),分別代表內(nèi)容和 mime 類型:

?

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

?

但如果,您知道您在使用 MimeMessage,而且消息是純文本格式,您就可以用 setText() 方法,它只需要代表實(shí)際內(nèi)容的參數(shù),( MIME 類型缺省為 text/plain):

?

message.setText("Hello");

?

后一種格式是設(shè)置純文本消息內(nèi)容的首選機(jī)制。至于發(fā)送其它類型的消息,如 HTML 文件格式的消息,我們首選前者。

?

用 setSubject() 方法設(shè)置 subject(主題):

?

message.setSubject("First");

?

下面的代碼演示了創(chuàng)建一個(gè)簡(jiǎn)單郵件信息的過程:

Message msg = new MimeMessage(session);

msg.setSubject("Test Title");

msg.setText("How are you!");

msg.setSentDate(new Date());

?

?

Address:地址

?????? 一旦您創(chuàng)建了 Session 和 Message,并將內(nèi)容填入消息后,就可以用 Address 確定信件地址了。和 Message 一樣,Address 也是個(gè)抽象類。您用的是 javax.mail.internet.InternetAddress 類。

?

若創(chuàng)建的地址只包含電子郵件地址,只要傳遞電子郵件地址到構(gòu)造器就行了。

?

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

?

若希望名字緊挨著電子郵件顯示,也可以把它傳遞給構(gòu)造器:

?

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

?

需要為消息的 from 域和 to 域創(chuàng)建地址對(duì)象。除非郵件服務(wù)器阻止,沒什么能阻止你發(fā)送一段看上去是來自任何人的消息。

?

一旦創(chuàng)建了 address(地址),將它們與消息連接的方法有兩種。如果要識(shí)別發(fā)件人,您可以用 setFrom() 和 setReplyTo() 方法。

?

message.setFrom(address)

?

需要消息顯示多個(gè) from 地址,可以使用 addFrom() 方法:

?

Address address[] = ...;

message.addFrom(address);

?

若要識(shí)別消息 recipient(收件人),您可以使用 addRecipient() 方法。除 address(地址)外,這一方法還請(qǐng)求一個(gè) Message.RecipientType。

?

message.addRecipient(type, address)

?

三種預(yù)定義的地址類型是:

?

Message.RecipientType.TO

Message.RecipientType.CC

Message.RecipientType.BCC

如果消息是發(fā)給副總統(tǒng)的,同時(shí)發(fā)送一個(gè)副本(carbon copy)給總統(tǒng)夫人,以下做法比較恰當(dāng):

?

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 中定義的)或驗(yàn)證郵件交換(mail exchange,MX)記錄,但這些功能不屬于 JavaMail API。

?

Authenticator:認(rèn)證者

?????? 與 java.net 類一樣,JavaMail API 也可以利用 Authenticator 通過用戶名和密碼訪問受保護(hù)的資源。對(duì)于JavaMail API 來說,這些資源就是郵件服務(wù)器。JavaMail Authenticator 在 javax.mail 包中,而且它和 java.net 中同名的類 Authenticator 不同。兩者并不共享同一個(gè) Authenticator,因?yàn)镴avaMail API 用于 Java 1.1,它沒有 java.net 類別。

?

?????? 要使用 Authenticator,先創(chuàng)建一個(gè)抽象類的子類,并從 getPasswordAuthentication() 方法中返回 PasswordAuthentication 實(shí)例。創(chuàng)建完成后,您必需向 session 注冊(cè) Authenticator。然后,在需要認(rèn)證的時(shí)候,就會(huì)通知 Authenticator。您可以彈出窗口,也可以從配置文件中(雖然沒有加密是不安全的)讀取用戶名和密碼,將它們作為 PasswordAuthentication 對(duì)象返回給調(diào)用程序。

?

Properties props = new Properties();

// fill props with any information

Authenticator auth = new MyAuthenticator();

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

?

發(fā)送消息:

?????? 發(fā)送電子郵件消息這一過程包括獲取一個(gè)會(huì)話,創(chuàng)建并填充一則消息,然后發(fā)送。得到 Session 時(shí),經(jīng)由設(shè)置傳遞的 Properties 對(duì)象中的 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)該將代碼放在一個(gè) try-catch 程序塊中,這樣創(chuàng)建和發(fā)送消息時(shí)就能夠拋出異常。

?

消息的提取:

?????? 為讀郵件,您獲取一個(gè)會(huì)話,獲取并連接一個(gè)用于郵箱的適宜的存儲(chǔ)(store),打開適宜的文件夾,然后獲取您的消息。同樣,切記完成后關(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();

?

對(duì)每條消息做些什么由您決定。上面的代碼塊只是顯示這些消息的發(fā)件人和主題。技術(shù)上講,from 地址列表可能為空,而 getFrom()[0] 調(diào)用會(huì)拋出一個(gè)異常。

?

要顯示全部信息,您可以在用戶看完 from 和 subject 域之后給出提示,如用戶有需要,就調(diào)用消息的 writeTo() 方法來實(shí)現(xiàn)。

?

????????? 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)識(shí)的刪除:

?????? 消息的刪除涉及使用與消息相關(guān)的 Flags(標(biāo)志)。不同 flag 對(duì)應(yīng)不同的狀態(tài),有些由系統(tǒng)定義而有些則由用戶定義。下面列出在內(nèi)部類 Flags.Flag 中預(yù)定義的標(biāo)志:

?

??? * Flags.Flag.ANSWERED

??? * Flags.Flag.DELETED

??? * Flags.Flag.DRAFT

??? * Flags.Flag.FLAGGED

??? * Flags.Flag.RECENT

??? * Flags.Flag.SEEN

??? * Flags.Flag.USER

?

僅僅因?yàn)榇嬖谝粋€(gè)標(biāo)志,并不意味著所有郵件服務(wù)器或供應(yīng)商都支持這個(gè)標(biāo)志。例如,除了刪除消息標(biāo)志外,POP 協(xié)議不再支持其它任何標(biāo)志。檢查是否存在新郵件,這不是個(gè) POP 任務(wù),而是內(nèi)建于郵件客戶機(jī)的任務(wù)。為找出哪些標(biāo)志能被支持,可以用 getPermanentFlags() 向 folder 提出要求。

?

要?jiǎng)h除消息,您可以設(shè)置消息的 DELETED flag:

?

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

?

首先,請(qǐng)以 READ_WRITE 模式打開 folder:

?

folder.open(Folder.READ_WRITE);

?

然后,當(dāng)所有消息的處理完成后,關(guān)閉 folder,并傳遞一個(gè) true 值,從而擦除(expunge)有 delete 標(biāo)志的消息。

?

folder.close(true);

?

一個(gè) Folder 的 expunge() 方法可以用來刪除消息。但 Sun 的 POP3 供應(yīng)商不支持。其它供應(yīng)商有的或許能夠?qū)崿F(xiàn)這一功能,而有的則不能。IMAP 供應(yīng)商極有可能實(shí)現(xiàn)此功能。因?yàn)?POP 只支持單個(gè)對(duì)郵箱的訪問,對(duì) Sun 的供應(yīng)商來說,您必需關(guān)閉 folder 以刪除消息。

?

要取消標(biāo)志,只要傳遞 false 給 setFlag() 方法就行了。想知道是否設(shè)置過標(biāo)志,可以用 isSet() 檢查。

?

親自認(rèn)證:

?????? 您已經(jīng)知道 — 如果需要可以用一個(gè) Authenticator 提示用戶輸入用戶名和密碼,而不是將用戶名和密碼作為字符串傳遞。在這里您會(huì)明確了解怎樣更充分的使用認(rèn)證。

?

不用主機(jī)、用戶名和密碼與 Store 相連接,而是設(shè)置 Properties 來?yè)碛兄鳈C(jī),然后告訴 Session 自定義的 Authenticator 實(shí)例,如下所示:

?

?

// 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();

?

然后,您創(chuàng)建一個(gè) Authenticator 子類并從 getPasswordAuthentication() 方法中返回 PasswordAuthentication 對(duì)象。下面就是這樣一種實(shí)現(xiàn),其中用戶名和密碼僅占用一個(gè)域。(這不是一個(gè) Swing 工程教程;只要將兩部分輸入同一個(gè)域,用逗號(hào)分隔就行。)

?

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);

? }

?

}

?

因?yàn)?PopupAuthenticator 涉及到 Swing,它會(huì)啟動(dòng) AWT 的事件處理線程。這一點(diǎn)基本上要求您在代碼中添加一個(gè)對(duì) System.exit() 的調(diào)用來終止程序。

?

消息的回復(fù):

?????? Message 類引入一個(gè) reply() 方法來配置一個(gè)新 Message,包括正確的 recipient(收件人)和添加“Re”(如果沒有就添加)的正確的 subject。這樣做并沒有為消息添加新內(nèi)容,僅僅將 from 或 reply-to(被回復(fù)人) 頭復(fù)制給新的收件人。這種方法用一個(gè) boolean 參數(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ā)送消息時(shí)要配置 reply to(被回復(fù)人) 地址,可以用 setReplyTo() 方法。

?

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

轉(zhuǎn)發(fā)消息有一點(diǎn)棘手。沒有單獨(dú)的方法可以調(diào)用,您通過對(duì)組成消息各部分的處理來組織要轉(zhuǎn)發(fā)的消息。

?

一條郵件消息可以由多個(gè)部分組成。在處理 MIME 消息時(shí),消息中每部分都是 BodyPart,再特殊些,是 MimeBodyPart。不同的 body part(信體部件或正文部件)結(jié)合成一個(gè)容器,名為 Multipart,再特殊些,就是 MimeMultipart。要轉(zhuǎn)發(fā)一條消息,您為自己的消息正文創(chuàng)建一個(gè)部件,要轉(zhuǎn)發(fā)的消息作為另一部件。并且將兩個(gè)部件結(jié)合成一個(gè) multipart(多部件)。然后您將這個(gè) multipart 添加到一則已寫好恰當(dāng)?shù)刂返南⒅?#xff0c;并發(fā)送。

?

本質(zhì)上就是如此。要將一條消息內(nèi)容復(fù)制到另一條,只要復(fù)制 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);

?

?

附件的處理:

附件是郵件消息的相關(guān)資源,如通常不包含在消息正文里文本文件、電子表格或圖像等。常見的郵件程序,如 Eudora 和 pine 之類,可以用 JavaMail API 將資源 attach(附加) 到您的消息上,就可以在收到消息時(shí)得到。

?

附件的發(fā)送:

發(fā)送附件非常像轉(zhuǎn)發(fā)消息。您建立各部分以組成完整消息。完成第一部件,即消息正文后,您添加其它部件,其中每個(gè) DataHandler 都代表附件,而不是轉(zhuǎn)發(fā)消息情況下的共享處理程序。如果從文件中讀附件,附件的數(shù)據(jù)源是 FileDataSource。而如果從 URL 中讀時(shí),附件的數(shù)據(jù)源是 URLDataSource。一旦存在 DataSource,只要先把它傳遞給 DataHandler 構(gòu)造器,最后再用 setDataHandler() 把它附加到 BodyPart。假定您要保留附件的原始文件名,最終要做的是用 BodyPart 的 setFileName() 方法設(shè)置與附件相關(guā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);

?

?

就消息引入附件時(shí),若程序是個(gè) servlet (小服務(wù)程序),除告知消息發(fā)送到何處外,還必需上載附件。可以將 multipart/form-data 表單編碼類型(form encoding type)用于每個(gè)上載文件的處理。

?

?

<FORM ENCTYPE="multipart/form-data"

??? method=post action="/myservlet">

? <INPUT TYPE="file" NAME="thefile">

? <INPUT TYPE="submit" VALUE="Upload">

</FORM>

?

注意:消息大小由 SMTP 服務(wù)器而不是 JavaMail API 來限制。如果您碰到問題,可以考慮用設(shè)置 ms 和 mx 參數(shù)的方法增大 Java 堆大小。

?

附件的獲取:

從消息中獲取附件比發(fā)送它們棘手些,因?yàn)?MIME 沒有簡(jiǎn)單的關(guān)于附件的概念。當(dāng)消息包含附件時(shí),消息的內(nèi)容是個(gè) Multipart 對(duì)象。接著,您需要處理每個(gè) Part,獲取主要內(nèi)容和附件。標(biāo)有從 part.getDisposition() 獲得的 Part.ATTACHMENT 配置(disposition)的部件(Part)無疑就是附件。但是,沒有配置(以及一個(gè)非文本 MIME 類型)和帶 Part.INLINE 配置的部件也可能是附件。當(dāng)配置要么是 Part.ATTACHMENT,要么是 Part.INLINE 時(shí),這個(gè)消息部件的內(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)建了一個(gè) File,它從輸入流中將字節(jié)讀出,然后寫入到文件中。萬一文件已經(jīng)存在,就在文件名后添加一個(gè)數(shù)字作為新文件名,如果這個(gè)文件名仍存在,則繼續(xù)添,直到找不到這樣的文件名為止。

?

// from saveFile()

File file = new File(filename);

for (int i=0; file.exists(); i++) {

? file = new File(filename+i);

}

?

上面的代碼涵蓋了最簡(jiǎn)單的情況 — 消息中各部件恰當(dāng)?shù)臉?biāo)記了。要涵蓋所有情況,還要在配置為空時(shí)進(jìn)行處理,并且獲取部件的 MIME 類型來進(jìn)行相應(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, ...

? }

? ...

}

?

對(duì) HTML 消息的處理

發(fā)送基于 HTML 文件格式消息的工作量比發(fā)送純文本消息多,雖然不一定非要這些多余的工作量。如何選擇完全取決于給定的請(qǐng)求。

?

HTML 消息的發(fā)送:

若您所要做的全部事情是發(fā)送一份 HTML 文件的等價(jià)物作為消息,但讓郵件閱讀者為不能提取任何內(nèi)嵌圖像或相關(guān)片段而擔(dān)心的話,可以使用 Message 的 setContent() 方法,把內(nèi)容當(dāng)作一個(gè) String 傳入,并將內(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 或其它第三方 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)容的消息完整(內(nèi)嵌的圖像作為消息的一部分),您必需把圖像作為附件,并且用一個(gè)給定的 cid URL 引用圖像,其中 cid 是圖像附件 Content-ID 頭的引用。

?

嵌入圖像的過程與附加文件到消息的過程非常相似,唯一的區(qū)別在于您必需通過設(shè)置 MimeMultipart 構(gòu)造器中的子類型(或者說用 setSubType())告知 MimeMultipart 各個(gè)相關(guān)部件,并且將這個(gè)圖像的 Content-ID 頭設(shè)置成隨機(jī)字符串,作為圖像的 src 在 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);

轉(zhuǎn)載于:https://www.cnblogs.com/nicholaswei/archive/2012/09/28/2707362.html

總結(jié)

以上是生活随笔為你收集整理的JavaMail发送和接收邮件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。