JavaMail:在Web应用下完整接收、解析复杂邮件

其实,让我们自己来解析一封复杂的邮件是很不容易的,邮件里面格式、规范复杂得很。幸运的是,我们所用的浏览器一定内置了解析各种数据类型的数据处理模块,我们只需要在把数据流传输给浏览器之前明确地指定该数据流属于哪种数据类型即可,之后一切的解析操作由浏览器自动帮我们完成。

现在我们想要像 Outlook 客户端或者登录网页邮箱那样子接收、查看邮件,而这些邮件中可能包含附件、正文中可能内嵌图片、音频等等。好吧,我们来实现一下吧。

程序结构:

1、mailboxLogin.html 文件用于提供一个用户登录界面,由用户填写 POP3 服务器主机名、用户名和密码;

2、connectServer.jsp 文件用于获取登录界面中的登录信息,并连接到 POP3 服务器,还要读取显示出邮箱中的所有邮件列表,再提供一个查看邮件详细内容的超链接;

3、showMails.jsp 文件用于将一个 Web 页面分成两帧,目的在上一篇文章中讲过,就是分别指定不同的 MIME 消息头类型来让浏览器解析、显示出邮件头内容和邮件正文内容;

4、ShowHeader.java 文件是处理邮件头内容的 Servlet 程序;

5、ShowContent.java 文件时处理邮件正文内容的 Servlet 程序;

6、HandleAttachments.java 文件是当从 ShowHeader.java 程序处理邮件头内容时,若发现该邮件包含附件,则交给 HandleAttachments.java 这个 Servlet 程序进行处理,它能够在邮件头中给出附件的文件名、超链接,所以用户可以点击下载。这是上篇文章中所缺乏的,也是这个程序实现中的重点!

7、web.xml 文件用于根据前面的 Servlet 程序来部署、配置相关的映射信息。

好吧,讲了那么多让人不知所云的东西,来点截图啊、代码啊最让我兴奋的了,因为截图、所有代码我保证都是完整的(或许自己尝试一下可以弄出更多的截图),嘻嘻…

我们依然需要 Tomcat 这个服务器,关于 JSP 、Servlet 编程技术、部署配置映射信息等方面的内容就不能多讲了。这里先说明,我们要登录的邮箱时 testhao@126.com ,用户名为 testhao ,密码为 123456,里面的邮件跟上篇文章重点截图一样,不过我自己多发送了一封包含3封附件的邮件哦,如下:(更多精彩截图,请继续看下文)

JavaMail:在Web应用下完整接收、解析复杂邮件

JavaMail:在Web应用下完整接收、解析复杂邮件

JavaMail:在Web应用下完整接收、解析复杂邮件

程序代码: 

mailboxLogin.html


  1. <hmtl> 
  2.     <head> 
  3.         <title>邮箱登录页面</title> 
  4.     </head> 
  5.     <body> 
  6.         <form action="connectServer.jsp" method="post"> 
  7.             POP3服务器主机名:<input name="pop3Server" type="text"></br> 
  8.             邮箱用户名:<input name="user" type="text"></br> 
  9.             邮箱密码:<input name="pwd" type="password"></br> 
  10.             <input type="submit" value="登录"> 
  11.             <input type="reset" value="重置"></br> 
  12.         </form> 
  13.     </body> 
  14. </html> 

