其实,让我们自己来解析一封复杂的邮件是很不容易的,邮件里面格式、规范复杂得很。幸运的是,我们所用的浏览器一定内置了解析各种数据类型的数据处理模块,我们只需要在把数据流传输给浏览器之前明确地指定该数据流属于哪种数据类型即可,之后一切的解析操作由浏览器自动帮我们完成。
现在我们想要像 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封附件的邮件哦,如下:(更多精彩截图,请继续看下文)
程序代码:?
mailboxLogin.html
- <hmtl>?
- ????<head>?
- ????????<title>邮箱登录页面</title>?
- ????</head>?
- ????<body>?
- ????????<form?action="connectServer.jsp"?method="post">?
- ????????????POP3服务器主机名:<input?name="pop3Server"?type="text"></br>?
- ????????????邮箱用户名:<input?name="user"?type="text"></br>?
- ????????????邮箱密码:<input?name="pwd"?type="password"></br>?
- ????????????<input?type="submit"?value="登录">?
- ????????????<input?type="reset"?value="重置"></br>?
- ????????</form>?
- ????</body>?
- </html>?
connectServer.jsp
- <%@?page ?
- ????import="javax.mail.*,java.util.Properties"?
- ????contentType="text/html;charset=gbk"?%> ?
- ?
- <% ?
- ????String?pop3Server?=?request.getParameter("pop3Server"); ?
- ????String?user?=?request.getParameter("user"); ?
- ????String?pwd?=?request.getParameter("pwd"); ?
- ?
- ????//?创建一个有具体连接信息的Properties对象 ?
- ????Properties?props?=?new?Properties(); ?
- ????props.setProperty("mail.store.protocol",?"pop3"); ?
- ????props.setProperty("mail.pop3.host",?pop3Server); ?
- ???? ?
- ????//?使用Properties对象获得Session对象 ?
- ????Session?mailSession?=?Session.getDefaultInstance(props); ?
- ????//mailSession.setDebug(true); ?
- ?
- ????Folder?folder?=?null; ?
- ????try{???????? ?
- ????????//?利用Session对象获得Store对象,并连接pop3服务器 ?
- ????????Store?store?=?mailSession.getStore(); ?
- ????????store.connect(pop3Server,?user,?pwd); ?
- ???????? ?
- ????????//?获得邮箱内的邮件夹Folder对象,以"读-写"打开 ?
- ????????folder?=?store.getFolder("inbox"); ?
- ????????folder.open(Folder.READ_WRITE); ?
- ?
- ????}catch(Exception?e){ ?
- ????????e.printStackTrace(); ?
- ????} ?
- //??Folder?folder?=?POP3Connect.getFolder(pop3Server,user,pwd); ?
- ????session.setAttribute("folder",?folder); ?
- ?
- ????String?from?=?null; ?
- ????String?subject?=?null; ?
- ????Message?[]?messages?=?folder.getMessages(); ?
- ????int?messageCounts?=?messages.length; ?
- ????for(int?i?=?0;?i?<?messageCounts;?i++) ?
- ????{ ?
- ????????try{ ?
- ????????????from?=?messages[i].getFrom()[0].toString(); ?
- ????????????subject?=?messages[i].getSubject(); ?
- ????????????out.println("<B>邮件?"?+?(i+1)?+?"</B>"); ?
- %> ?
- ????????</br>发件人地址:<%=from?%></br> ?
- ????????邮件主题:<%=subject?%></br> ?
- ????????<a?href="showMails.jsp?msgnum=<%=i+1?%>"> ?
- ????????>>?查看邮件!!!</a></br></br> ?
- <% ?
- ????????}catch(Exception?e){ ?
- ????????????e.printStackTrace(); ?
- ????????} ?
- ????} ?
- %>?
showMails.jsp
- <frameset?rows="25%,*">?
- ????<frame?src="/JavaMail/ShowHeader?msgnum= ?
- ????????????<%=request.getParameter("msgnum")%>"?scrolling="yes">?
- ????<frame?src="/JavaMail/ShowContent?msgnum= ?
- ????????????<%=request.getParameter("msgnum")%>"?scrolling="yes">?
- </frameset>?
ShowHeader.java
- import?java.io.*; ?
- import?java.text.DateFormat; ?
- import?javax.mail.internet.MimeUtility; ?
- import?javax.mail.*; ?
- import?javax.servlet.*; ?
- import?javax.servlet.http.*; ?
- ?
- //?解析邮件头消息,包括判断是否有附件 ?
- public?class?ShowHeader?extends?HttpServlet ?
- { ?
- ????public?void?doGet(HttpServletRequest?request, ?
- ????????HttpServletResponse?response)?throws?ServletException,?IOException ?
- ????{ ?
- ????????response.setContentType("text/html;charset=gbk"); ?
- ????????PrintWriter?out?=?response.getWriter(); ?
- ????????HttpSession?session?=?request.getSession(); ?
- ?
- ????????Folder?folder?=?(Folder)session.getAttribute("folder"); ?
- ????????int?msgnum?=?Integer.parseInt(request.getParameter("msgnum")); ?
- ?
- ????????try{???????????????????? ?
- ????????????Message?message?=?folder.getMessage(msgnum); ?
- ????????????String?from?=?(message.getFrom()[0]).toString(); ?
- ????????????String?subject?=?message.getSubject(); ?
- ????????????String?sentDate?=?DateFormat.getInstance().format(message.getSentDate()); ?
- ?
- ????????????out.println("邮件主题:"?+?subject?+?"<br/>"); ?
- ????????????out.println("发件人地址:"?+?from?+?"<br/>"); ?
- ????????????out.println("发送日期:"?+?sentDate?+?"<br/>"); ?
- ???????????? ?
- ????????????//?如果该邮件是组合型"multipart/*"则可能包含附件等 ?
- ????????????if(message.isMimeType("multipart/*")) ?
- ????????????{ ?
- ????????????????Multipart?multipart?=?(Multipart)message.getContent(); ?
- ????????????????int?bodyCounts?=?multipart.getCount(); ?
- ????????????????for(int?i?=?0;?i?<?bodyCounts;?i++) ?
- ????????????????{ ?
- ????????????????????BodyPart?bodypart?=?multipart.getBodyPart(i); ?
- ????????????????????//?如果该BodyPart对象包含附件,则应该解析出来 ?
- ????????????????????if(bodypart.getDisposition()?!=?null) ?
- ????????????????????{ ?
- ????????????????????????String?filename?=?bodypart.getFileName(); ?
- ????????????????????????if(filename.startsWith("=?")) ?
- ????????????????????????{ ?
- ????????????????????????????//?把文件名编码成符合RFC822规范 ?
- ????????????????????????????filename?=?MimeUtility.decodeText(filename); ?
- ????????????????????????} ?
- ????????????????????????//?生成打开附件的超链接 ?
- ????????????????????????out.print("<B>附件?"?+?(i+1)?+?":</B>"); ?
- ????????????????????????out.println("<a?href=HandleAttachments?msgnum="? ?
- ????????????????????????????+?msgnum?+?"&&bodynum="?+?i?+?"&&filename="?
- ????????????????????????????+?filename?+?">"?+?filename?+?"</a></br>"); ?
- ????????????????????} ?
- ????????????????} ?
- ????????????} ?
- ????????}catch(Exception?e){ ?
- ????????????e.printStackTrace(); ?
- ????????} ?
- ????} ?
- }?
ShowContent.java
- import?java.io.*; ?
- import?javax.mail.*; ?
- import?javax.servlet.*; ?
- import?javax.servlet.http.*; ?
- ?
- //?处理邮件的正文部分 ?
- public?class?ShowContent?extends?HttpServlet ?
- { ?
- ????public?void?doGet(HttpServletRequest?request, ?
- ????????HttpServletResponse?response)?throws?ServletException,?IOException ?
- ????{ ?
- ????????//?获取输出流、Session?会话对象、邮件夹?Folder?对象 ?
- ????????ServletOutputStream?out?=?response.getOutputStream(); ?
- ????????HttpSession?session?=?request.getSession(); ?
- ????????Folder?folder?=?(Folder)session.getAttribute("folder"); ?
- ????????int?msgnum?=?Integer.parseInt(request.getParameter("msgnum")); ?
- ?
- ????????try{ ?
- ????????????Message?message?=?folder.getMessage(msgnum); ?
- ????????????if(!message.isMimeType("multipart/mixed")) ?
- ????????????{ ?
- ????????????????//?若邮件类型不是"mixed"则表明不包含附件, ?
- ????????????????//?并设置类型让浏览器直接输出正文 ?
- ????????????????response.setContentType("message/rfc822"); ?
- ????????????????message.writeTo(out); ?
- ????????????}else{ ?
- ????????????????//?如果是"mixed"型,则遍历所有BodyPart对象, ?
- ????????????????//?把不包含附件的邮件正文打印出来。 ?
- ????????????????//?这是为了不让该程序既输出正文又传输附件大量的数据 ?
- ????????????????Multipart?multipart?=?(Multipart)message.getContent(); ?
- ????????????????int?bodyCounts?=?multipart.getCount(); ?
- ????????????????for(int?i?=?0;?i?<?bodyCounts;?i++) ?
- ????????????????{ ?
- ????????????????????BodyPart?bodypart?=?multipart.getBodyPart(i); ?
- ????????????????????//?不是"mixed"型且不包含附件 ?
- ????????????????????if(!bodypart.isMimeType("multipart/mixed")? ?
- ????????????????????????&&?bodypart.getDisposition()?==?null) ?
- ????????????????????{ ?
- ????????????????????????response.setContentType("message/rfc822"); ?
- ????????????????????????bodypart.writeTo(out);?????????????????????? ?
- ????????????????????} ?
- ????????????????} ?
- ????????????} ?
- ????????}catch(Exception?e){ ?
- ????????????e.printStackTrace(); ?
- ????????} ?
- ????} ?
- }?
HandleAttachments.java
- import?java.io.*; ?
- import?javax.mail.*; ?
- import?javax.servlet.*; ?
- import?javax.servlet.http.*; ?
- ?
- //?处理邮件中的附件 ?
- public?class?HandleAttachments?extends?HttpServlet ?
- { ?
- ????public?void?doGet(HttpServletRequest?request, ?
- ????????HttpServletResponse?response)?throws?ServletException,?IOException ?
- ????{ ?
- ????????response.setContentType("text/html;charset=gbk"); ?
- ????????PrintWriter?out?=?response.getWriter(); ?
- ????????HttpSession?session?=?request.getSession(); ?
- ?
- ????????int?msgnum?=?Integer.parseInt(request.getParameter("msgnum")); ?
- ????????int?bodynum?=?Integer.parseInt(request.getParameter("bodynum"));???????? ?
- ????????Folder?folder?=?(Folder)session.getAttribute("folder"); ?
- ????????String?filename?=?request.getParameter("filename"); ?
- ?
- ????????try{ ?
- ????????????Message?message?=?folder.getMessage(msgnum); ?
- ????????????//?将消息头类型设置为附件类型 ?
- ????????????response.setHeader("Content-Disposition",? ?
- ????????????????"attachment;filename="?+?filename); ?
- ?
- ????????????Multipart?multipart?=?(Multipart)message.getContent(); ?
- ????????????BodyPart?bodypart?=?multipart.getBodyPart(bodynum); ?
- ?
- ????????????InputStream?input?=?bodypart.getInputStream(); ?
- ????????????int?temp?=?0; ?
- ????????????while((temp?=?input.read())?!=?-1) ?
- ????????????{ ?
- ????????????????out.write(temp); ?
- ????????????} ?
- ????????}catch(Exception?e){ ?
- ????????????e.printStackTrace(); ?
- ????????} ?
- ????} ?
- }?
web.xml
- <?xml?version="1.0"?encoding="gb2312"?>?
- ?
- <web-app?xmlns="http://java.sun.com/xml/ns/j2ee"?
- ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?
- ????xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee?http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"?
- ????version="2.4">?
- ???? ?
- ????<servlet>?
- ????????<servlet-name>ShowHeader</servlet-name>?
- ????????<servlet-class>ShowHeader</servlet-class>?
- ????</servlet>???? ?
- ????<servlet-mapping>?
- ????????<servlet-name>ShowHeader</servlet-name>?
- ????????<url-pattern>/ShowHeader</url-pattern>?
- ????</servlet-mapping>?
- ????? ?
- ????<servlet>?
- ????????<servlet-name>ShowContent</servlet-name>?
- ????????<servlet-class>ShowContent</servlet-class>?
- ????</servlet>???? ?
- ????<servlet-mapping>?
- ????????<servlet-name>ShowContent</servlet-name>?
- ????????<url-pattern>/ShowContent</url-pattern>?
- ????</servlet-mapping>???? ?
- ????? ?
- ????<servlet>?
- ????????<servlet-name>HandleAttachments</servlet-name>?
- ????????<servlet-class>HandleAttachments</servlet-class>?
- ????</servlet>???? ?
- ????<servlet-mapping>?
- ????????<servlet-name>HandleAttachments</servlet-name>?
- ????????<url-pattern>/HandleAttachments</url-pattern>?
- ????</servlet-mapping>?
- ???? ?
- </web-app>?
测试过程:(其实就是精彩的截图啦)
?
好了,精彩截图没了吗?不是的,我们还要与 126 邮箱中的解析、显示效果比对一下,如下:
又是这个问题:
为什么我们明明才上传了 3 个附件啊(见最上面的图),这里显示为 4 个了。我猜测的原因在前面的文章中也说过了,它把邮件正文中的图片也解析为附件了,不同的邮件服务器在解析发送、接收、解析邮件时都有自己的方式、策略,这个不理了。不过话说回来,我们自己写的程序好像更加合理一点哦,直接显示 3 个附件,真好!
小结:
1、在这个基于 Tomcat 的 Web 应用中,只用解析邮件中的附件是新的知识,其他的都讲过了;
2、关于程序代码结构、内容是否高效的问题,在这些文章中都没有太多注意,原因是比较注重实现想要的功能,这个不足要意识到并且逐步改过来;
3、关于 JavaMail 邮件开发的学习似乎就到此告一段落了,从最原始的用 Windows 下的 telnet 程序连接服务器手工一条一条命令地发送、接收邮件,到自己写了个 GUI 程序封装这些邮件发送命令以达到真正的纯文本邮件发送的功能,再到学习 JavaMail API 更轻松的创建邮件内容、邮件发送、邮件接收、运用 Tomcat 和浏览器实现邮件的解析…
噢,好像是学习完了。但是,编程学习要达到卖油翁的“无他, 唯手熟尔”绝对是一条漫长艰苦的道路,在此源于大家互相交流、共同学习、一起进步!加油!!!
其实,有时间的话我们也可以扩展上面的程序,综合前面所有文章中的内容,实现一个能够发送邮件,上传图片、附件,以及接收、解析、查看邮件的综合应用…
我的相关文章:
图解使用Telnet程序手工发送邮件
简单的E-mail发送端程序的Java实现
图解使用telnet程序手工接收邮件及其过程
JavaMail:邮件发送以及sina、163、QQ服务器不同的解析结果(附图)
JavaMail:简单的邮件接收程序
JavaMail:利用Tomcat和浏览器解析邮件内容
本文出自 “蚂蚁” 博客,请务必保留此出处http://haolloyin.blog.51cto.com/1177454/357204