JavaMail介紹及相關類介紹

    JavaMail是SUN提供給開發人員在應用程序中實現“郵件發送和接收功能”的一套標準開發類庫,支持常用的郵件協議,如SMTP、POP3、IMAP。

  • SMTP:簡單郵件傳輸協議,用於發送電子郵件的傳輸協議;

  • POP3:郵局協議,用於接收電子郵件的標準協議;

  • IMAP:互聯網消息訪問協議,是POP3的替代協議。

    (這三種協議都有對應SSL加密傳輸的協議,分別是SMTPS,POP3S和IMAP3)。

  • MIME:多用途因特網郵件擴展別準,它不是郵件傳輸消息,但對傳輸內容的消息、附件及其他的內容定義了格式。    

    開發人員使用JavaMail編寫郵件程序時,無需考慮底層的通信細節(Socket),JavaMail也提供了能夠創建出各種複雜MIME格式的郵件內容的API。使用JavaMail,我們可以實現類似OutLook、FoxMail的軟件。雖然JavaMail(僅支持JDK4及以上)也是Java的API之一,但是卻沒有直接加入到JDK中,所以我們需要另行下載。另外,JavaMail依賴JAF(JavaBeans Activation Framework)來處理不是純文本的郵件內容(如MIME多用途互聯網郵件擴展、URL頁面和文件附件等內容),JAF在Java6之後已經合併到JDK中,而JDK5之前需要另外下載JAF的類庫。下載地址如下:

       JavaMail:http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-eeplat-419426.html#javamail-1.4.5-oth-JPR

       JavaMail spec:http://www.oracle.com/technetwork/java/javamail-1-149769.pdf

       JAF:http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-plat-419418.html#jaf-1.1.1-fcs-oth-JPR

       JavaMail下載好後,我們來看一下其主要內容:            

        README.txt:整體介紹JavaMail,需要看一下
        docs/javadocs:The JavaMail API javadocs,需要看一下
        mail.jar:包括JavaMail API和所有service providers,大部分用戶只需要該jar包
        lib/mailapi.jar	:只有JavaMail API
        lib/imap.jar:The IMAP service provider
        lib/smtp.jar:The SMTP service provider
        lib/pop3.jar:The POP3 service provider
        lib/dsn.jar:multipart/report DSN message support
        demo:demo示例,簡單瞭解,有需要再看

    JavaMail包含兩部分內容,一部分是JavaMail API,定義了一組平臺無關、獨立於通訊協議的郵件程序框架,該部分稱爲應用級接口,也就是供我們調用的部分,另一部分是service provider,該部分使用特定的協議語言來實現第一部分定義的抽象類和接口,這些協議包括:SMTP、NNTP、POP3、IMAP,如果讓JavaMail與郵件服務器通信,就需要相應的協議支持,該部分稱爲服務提供者接口,也就是JavaMail自身需要的協議支持。在使用JavaMail時,通常我們只需將mail.jar放在classpath下使用,它包含了JavaMail API部分和SUN自己實現的service provider部分。可能也有特殊的時候,我們應用程序中需要自己實現service provider部分,那我們只需要mailapi.jar。下面通過幾個類來簡單認識下JavaMail API:

    javax.mail.Session:上下文環境信息,如服務器的主機名、端口號、協議名稱等
    javax.mail.Message:郵件模型,發送郵件和接收郵件的媒介,封裝了郵件的信息,如發件人、收件人、郵件標題、郵件內容等
    javax.mail.Transport:連接郵件SMTP服務器,發送郵件
    javax.mail.Store:連接郵件POP3、IMAP服務器,收取郵件

通過這些類,最終就可以實現收發郵件,一個發送郵件的簡單示例:

public class JavaMailTest1 {
	public static void main(String[] args) throws MessagingException {
		Properties props = new Properties();
		// 開啓debug調試
		props.setProperty("mail.debug", "true");
		// 發送服務器需要身份驗證
		props.setProperty("mail.smtp.auth", "true");
		// 設置郵件服務器主機名
		props.setProperty("mail.host", "smtp.163.com");
		// 發送郵件協議名稱
		props.setProperty("mail.transport.protocol", "smtp");
		
		// 設置環境信息
		Session session = Session.getInstance(props);
		
		// 創建郵件對象
		Message msg = new MimeMessage(session);
		msg.setSubject("JavaMail測試");
		// 設置郵件內容
		msg.setText("這是一封由JavaMail發送的郵件!");
		// 設置發件人
		msg.setFrom(new InternetAddress("[email protected]"));
		
		Transport transport = session.getTransport();
		// 連接郵件服務器
		transport.connect("java_mail_001", "javamail");
		// 發送郵件
		transport.sendMessage(msg, new Address[] {new InternetAddress("[email protected]")});
		// 關閉連接
		transport.close();
	}
}