connectServer.jsp


  1. <%@ page  
  2.     import="javax.mail.*,java.util.Properties" 
  3.     contentType="text/html;charset=gbk" %>  
  4.  
  5. <%  
  6.     String pop3Server = request.getParameter("pop3Server");  
  7.     String user = request.getParameter("user");  
  8.     String pwd = request.getParameter("pwd");  
  9.  
  10.     // 创建一个有具体连接信息的Properties对象  
  11.     Properties props = new Properties();  
  12.     props.setProperty("mail.store.protocol""pop3");  
  13.     props.setProperty("mail.pop3.host", pop3Server);  
  14.       
  15.     // 使用Properties对象获得Session对象  
  16.     Session mailSession = Session.getDefaultInstance(props);  
  17.     //mailSession.setDebug(true);  
  18.  
  19.     Folder folder = null;  
  20.     try{          
  21.         // 利用Session对象获得Store对象,并连接pop3服务器  
  22.         Store store = mailSession.getStore();  
  23.         store.connect(pop3Server, user, pwd);  
  24.           
  25.         // 获得邮箱内的邮件夹Folder对象,以"读-写"打开  
  26.         folder = store.getFolder("inbox");  
  27.         folder.open(Folder.READ_WRITE);  
  28.  
  29.     }catch(Exception e){  
  30.         e.printStackTrace();  
  31.     }  
  32. //  Folder folder = POP3Connect.getFolder(pop3Server,user,pwd);  
  33.     session.setAttribute("folder", folder);  
  34.  
  35.     String from = null;  
  36.     String subject = null;  
  37.     Message [] messages = folder.getMessages();  
  38.     int messageCounts = messages.length;  
  39.     for(int i = 0; i < messageCounts; i++)  
  40.     {  
  41.         try{  
  42.             from = messages[i].getFrom()[0].toString();  
  43.             subject = messages[i].getSubject();  
  44.             out.println("<B>邮件 " + (i+1) + "</B>");  
  45. %>  
  46.         </br>发件人地址:<%=from %></br>  
  47.         邮件主题:<%=subject %></br>  
  48.         <a href="showMails.jsp?msgnum=<%=i+1 %>">  
  49.         >> 查看邮件!!!</a></br></br>  
  50. <%  
  51.         }catch(Exception e){  
  52.             e.printStackTrace();  
  53.         }  
  54.     }  
  55. %> 

showMails.jsp


  1. <frameset rows="25%,*"> 
  2.     <frame src="/JavaMail/ShowHeader?msgnum=  
  3.             <%=request.getParameter("msgnum")%>scrolling="yes"> 
  4.     <frame src="/JavaMail/ShowContent?msgnum=  
  5.             <%=request.getParameter("msgnum")%>scrolling="yes"> 
  6. </frameset> 

