引言:
JavaMail jar包下載地址:http://java.sun.com/products/javamail/downloads/index.html
此篇是緊隨上篇文章而封裝出來的,閱讀本篇章建議先閱讀上一篇 -->javamail模擬郵箱功能發送電子郵件-中級實戰篇【新增附件發送方法】(javamail API電子郵件實例)
在上一篇中,講解了郵件發送的兩個基本方法(HTML和附件),並且引入了兩個新類 Multipart 和 BodyPart 兩類,整體結構比較緊湊,郵件的服務實體類和發送的業務方法耦合在一起,本篇章節中將再次對模塊進行拆分,來實現簡單責任原則。新優化為:郵件基礎父類,郵件基礎服務類,發送郵件業務類,收取郵件業務類,下面會為大家列出詳細列表。
既然本章節主要講解的是郵件的接收|查看,就先來分析下郵件的發送和讀取有什么本質上的區別(總結的不一定全面,請見諒~)。
相同之處是:他們都需要初始化服務實體類里的各大屬性,如:propertis文件、Message消息、Session郵件會話等,在操作附件時都用到了io流的操作。
不同之處是:郵件發送會用到Transport通道,協議使用的是SMTP協議,而郵件接收則用到的是Store容器類,且協議一般廣泛使用POP(最新為POP3)協議,這種協議需要用戶自定義設置里面開啟才能使用,並且目前該協議只支持收件箱的讀取(吐槽下 ‘-.-’ ,要能讀私密文件夾,那豈不***)。
javax.mail.Store:容器類,由它來訪問用戶保存在服務器上的各個郵件夾
示例結構:
本篇示例代碼分了4類(都是在前一章節基礎上進行拆分的,並且把test測試都融合在各自的業務類里面【簡單main方法】)
- EmailEntity 類 郵件基礎父類 【和上一章相同】 點我查看上一章節
- EmailServiceEnity 類 郵件服務支持類,繼承郵件基礎父類,並聲明其他必要的私有屬性(propertis文件、Message消息、Session郵件會話等)
- SendEmailService 類 郵件發送業務類,封裝郵件發送的兩個方法(HTML和附件)
- LookEmailService 類 郵件接收|查看業務類,封裝郵件查看方法(正文閱讀和附件下載)
實例代碼演示:
**************復制此四個類可直接跑測試**************注釋部分我盡可能詳細講解每個方法的作用**************
EmailEntity 類 (有復制之前章節的可忽略此類)