最終運行後,郵件發送成功。由於我們開啓了debug調試,在控制檯可以看到JavaMail和服務器之間的交互信息記錄。

       PS:文中示例以及以後的示例中所用的郵箱賬戶均爲在163申請的測試賬戶,分別爲java_mail_001至java_mail_004,密碼均爲javamail。




        JavaMail API使用上非常靈活。它對收發郵件進行了高級的抽象,形成了一些關鍵的接口和類,它們構成了程序的基礎,下面分別介紹這些對象:

  • Properties

        屬性對象。由於JavaMail需要和郵件服務器進行通信,這就要求程序提供許多諸如服務器地址、端口、用戶名、密碼等信息,JavaMail通過Properties對象封裝這些屬性信息。例如

    Properties props = new Properties();
    props.put("mail.smtp.host", "smtp.sina.com.cn");
    props.put("mail.smtp.auth", "true");

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

屬性名

屬性類型

說明

mail.stmp.host

String

SMTP服務器地址,如smtp.sina.com.cn

mail.stmp.port

int

SMTP服務器端口號,默認爲25

mail.stmp.auth

boolean

SMTP服務器是否需要用戶認證,默認爲false

mail.stmp.user

String

SMTP默認的登陸用戶名

mail.stmp.from

String

默認的郵件發送源地址

mail.stmp.socketFactory.class

String

socket工廠類類名,通過設置該屬性可以覆蓋提供者默認的實現,必須實現javax.net.SocketFactory接口

mail.stmp.socketFactory.port

int

指定socket工廠類所用的端口號,如果沒有規定,則使用默認的端口號

mail.smtp.socketFactory.fallback

boolean

設置爲true時,當使用指定的socket類創建socket失敗後,將使用java.net.Socket創建socket,默認爲true

mail.stmp.timeout

int

I/O連接超時時間,單位爲毫秒,默認爲永不超時


其他幾個協議也有類似的一系列屬性,如POP3mail.pop3.hostmail.pop3.port以及IMAPmail.imap.hostmail.imap.port等。更詳細的信息請查看com.sun.mail.smtpcom.sun.mail.pop3com.sun.mail.imap這三個包的Javadochttp://java.sun.com/products/javamail/javadocs/index.html


  • Session

    

    會話對象。千萬別以爲這裏的Session向HTTPSession一樣代表真實的交互會話,創建Session對象時,並沒有對應的物理連接,它只不過是一對配置信息的集合。主要作用包括兩個方面:

    1)接收各種配置屬性信息:通過Properties對象設置的屬性信息;

    2)初始化JavaMail環境:根據JavaMail的配置文件,初始化JavaMail環境,以便通過Session對象創建其他重要類的實例。    

    JavaMail分爲API和service provider兩部分,API定義了相關接口(eg.:Transport and Store),service provider中實現了這些接口。JavaMail提供的mail.jar/smtp.jar/pop3.jar/imap.jar等jar包的META-INF目錄下,通過javamail.providers或javamail.default.provider、javamail.address.map和javamail.default.address.map文件提供了基本的配置信息,以便session能夠根據這個配置文件家在提供者的實現類。javamail.default.provider文件的配置信息如:

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

    每一行聲明瞭協議名稱、協議類型、實現類、供應商、版本等信息,如果需要自己實現相應的協議,必須按照該格式配置好,Java Mail API中才能正確的調用到。

 Session在加載配置文件時會按照以下優先級順序進行:

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

       2)如果1)不存在相應的配置文件,使用類路徑下mail.jarMETA-INF目錄下的javamail.providers

       3)如果2)不存在相應的配置文件,使用類路徑下的mail.jarMETA-INF目錄下的javamail.default.providers

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

    Session用於收集JavaMail運行過程中的環境信息,它可以創建一個單例的對象,也可以每次創建新的對象,Session沒有構造器,但擁有多個靜態工廠方法用於創造實例:

static SessiongetDefaultInstance(Properties props)
          Get the default Session object.
static SessiongetDefaultInstance(Properties props,Authenticator authenticator)
          Get the default Session object.
static SessiongetInstance(Properties props)
          Get a new Session object.
static SessiongetInstance(Properties props,Authenticator authenticator)
          Get a new Session object.