ShowHeader.java


  1. import java.io.*;  
  2. import java.text.DateFormat;  
  3. import javax.mail.internet.MimeUtility;  
  4. import javax.mail.*;  
  5. import javax.servlet.*;  
  6. import javax.servlet.http.*;  
  7.  
  8. // 解析邮件头消息,包括判断是否有附件  
  9. public class ShowHeader extends HttpServlet  
  10. {  
  11.     public void doGet(HttpServletRequest request,  
  12.         HttpServletResponse response) throws ServletException, IOException  
  13.     {  
  14.         response.setContentType("text/html;charset=gbk");  
  15.         PrintWriter out = response.getWriter();  
  16.         HttpSession session = request.getSession();  
  17.  
  18.         Folder folder = (Folder)session.getAttribute("folder");  
  19.         int msgnum = Integer.parseInt(request.getParameter("msgnum"));  
  20.  
  21.         try{                      
  22.             Message message = folder.getMessage(msgnum);  
  23.             String from = (message.getFrom()[0]).toString();  
  24.             String subject = message.getSubject();  
  25.             String sentDate = DateFormat.getInstance().format(message.getSentDate());  
  26.  
  27.             out.println("邮件主题:" + subject + "<br/>");  
  28.             out.println("发件人地址:" + from + "<br/>");  
  29.             out.println("发送日期:" + sentDate + "<br/>");  
  30.               
  31.             // 如果该邮件是组合型"multipart/*"则可能包含附件等  
  32.             if(message.isMimeType("multipart/*"))  
  33.             {  
  34.                 Multipart multipart = (Multipart)message.getContent();  
  35.                 int bodyCounts = multipart.getCount();  
  36.                 for(int i = 0; i < bodyCounts; i++)  
  37.                 {  
  38.                     BodyPart bodypart = multipart.getBodyPart(i);  
  39.                     // 如果该BodyPart对象包含附件,则应该解析出来  
  40.                     if(bodypart.getDisposition() != null)  
  41.                     {  
  42.                         String filename = bodypart.getFileName();  
  43.                         if(filename.startsWith("=?"))  
  44.                         {  
  45.                             // 把文件名编码成符合RFC822规范  
  46.                             filename = MimeUtility.decodeText(filename);  
  47.                         }  
  48.                         // 生成打开附件的超链接  
  49.                         out.print("<B>附件 " + (i+1) + ":</B>");  
  50.                         out.println("<a href=HandleAttachments?msgnum="   
  51.                             + msgnum + "&&bodynum=" + i + "&&filename=" 
  52.                             + filename + ">" + filename + "</a></br>");  
  53.                     }  
  54.                 }  
  55.             }  
  56.         }catch(Exception e){  
  57.             e.printStackTrace();  
  58.         }  
  59.     }  

ShowContent.java


  1. import java.io.*;  
  2. import javax.mail.*;  
  3. import javax.servlet.*;  
  4. import javax.servlet.http.*;  
  5.  
  6. // 处理邮件的正文部分  
  7. public class ShowContent extends HttpServlet  
  8. {  
  9.     public void doGet(HttpServletRequest request,  
  10.         HttpServletResponse response) throws ServletException, IOException  
  11.     {  
  12.         // 获取输出流、Session 会话对象、邮件夹 Folder 对象  
  13.         ServletOutputStream out = response.getOutputStream();  
  14.         HttpSession session = request.getSession();  
  15.         Folder folder = (Folder)session.getAttribute("folder");  
  16.         int msgnum = Integer.parseInt(request.getParameter("msgnum"));  
  17.  
  18.         try{  
  19.             Message message = folder.getMessage(msgnum);  
  20.             if(!message.isMimeType("multipart/mixed"))  
  21.             {  
  22.                 // 若邮件类型不是"mixed"则表明不包含附件,  
  23.                 // 并设置类型让浏览器直接输出正文  
  24.                 response.setContentType("message/rfc822");  
  25.                 message.writeTo(out);  
  26.             }else{  
  27.                 // 如果是"mixed"型,则遍历所有BodyPart对象,  
  28.                 // 把不包含附件的邮件正文打印出来。  
  29.                 // 这是为了不让该程序既输出正文又传输附件大量的数据  
  30.                 Multipart multipart = (Multipart)message.getContent();  
  31.                 int bodyCounts = multipart.getCount();  
  32.                 for(int i = 0; i < bodyCounts; i++)  
  33.                 {  
  34.                     BodyPart bodypart = multipart.getBodyPart(i);  
  35.                     // 不是"mixed"型且不包含附件  
  36.                     if(!bodypart.isMimeType("multipart/mixed")   
  37.                         && bodypart.getDisposition() == null)  
  38.                     {  
  39.                         response.setContentType("message/rfc822");  
  40.                         bodypart.writeTo(out);                        
  41.                     }  
  42.                 }  
  43.             }  
  44.         }catch(Exception e){  
  45.             e.printStackTrace();  
  46.         }  
  47.     }  

HandleAttachments.java


  1. import java.io.*;  
  2. import javax.mail.*;  
  3. import javax.servlet.*;  
  4. import javax.servlet.http.*;  
  5.  
  6. // 处理邮件中的附件  
  7. public class HandleAttachments extends HttpServlet  
  8. {  
  9.     public void doGet(HttpServletRequest request,  
  10.         HttpServletResponse response) throws ServletException, IOException  
  11.     {  
  12.         response.setContentType("text/html;charset=gbk");  
  13.         PrintWriter out = response.getWriter();  
  14.         HttpSession session = request.getSession();  
  15.  
  16.         int msgnum = Integer.parseInt(request.getParameter("msgnum"));  
  17.         int bodynum = Integer.parseInt(request.getParameter("bodynum"));          
  18.         Folder folder = (Folder)session.getAttribute("folder");  
  19.         String filename = request.getParameter("filename");  
  20.  
  21.         try{  
  22.             Message message = folder.getMessage(msgnum);  
  23.             // 将消息头类型设置为附件类型  
  24.             response.setHeader("Content-Disposition",   
  25.                 "attachment;filename=" + filename);  
  26.  
  27.             Multipart multipart = (Multipart)message.getContent();  
  28.             BodyPart bodypart = multipart.getBodyPart(bodynum);  
  29.  
  30.             InputStream input = bodypart.getInputStream();  
  31.             int temp = 0;  
  32.             while((temp = input.read()) != -1)  
  33.             {  
  34.                 out.write(temp);  
  35.             }  
  36.         }catch(Exception e){  
  37.             e.printStackTrace();  
  38.         }  
  39.     }  

web.xml


  1. <?xml version="1.0" encoding="gb2312"?> 
  2.  
  3. <web-app xmlns="http://java.sun.com/xml/ns/j2ee" 
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" 
  6.     version="2.4"> 
  7.       
  8.     <servlet> 
  9.         <servlet-name>ShowHeader</servlet-name> 
  10.         <servlet-class>ShowHeader</servlet-class> 
  11.     </servlet>      
  12.     <servlet-mapping> 
  13.         <servlet-name>ShowHeader</servlet-name> 
  14.         <url-pattern>/ShowHeader</url-pattern> 
  15.     </servlet-mapping> 
  16.        
  17.     <servlet> 
  18.         <servlet-name>ShowContent</servlet-name> 
  19.         <servlet-class>ShowContent</servlet-class> 
  20.     </servlet>      
  21.     <servlet-mapping> 
  22.         <servlet-name>ShowContent</servlet-name> 
  23.         <url-pattern>/ShowContent</url-pattern> 
  24.     </servlet-mapping>      
  25.        
  26.     <servlet> 
  27.         <servlet-name>HandleAttachments</servlet-name> 
  28.         <servlet-class>HandleAttachments</servlet-class> 
  29.     </servlet>      
  30.     <servlet-mapping> 
  31.         <servlet-name>HandleAttachments</servlet-name> 
  32.         <url-pattern>/HandleAttachments</url-pattern> 
  33.     </servlet-mapping> 
  34.       
  35. </web-app> 

测试过程:(其实就是精彩的截图啦)

JavaMail:在Web应用下完整接收、解析复杂邮件

 

JavaMail:在Web应用下完整接收、解析复杂邮件

JavaMail:在Web应用下完整接收、解析复杂邮件

JavaMail:在Web应用下完整接收、解析复杂邮件

JavaMail:在Web应用下完整接收、解析复杂邮件

好了,精彩截图没了吗?不是的,我们还要与 126 邮箱中的解析、显示效果比对一下,如下:

JavaMail:在Web应用下完整接收、解析复杂邮件

又是这个问题:

为什么我们明明才上传了 3 个附件啊(见最上面的图),这里显示为 4 个了。我猜测的原因在前面的文章中也说过了,它把邮件正文中的图片也解析为附件了,不同的邮件服务器在解析发送、接收、解析邮件时都有自己的方式、策略,这个不理了。不过话说回来,我们自己写的程序好像更加合理一点哦,直接显示 3 个附件,真好!

小结:

1、在这个基于 Tomcat 的 Web 应用中,只用解析邮件中的附件是新的知识,其他的都讲过了;

2、关于程序代码结构、内容是否高效的问题,在这些文章中都没有太多注意,原因是比较注重实现想要的功能,这个不足要意识到并且逐步改过来;

3、关于 JavaMail 邮件开发的学习似乎就到此告一段落了,从最原始的用 Windows 下的 telnet 程序连接服务器手工一条一条命令地发送、接收邮件,到自己写了个 GUI 程序封装这些邮件发送命令以达到真正的纯文本邮件发送的功能,再到学习 JavaMail API 更轻松的创建邮件内容、邮件发送、邮件接收、运用 Tomcat 和浏览器实现邮件的解析…

噢,好像是学习完了。但是,编程学习要达到卖油翁的“无他, 唯手熟尔”绝对是一条漫长艰苦的道路,在此源于大家互相交流、共同学习、一起进步!加油!!!

其实,有时间的话我们也可以扩展上面的程序,综合前面所有文章中的内容,实现一个能够发送邮件,上传图片、附件,以及接收、解析、查看邮件的综合应用…



本文转自 xxxx66yyyy 51CTO博客,原文链接:http://blog.51cto.com/haolloyin/357204,如需转载请自行联系原作者

上一篇:运维监控系统建设 | 学习笔记


下一篇:【D3.js 学习总结】15、D3布局-堆栈图