package com.cplatform.movie.back.javamail; import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; /** * 郵件基礎實體類 * @author liuyt * @date 2014-10-24 下午2:12:10 */ public class EmailEntity extends Authenticator { /** * 用戶名(登錄郵箱) */ protected static String username; /** * 密碼 */ protected static String password; /** * 初始化郵箱地址和密碼 * @param username 郵箱 * @param password 密碼 */ public EmailEntity(String username, String password) { EmailEntity.username = "這里填寫發件箱地址"; EmailEntity.password = "這里填寫發件箱密碼"; } /** * 重寫自我檢驗方法 */ @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } String getPassword() { return password; } String getUsername() { return username; } public void setPassword(String password) { EmailEntity.password = password; } public void setUsername(String username) { EmailEntity.username = username; } }
EmailServiceEnity 類 (較之前章節有拆分操作)
package com.cplatform.movie.back.javamail; import java.io.UnsupportedEncodingException; import java.util.Properties; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.NoSuchProviderException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import com.cplatform.movie.back.javamail.SimpleEmailFunction.MyAuthenricator; /** * 郵件服務支持類 * @author liuyt * @date 2014-10-24 下午2:11:38 */ public class EmailServiceEnity extends EmailEntity{ // java.util.propertis 類 private transient Properties props; // 一個郵件會話 private transient Session session; // 郵件消息 private transient MimeMessage message; // 郵件傳輸對象 private Transport transport; // 郵件發送內容 private String content; // 郵件內容格式 private final String CONTENT_TYPE_HTML = "text/html;charset=utf-8"; // 端口號 private final static String MAIL_PORT = "25"; // 郵箱協議常量 public static final String MAIL_PROTOCOL_SMTP = "smtp"; public static final String MAIL_PROTOCOL_POP3 = "pop3"; // 郵箱所使用的協議 private String mailProtocol; // 郵箱服務器列表 private String hostPort; //////////////////分//////////////////界/////////////////////線///////////////////////////// /** * 實參構造 * @param mailToaddress 收件人地址,多個以逗號隔開 * @param content 郵件內容 * @throws MessagingException * @throws UnsupportedEncodingException */ public EmailServiceEnity(String mailToaddress, String content, String mailProtocol) throws UnsupportedEncodingException, MessagingException { super(username, password); this.setMailProtocol(mailProtocol); this.setHostPort(mailProtocol +"."+ username.split("@")[1]); this.content = content; this.session = this.initSession(); this.message = this.initMessage(this.getSession(), mailToaddress); // 這里需要對協議進行判斷,SMTP:為發送協議(初始化Transport) POP3:則為接收協議(只能初始化Store,在接收郵件章節用到) if(this.getMailProtocol().equals(MAIL_PROTOCOL_SMTP)){ this.transport = this.initTransport(this.getSession()); } } /** * 初始化perps文件 * @return */ public Properties initPrope() { // 初始化props文件 props = new Properties(); props.setProperty("mail.transport.protocol", this.getMailProtocol());//發送郵件協議 props.put("mail.smtp.auth", "true"); //需要驗證 props.put("mail.smtp.host", this.getHostPort()); //服務器地址 return props; } /** * 初始化session會話 * @return */ public Session initSession() { session = Session.getInstance(this.initPrope(),new MyAuthenricator(username, password)); session.setDebug(true); return session; } /** * 初始化Message消息 * @param session * @return * @throws MessagingException * @throws UnsupportedEncodingException */ public MimeMessage initMessage(Session session, String mailToaddress) throws MessagingException, UnsupportedEncodingException { message = new MimeMessage(session); // 設置發件人地址 message.setFrom(new InternetAddress(username, "要顯示的發件人名稱")); // 設置郵件主題 message.setSubject("主題:默認主題"); // 設置郵件發送內容和內容的content-type message.setContent(content.toString(),this.CONTENT_TYPE_HTML); // 設置郵件接收人地址 if(mailToaddress.trim().length() > 0) { String [] address = mailToaddress.split(","); for(int i=0; i<address.length; i++) { // addRecipient(該方法為添加收件人列表,參數一為類型:TO-收件人,CC-抄送,參數二為一個郵件地址) message.addRecipient(Message.RecipientType.TO, new InternetAddress(address[i].trim())); // 下面方法為傳遞一個收件地址字符串 (二者方法任選其一即可) message.addRecipients(Message.RecipientType.CC, address[i].trim()); } } return message; } /** * 初始化Transport * @param session * @return * @throws NoSuchProviderException */ public Transport initTransport(Session session) throws NoSuchProviderException { transport = session.getTransport(); return transport; } /***************** 提供必要的get set方法支持 ************飄逸的分割線****************/ public Session getSession() { return session; } public void setSession(Session session) { this.session = session; } public MimeMessage getMessage() { return message; } public void setMessage(MimeMessage message) { this.message = message; } public Properties getProps() { return props; } public String getContentTypeHtml() { return CONTENT_TYPE_HTML; } public static String getMailPort() { return MAIL_PORT; } public String getHostPort() { return hostPort; } public void setHostPort(String hostPort) { this.hostPort = hostPort; } public Transport getTransport() { return transport; } public void setTransport(Transport transport) { this.transport = transport; } public void setProps(Properties props) { this.props = props; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getCONTENT_TYPE_HTML() { return CONTENT_TYPE_HTML; } public static String getMailProtocolSmtp() { return MAIL_PROTOCOL_SMTP; } public static String getMailProtocolPop3() { return MAIL_PROTOCOL_POP3; } public String getMailProtocol() { return mailProtocol; } public void setMailProtocol(String mailProtocol) { this.mailProtocol = mailProtocol; } }
SendEmailService 類
package com.cplatform.movie.back.javamail; import java.io.File; import java.io.UnsupportedEncodingException; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeUtility; /** * 郵件發送業務類 * @author liuyt * @date 2014-10-26 上午11:17:45 */ public class SendEmailService { private EmailServiceEnity serviceEnity; /** * 發送HTML內容郵件 (包括TEXT格式) * @throws MessagingException */ public void sendHtmlOrText() throws MessagingException { this.send(); } /** * 附件發送 * @param file java.io.File * @param fileName 附件名 * @throws MessagingException * @throws UnsupportedEncodingException */ public void sendFile(File file, String fileName) throws MessagingException, UnsupportedEncodingException { // 獲得Message實例 Message message = serviceEnity.getMessage(); // 創建multipart容器用來容納bodyPart(部件) Multipart multipart = new MimeMultipart(); /** * 創建一個BodyPart內容報文 * 每個消息都有多個部分組成,每個部分是一個BodyPart報文部分,多個BodyPart部分又同時組成一個Multipart的容器 */ BodyPart messageBodyPart = new MimeBodyPart(); // 設置該報文的內容 messageBodyPart.setContent(serviceEnity.getContent(),serviceEnity.getCONTENT_TYPE_HTML()); // 添加bodyPart報文部分到multiPart容器 multipart.addBodyPart(messageBodyPart); // 創建一個附件報文 messageBodyPart = new MimeBodyPart(); // 文件源 FileDataSource fds = new FileDataSource(file); // 設置郵件的內含附件 (設置數據源為復件) messageBodyPart.setDataHandler(new DataHandler(fds)); // 設置附件的文件名,需進行編碼,否則文件名會亂碼 messageBodyPart.setFileName(MimeUtility.encodeText(fileName)); // 添加到容器 multipart.addBodyPart(messageBodyPart); // 添加報文容器到消息實例 message.setContent(multipart); // 發送消息 this.send(); } /** * 發送 * 推薦使用方法一,因為方法二如果收件人為多個的話,會為每個人都打開一個Transport通道再關閉 * 而方法一在發送過程中一直保持連接通常,所有操作完成后才關閉 * @throws MessagingException */ public void send() throws MessagingException { Message message = serviceEnity.getMessage(); // 方法一 serviceEnity.getTransport().connect(); serviceEnity.getTransport().sendMessage(message, message.getAllRecipients()); serviceEnity.getTransport().close(); // 方法二 // Transport.send(this.getMessage()); } // main 方法測試 public static void main(String[] args) { SendEmailService service; EmailServiceEnity enity; // 多個收件人中間以逗號間隔 String mailToaddress = "418874847@qq.com,12450374@qq.com"; // 正文(內容)部分 String content = "點擊進入» <a href='http://www.cnblogs.com/liuyitian'>劉一天的博客</a>"; try { service = new SendEmailService(); enity = new EmailServiceEnity(mailToaddress, content, EmailServiceEnity.MAIL_PROTOCOL_SMTP); service.setServiceEnity(enity); service.sendHtmlOrText(); // 測試HTML文本 /** * 切勿使用同一個EmailServiceEnity實例來發送不同內容,如有需要就再初始化一個新實例(否則附件發送失敗且亂碼) * 因為每個實例在發送完郵件后就會關閉Transport */ enity = new EmailServiceEnity(mailToaddress, content, EmailServiceEnity.MAIL_PROTOCOL_SMTP); service.setServiceEnity(enity); // 傳入一個絕對位置的文件路徑 File file = new File("d:/data/adimg/20141022/09/ad_20141022094708943.jpg"); service.sendFile(file,"測試附件發送.jpg"); // 測試復件發送 } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } catch (MessagingException e1) { e1.printStackTrace(); } } public EmailServiceEnity getServiceEnity() { return serviceEnity; } public void setServiceEnity(EmailServiceEnity serviceEnity) { this.serviceEnity = serviceEnity; } }
LookEmailService 類
package com.cplatform.movie.back.javamail; import java.io.DataInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.mail.BodyPart; import javax.mail.Folder; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Store; import javax.mail.internet.MimeUtility; /** * 查看|接收郵件業務類 * @author liuyt * @date 2014-10-24 下午2:04:48 */ public class LookEmailService { private transient EmailServiceEnity emailService; public void lookEmail() throws MessagingException, IOException, InterruptedException { /** * 接收郵件時,郵箱的協議為POP3,SMTP為郵件傳輸協議,這里別搞混了 * 並且檢查你的郵箱設置POP3功能是否開啟 */ emailService = new EmailServiceEnity("", "",EmailServiceEnity.MAIL_PROTOCOL_POP3); /** * javax.mail.Store類用於連接郵件接收服務器,並訪問郵件接收服務器上的各個郵箱夾 * javax.mail.Folder類表示郵件夾 * 通過一個Session我們可以拿到一個郵箱對應的Store */ Store store = emailService.getSession().getStore(emailService.getMailProtocol()); store.connect(emailService.getHostPort(), EmailServiceEnity.username, EmailServiceEnity.password); /** * 通過Store拿到收件箱文件夾 * INBOX 標識獲取到郵件夾里的收件箱 (對於POP3協議僅INBOX可用--蛋疼哦) * 並以只讀方式打開收件箱 */ Folder folder = store.getFolder("INBOX"); folder.open(Folder.READ_ONLY); /** * 讀取到的郵件是存在Message里面,有不同的獲取方法 * 方法一:獲取的是全部郵件,返回一個Message數組 * 方法二:獲取指定條目的郵件(1表示郵箱里面的第一封郵件,也就是最早的一封) * 還有很多方法,如起始位置和結束位置......不一一列舉 */ Message[] messages = folder.getMessages(); // 方法一,得到全部郵件數組 Message message = folder.getMessage(messages.length); // 方法二 System.out.println("郵件接收時間:"+message.getSentDate()); System.out.println("郵件發送者:"+message.getFrom()[0]); System.out.println("郵件主題:"+message.getSubject()); System.out.println("郵件內容:"+message.getContent()); // 內存地址 System.out.println("***********************飄逸的分割線*****************************"); // 得到郵件的Multipart(內容總部件--【包涵附件】) Multipart multipart = (Multipart) message.getContent(); int count = multipart.getCount(); // 部件個數 for(int i=0; i<count; i++) { // 單個部件 注意:單個部件有可能又為一個Multipart,層層嵌套 BodyPart part = multipart.getBodyPart(i); // 單個部件類型 String type = part.getContentType().split(";")[0]; /** * 類型眾多,逐一判斷,其中TEXT、HTML類型可以直接用字符串接收,其余接收為內存地址 * 可能不全,如有沒判斷住的,請自己打印查看類型,在新增判斷 */ if(type.equals("multipart/alternative")) { // HTML (文本和超文本組合) System.out.println("超文本:" + part.getContent().toString()); }else if(type.equals("text/plain")) { // 純文本 System.out.println("純文本:" + part.getContent().toString()); }else if(type.equals("text/html")){ // HTML標簽元素 System.out.println("HTML元素:" + part.getContent().toString()); }else if(type.equals("multipart/related")){ // 內嵌資源 (包涵文本和超文本組合) System.out.println("內嵌資源:" + part.getContent().toString()); }else if(type.contains("application/")) { // 應用附件 (zip、xls、docx等) System.out.println("應用文件:" + part.getContent().toString()); }else if(type.contains("image/")) { // 圖片附件 (jpg、gpeg、gif等) System.out.println("圖片文件:" + part.getContent().toString()); } /*****************************************獲取郵件內容方法***************************************************/ /** * 附件下載 * 這里針對image圖片類型附件做下載操作,其他類型附件同理 */ if(type.contains("image/")) { // 打開附件的輸入流 DataInputStream in = new DataInputStream(part.getInputStream()); // 一個文件輸出流 FileOutputStream out = null; // 獲取附件名 String fileName = part.getFileName(); // 文件名解碼 fileName = MimeUtility.decodeText(fileName); // 根據附件名創建一個File文件 File file = new File("d:/data/" + fileName); // 查看是否有當前文件 Boolean b = file.exists(); if(!b) { out = new FileOutputStream(file); int data; // 循環讀寫 while((data=in.read()) != -1) { out.write(data); } System.out.println("附件:【" + fileName + "】下載完畢,保存路徑為:" + file.getPath()); } // 關流 if(in != null) { in.close(); } if(out != null) { out.close(); } } /** * 獲取超文本復合內容 * 他本是又是一個Multipart容器 * 此時郵件會分為TEXT(純文本)正文和HTML正文(HTML標簽元素) */ if(type.equals("multipart/alternative")) { Multipart m = (Multipart) part.getContent(); for (int k=0; k<m.getCount(); k++) { if(m.getBodyPart(k).getContentType().startsWith("text/plain")) { // 處理文本正文 System.out.println("TEXT文本內容:"+"\n" + m.getBodyPart(k).getContent().toString().trim()+"\n"); } else { // 處理 HTML 正文 System.out.println("HTML文本內容:"+"\n" + m.getBodyPart(k).getContent()+"\n"); } } } } /** * 最后千萬別忘記了關閉 */ folder.close(false); // false為不更新郵件,true為更新,一般在刪除郵件后使用 store.close(); } // main 方法簡單測試 public static void main(String[] args) { try { new LookEmailService().lookEmail(); } catch (IOException e) { e.printStackTrace(); } catch (MessagingException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
到此處本章的代碼部分全部貼出來了,篇幅可能有點長,只是把現有的功能都貼出來了,方便做對比。
本章小結:
- 對代碼再次進行拆分,分為實體類、業務類支持類、發送業務類、接收業務類
- 對郵件的兩大功能(收/發)做簡單對比
- 簡單責任原則,業務類里面能拆分的功能都進行拆分,各負其責,test方法和業務類融合,方便在本類進行測試
- 對於郵件接收,由於內容Content-type類型眾多,可能沒有完全判斷住(具體問題具體分析)
- 常用的郵件協議:SMTP和POP3協議簡單說明(詳細還請度娘腦補)
- 其他細節:(附件編碼問題,正文格式聲明,設置收件人方法【多種】)
- 未涉及:其他功能。如:刪除、回復、轉發等(之后陸續更新)
javamail API 系列篇:
- javamail模擬郵箱功能發送電子郵件-基礎實戰篇
- javamail模擬郵箱功能發送電子郵件-中級實戰篇【新增附件發送方法】
- javamail模擬郵箱功能獲取郵件內容-中級實戰篇【內容|附件下載方法】
- javamail模擬郵箱功能--郵件回復-中級實戰篇【郵件回復方法】
- javamail模擬郵箱功能--郵件刪除-中級實戰篇【郵件標記方法】
寫作不易,難免有疏漏和錯誤,還請慷慨指正,覺得有幫助幫忙推薦哦。
ps:歡迎轉載,轉載請注明出處:http://www.cnblogs.com/liuyitian/p/4051922.html
每天多學一點點 代碼少敲一點點