l         static Session getDefaultInstance(Properties props, Authenticator authenticator):當JVM中已經存在默認的Session實例中,直接返回這個實例,否則創建一個新的Session實例,並將其作爲JVM中默認Session實例。這個API很詭異,我們將對它進行詳細的講解。由於這個默認Session實例可以被同一個JVM所有的代碼訪問到,而Session中本身又可能包括密碼、用戶名等敏感信息在內的所有屬性信息,所以後續調用也必須傳入和第一次相同的Authenticator實例,否則將拋出java.lang.SecurityException異常。如果第一次調用時Authenticator入參爲null,則後續調用通過nullAuthenticator入參或直接使用getDefaultInstance(Properties props)即可返回這個默認的Session實例。值得一提的是,雖然後續調用也會傳入Properties,但新屬性並不會起作用,如果希望採用新的屬性值,則可以通過getDefaultInstance(Properties props)創建一個新的Session實例達到目的。Authenticator在這裏承當了兩個功能:首先,對JVM中默認Session實例進行認證保護,後續調用執行getDefaultInstance(Properties props, Authenticator authenticator)方法時必須和第一次一樣;其次,在具體和郵件服務器交互時,又作爲認證的信息;

l         static Session getDefaultInstance(Properties props):返回JVM中默認的Session實例,如果第一次創建Session未指定Authenticator入參,後續調用可以使用該訪問獲取Session;

l         static Session getInstance(Properties props, Authenticator authenticator):創建一個新的Session實例,它不會在JVM中被作爲默認實例共享;

l         static Session getInstance(Properties props):根據相關屬性創建一個新的Session實例,未使用安全認證信息;

    getDefaultInstance得到的始終是該方法初次創建的缺省的對象,而getInstance得到的始終是新的對象,Authenticator的使用後面會說到。Session是JavaMail提供者配置文件以及設置屬性信息的“容器”,其本身不會和郵件服務器進行任何的通信。所以,一般情況下,我們僅需要通過getDefaultInstance獲取一個共享的Session實例就可以了。例如:

    Properties props = System.getProperties();
    props.setProperty("mail.transport.protocol", "smtp");              …
    Session session = Session.getDefaultInstance(props);


Message


    消息對象。Message是郵件的載體,用於封裝郵件的所有信息,Message是一個抽象類,已知的實現類有MimeMessage。

    MimeMessage message=new MimeMessage(session)

     ps:Address類:地址。一旦你創建了Session和Message,並將內容填入消息後,就可以用Address確定信件地址了。和Message一樣,Address也是一個抽象類,常用InternetAddress類實例。

    若創建的地址只包含電子郵件地址,只要傳遞電子郵件地址到構造器就行了。
        Address address = new InternetAddress("[email protected]");
    若希望名字緊挨着電子郵件顯示,也可以把它傳遞給構造器:
        Address address = new InternetAddress("[email protected]", "George Bush");

    下面來看下Message中設置郵件信息的一些方法。

發件人

abstract  voidsetFrom()
          Set the "From" attribute in this Message.
abstract  voidsetFrom(Address address)
          Set the "From" attribute in this Message.

    現在大多數SMTP服務器要求發件人與連接賬戶必須一致,否則會拋出驗證失敗的異常,這樣是防止用戶僞裝成其它人的賬戶惡意發送郵件。

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

                 Address address[] = ...;

                message.addFrom(address);

收件人/抄送人/暗送人

voidsetRecipient(Message.RecipientType type,Address address)
          Set the recipient address.
abstract  voidsetRecipients(Message.RecipientType type,Address[] addresses)
          Set the recipient addresses.

    第一個方法設置單個人,第二個方法設置多個人。

    方法中第一個參數涉及到另一個類RecipientType(預定義地址),該類是Message的靜態內部類,期內有三個常量值:

static Message.RecipientTypeBCC
          The "Bcc" (blind carbon copy) recipients.
static Message.RecipientTypeCC
          The "Cc" (carbon copy) recipients.
static Message.RecipientTypeTO
          The "To" (primary) recipients.

       TO - 收件人;CC - 抄送人;BCC - 暗送人。

回覆人

 voidsetReplyTo(Address[] addresses)
          Set the addresses to which replies should be directed.

    設置收件人收到郵件後的回覆地址。

標題

abstract  voidsetSubject(String subject)
          Set the subject of this message.

    設置郵件標題/主題。

內容

 voidsetContent(Multipart mp)
          This method sets the given Multipart object as this message's content.
 voidsetContent(Object obj,String type)
          A convenience method for setting this part's content.
 voidsetText(String text)
          A convenience method that sets the given String as this part's content with a MIME type of "text/plain".

    設置郵件文本內容、HTML內容、附件內容。

示例 

    如果消息是發給副總統的,同時發送一個副本(carbon copy)給總統夫人,以下做法比較恰當: 

    Address toAddress = new InternetAddress("[email protected]");
    Address ccAddress = new InternetAddress("[email protected]");
    message.addRecipient(Message.RecipientType.TO, toAddress);
    message.addRecipient(Message.RecipientType.CC, ccAddress);

Transport和Store

    傳輸和存儲。通過Session可以創建Transport(用於發送郵件)和Store(用於接收郵件)。創建機制:我們知道提供者在javamail.providers配置文件中爲每一種支持的郵件協議定義了實現類,Session根據協議類型(stmppop3等)和郵件操作方式(傳輸和存儲)這兩個信息就可以定位到一個實例類上。比如,指定stmp協議和transport類型後,Session就會使用com.sun.mail.smtp.SMTPTransport實現類創建一個Transport實例,而指定pop3協議和store類型時,則會使用com.sun.mail.pop3.POP3Store實例類創建一個Store實例。Session提供了多個重載的getTransport()getStore()方法,這些方法將根據SessionProperties屬性設置情況進行工作,影響這兩套方法工作的屬性包括:

屬性名

說明

mail.transport.protocol

默認的郵件傳輸協議,例如,smtp

mail.store.protocol

默認的存儲郵件協議,例如:pop3

mail.host

默認的郵件服務地址,例如:192.168.67.1

mail.user

默認的登陸用戶名,例如:zapldy

Session中提供的創建Trasnsport和Store的方法如下(Session實例設置了mail.transport.protocol屬性時,該方法返回對應的Transport實例,否則拋出javax.mail.NoSuchProviderException。如果Session沒有設置mail.transport.protocol屬性,可以通過該方法返回指定類型的Transport,如transport = session.getTransport(“smtp”)。)

 StoregetStore()
          Get a Store object that implements this user's desired Store protocol.
 StoregetStore(Provider provider)
          Get an instance of the store specified by Provider.
 StoregetStore(String protocol)
          Get a Store object that implements the specified protocol.
 StoregetStore(URLName url)
          Get a Store object for the given URLName.
 TransportgetTransport()
          Get a Transport object that implements this user's desired Transport protcol.
 TransportgetTransport(Address address)
          Get a Transport object that can transport a Message of the specified address type.
 TransportgetTransport(Provider provider)
          Get an instance of the transport specified in the Provider.
 TransportgetTransport(String protocol)
          Get a Transport object that implements the specified protocol.
 TransportgetTransport(URLName url)
          Get a Transport object for the given URLName.

    可以看到,重構了很多,這些方法最終都會去解析上文提到的配置文件,找到對應配置信息。       

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

Transport getTransport(URLName url):用戶可以通過URLName入參指定郵件協議、郵件服務器、端口、用戶名和密碼信息,請看下面的代碼:

URLName urln = new URLName(“smtp”, “smtp.sina.com.cn”, 25, null, “masterspring2”, “spring”);
Transport transport = session.getTransport(urln);

這裏,指定了郵件協議爲smtp,郵件服務器是smtp.sina.com.cn,端口爲25,用戶名/密碼爲masterspring2/spring


消息發送:使用  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) 設置調試標誌。

 

獲取消息: Session 獲取消息與發送消息開始很相似。但是,在 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(); 看上去是個很慢的操作,它從服務器上讀取每一條消息,但僅在你實際需要消息的一部分時,消息的內容纔會被檢索。

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

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

    一旦讀完郵件,要關閉與 folder  store 的連接。

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

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

示例

       下面來看一個稍複雜點的示例:

public class JavaMailTest2 {

	public static void main(String[] args) throws MessagingException {
		Properties props = new Properties();
		// 開啓debug調試
		props.setProperty("mail.debug", "true");
		// 發送服務器需要身份驗證
		props.setProperty("mail.smtp.auth", "true");
		// 設置郵件服務器主機名
		props.setProperty("mail.host", "smtp.163.com");
		// 發送郵件協議名稱
		props.setProperty("mail.transport.protocol", "smtp");
		
		// 設置環境信息
		Session session = Session.getInstance(props, new Authenticator() {
			// 在session中設置賬戶信息,Transport發送郵件時會使用
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication("java_mail_001", "javamail");
			}
		});
		
		// 創建郵件對象
		Message msg = new MimeMessage(session);
		// 發件人
		msg.setFrom(new InternetAddress("[email protected]"));
		// 多個收件人
		msg.setRecipients(RecipientType.TO, InternetAddress.parse("[email protected],[email protected]"));
		// 抄送人
		msg.setRecipient(RecipientType.CC, new InternetAddress("[email protected]"));
		// 暗送人
		msg.setRecipient(RecipientType.BCC, new InternetAddress("[email protected]"));
		
		// 主題
		msg.setSubject("中文主題");
		// HTML內容
		msg.setContent("<div align=\"center\">你好啊</div>", "text/html;charset=utf-8");
		
		// 連接郵件服務器、發送郵件、關閉連接,全乾了
		Transport.send(msg);
	}

}



wKioL1PIcivSZFrkAAARrAqeod8864.gif

 本文來自:

        高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/17839983

                zapldy,原文地址:http://blog.csdn.net/zapldy/article/details/3971579

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章