本系统是基于web的,引用了第三方的API:mail.jar开发包。
一.目录结构的介绍
我们可以到Oracle官网下载mail.jar开发包,我下载的版本是1.4.5。下载成功后,会得到一个javamail1_4_5.zip的文件,然后解压。
首先是根目录下的mail.jar是它的核心包
在lib子目录下有对应如下的jar包,其中mailapi.jar封装了创建邮件内容和面向普通开发人员调用邮件发送和接收的API类,其它三个jar文件(imap.jar、pop3.jar、smtp.jar)则是封装了它们名称相对应协议的服务实现程序。mailapi.jar与其它三个jar文件的关系,犹如JDBC API与各个数据库所实现jdbc驱动程序之间的关系一样。在编译Java邮件程序时,只需要mailapi.jar文件即可,但是,在运行时必须要有相应邮件协议的底层服务实现程序。本次应用程序中只使用到邮件发送功能,所以可以只导入smtp.jar和mailapi.jar这两个文件,如果应用程序需要使用邮件的接收功能,则可以安装pop3.jar或imap.jar和mailapi.jar这两个jar文件,而不用导入整个mail.jar文件。
二.相关协议的介绍
1.SMTP协议
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP协议属于TCP/IP协议族,它帮助每台计算机在发送或中转信件时找到下一个目的地。通过SMTP协议所指定的服务器,就可以把E-mail寄到收信人的服务器上了,整个过程只要几分钟。SMTP服务器则是遵循SMTP协议的发送邮件服务器,用来发送或中转发出的电子邮件。
2.POP协议
POP 代表邮局协议(Post Office Protocol)。目前用的是版本 3,也称 POP3,RFC 1939 定义了这个协议。POP 是一种机制,因特网上大多数人用它得到邮件。它规定每个用户一个邮箱的支持。这就是它所能做的,而这也造成了许多混淆。使用 POP 时,用户熟悉的许多性能并不是由 POP 协议支持的,如查看有几封新邮件消息这一性能。这些性能内建于如 Eudora 或 Microsoft Outlook 之类的程序中,它们能记住一些事,诸如最近一次收到的邮件,还能计算出有多少是新的。
3.IMAP协议
IMAP 是更高级的用于接收消息的协议。在 RFC 2060 中被定义,IMAP 代表因特网消息访问协议(Internet Message Access Protocol),目前用的是版本 4,也称 IMAP4。在用到 IMAP 时,邮件服务器必需支持这个协议。不能仅仅把使用 POP 的程序用于 IMAP,并指望它支持 IMAP 所有性能。假设邮件服务器支持 IMAP,基于 JavaMail 的程序可以利用这种情况 — 用户在服务器上有多个文件夹(folder),并且这些文件夹可以被多个用户共享。
因为有这一更高级的性能,您也许会认为所有用户都会使用 IMAP。事实并不是这样。要求服务器接收新消息,在用户请求时发送到用户手中,还要在每个用户的多个文件夹中维护消息。这样虽然能将消息集中备份,但随着用户长期的邮件夹越来越大,到磁盘空间耗尽时,每个用户都会受到损失。使用 POP,就能卸载邮件服务器上保存的消息了。
最后介绍一下MIME,MINE 代表多用途因特网邮件扩展标准(Multipurpose Internet Mail Extensions)。它不是邮件传输协议。但对传输内容的消息、附件及其它的内容定义了格式。好,以上是邮件发送和接受的基本知识,有了基本知识,我们在结合代码对java Mail进行深入的了解和学习
邮件发送和接受的示意图
邮件发送的示意图
三.Mail发送邮件的封装
public class Mail { private MimeMessage mimeMsg; //MIME邮件对象 private Session session; //邮件配置对象 private Properties props; //系统属性 @SuppressWarnings("unused") private boolean needAuth = false; //smtp是否需要认证 //smtp认证用户名和密码 private String username; private String password; private Multipart mp; //Multipart对象,邮件内容,标题,附件等内容均添加到其中后再生成MimeMessage对象 /** * Constructor * @param smtp 邮件发送服务器 */ public Mail(String smtp){ setSmtpHost(smtp); createMimeMessage(); } /** * 设置邮件发送服务器 * @param hostName String */ public void setSmtpHost(String hostName) { if(props == null) props = System.getProperties(); //获得系统属性对象 props.put("mail.smtp.host",hostName); //设置SMTP主机 } /** * 创建MIME邮件对象 * @return */ public boolean createMimeMessage() { try { System.out.println("准备获取邮件会话对象!"); session = Session.getDefaultInstance(props,null); //获得邮件会话对象 } catch(Exception e){ System.err.println("获取邮件会话对象时发生错误!"+e); return false; } System.out.println("准备创建MIME邮件对象!"); try { mimeMsg = new MimeMessage(session); //创建MIME邮件对象 mp = new MimeMultipart(); return true; } catch(Exception e){ System.err.println("创建MIME邮件对象失败!"+e); return false; } } /** * 设置SMTP是否需要验证 * @param need */ public void setNeedAuth(boolean need) { System.out.println("设置smtp身份认证:mail.smtp.auth = "+need); if(props == null) props = System.getProperties(); if(need){ props.put("mail.smtp.auth","true"); }else{ props.put("mail.smtp.auth","false"); } } /** * 设置用户名和密码 * @param name * @param pass */ public void setNamePass(String name,String pass) { username = name; password = pass; } /** * 设置邮件主题 * @param mailSubject * @return */ public boolean setSubject(String mailSubject) { System.out.println("设置邮件主题!"); try{ mimeMsg.setSubject(mailSubject); return true; } catch(Exception e) { System.err.println("设置邮件主题发生错误!"); return false; } } /** * 设置邮件正文 * @param mailBody String */ public boolean setBody(String mailBody) { try{ BodyPart bp = new MimeBodyPart(); bp.setContent(""+mailBody,"text/html;charset=GBK"); mp.addBodyPart(bp); return true; } catch(Exception e){ System.err.println("设置邮件正文时发生错误!"+e); return false; } } /** * 添加附件 * @param filename String */ public boolean addFileAffix(String filename) { System.out.println("增加邮件附件:"+filename); try{ BodyPart bp = new MimeBodyPart(); FileDataSource fileds = new FileDataSource(filename); bp.setDataHandler(new DataHandler(fileds)); bp.setFileName(fileds.getName()); mp.addBodyPart(bp); return true; } catch(Exception e){ System.err.println("增加邮件附件:"+filename+"发生错误!"+e); return false; } } /** * 设置发信人 * @param from String */ public boolean setFrom(String from) { System.out.println("设置发信人!"); try{ mimeMsg.setFrom(new InternetAddress(from)); //设置发信人 return true; } catch(Exception e) { return false; } } /** * 设置收信人 * @param to String */ public boolean setTo(String to){ if(to == null)return false; try{ mimeMsg.setRecipients(Message.RecipientType.TO,InternetAddress.parse(to)); return true; } catch(Exception e) { return false; } } /** * 设置抄送人 * @param copyto String */ public boolean setCopyTo(String copyto) { if(copyto == null)return false; try{ mimeMsg.setRecipients(Message.RecipientType.CC,(Address[])InternetAddress.parse(copyto)); return true; } catch(Exception e) { return false; } } /** * 发送邮件 */ public boolean sendOut() { try{ mimeMsg.setContent(mp); mimeMsg.saveChanges(); System.out.println("正在发送邮件...."); Session mailSession = Session.getInstance(props,null); Transport transport = mailSession.getTransport("smtp"); transport.connect((String)props.get("mail.smtp.host"),username,password); transport.sendMessage(mimeMsg,mimeMsg.getRecipients(Message.RecipientType.TO)); transport.sendMessage(mimeMsg,mimeMsg.getRecipients(Message.RecipientType.CC)); //transport.send(mimeMsg); System.out.println("发送邮件成功!"); transport.close(); return true; } catch(Exception e) { System.err.println("邮件发送失败!"+e); return false; } } /** * 调用sendOut方法完成邮件发送 * @param smtp * @param from * @param to * @param subject * @param content * @param username * @param password * @return boolean */ public static boolean send(String smtp,String from,String to,String subject,String content,String username,String password) { Mail theMail = new Mail(smtp); theMail.setNeedAuth(true); //需要验证 if(!theMail.setSubject(subject)) return false; if(!theMail.setBody(content)) return false; if(!theMail.setTo(to)) return false; if(!theMail.setFrom(from)) return false; theMail.setNamePass(username,password); if(!theMail.sendOut()) return false; return true; } /** * 调用sendOut方法完成邮件发送,带抄送 * @param smtp * @param from * @param to * @param copyto * @param subject * @param content * @param username * @param password * @return boolean */ public static boolean sendAndCc(String smtp,String from,String to,String copyto,String subject,String content,String username,String password) { Mail theMail = new Mail(smtp); theMail.setNeedAuth(true); //需要验证 if(!theMail.setSubject(subject)) return false; if(!theMail.setBody(content)) return false; if(!theMail.setTo(to)) return false; if(!theMail.setCopyTo(copyto)) return false; if(!theMail.setFrom(from)) return false; theMail.setNamePass(username,password); if(!theMail.sendOut()) return false; return true; } /** * 调用sendOut方法完成邮件发送,带附件 * @param smtp * @param from * @param to * @param subject * @param content * @param username * @param password * @param filename 附件路径 * @return */ public static boolean send(String smtp,String from,String to,String subject,String content,String username,String password,String filename) { Mail theMail = new Mail(smtp); theMail.setNeedAuth(true); //需要验证 if(!theMail.setSubject(subject)) return false; if(!theMail.setBody(content)) return false; if(!theMail.addFileAffix(filename)) return false; if(!theMail.setTo(to)) return false; if(!theMail.setFrom(from)) return false; theMail.setNamePass(username,password); if(!theMail.sendOut()) return false; return true; } /** * 调用sendOut方法完成邮件发送,带附件和抄送 * @param smtp * @param from * @param to * @param copyto * @param subject * @param content * @param username * @param password * @param filename * @return */ public static boolean sendAndCc(String smtp,String from,String to,String copyto,String subject,String content,String username,String password,String filename) { Mail theMail = new Mail(smtp); theMail.setNeedAuth(true); //需要验证 if(!theMail.setSubject(subject)) return false; if(!theMail.setBody(content)) return false; if(!theMail.addFileAffix(filename)) return false; if(!theMail.setTo(to)) return false; if(!theMail.setCopyTo(copyto)) return false; if(!theMail.setFrom(from)) return false; theMail.setNamePass(username,password); if(!theMail.sendOut()) return false; return true; } }代码分析:
第三行中 MimeMessage,前面介绍了MINE 代表多用途因特网邮件扩展标准,它继承自 Message类,javax.mail.Message 类是创建和解析邮件的核心API,它的实例对象可以理解为一封电子邮件。
第四行中Session类,它是一个很容易被误解的类,这归咎于混淆视听的类名。千万不要以为这里的Session像HttpSession一样代表真实的交互会话,但创建Session对象时,并没有对应的物理连接,它只不过是一对配置信息的集合。Session的主要作用包括两个方面:
1)接收各种配置属性信息:通过Properties对象设置的属性信息;
2)初始化JavaMail环境:根据JavaMail的配置文件,初始化JavaMail环境,以便通过Session对象创建其他重要类的实例。
所以,如果把Session更名为Configure也许更容易理解一些
第五行 Properties对象,他表示 属性对象由于JavaMail需要和邮件服务器进行通信,这就要求程序提供许多诸如服务器地址、端口、用户名、密码等信息,JavaMail通过Properties对象封装这些属性的信息
第三十八行 是创建MINE邮件对象的过程,可以看出是通过session配置相应的properties对象信息,从而完成邮件的创建。
第185行是发送邮件的代码,可以看出先是通过session类初始化javaMail的初始环境,获取Properties对象;然后在调用session的Transport方法,(其实session有传输和存储两种方法,但是本web应用中只用到了邮件的发送,所以Store的相关方法不细讲)
Transport transport = mailSession.getTransport("smtp");
transport.connect((String)props.get("mail.smtp.host"),username,password);
表示通过session获取指定类型的Transport,然后配置服务器端口,用户名和密码等相关验证信息。
第195行 表示消息发送
此处是使用 Transport 类。这个类用协议指定的语言发送消息(通常是 SMTP)。它是抽象类,它的工作方式与 Session 有些类似。仅调用静态 send() 方法
第273行用于验证发送是否成功。
上面我们对,邮件的发送进行了很好的封装,下面我们就通过一个web页面来进行调用测试
首先是一个我们的邮件发送客户端
<body> <center> <p>Send Email using JSP</p> </center> <form action="SendMailServlet" method="post" enctype="multipart/form-data"> 收件人:<input type="text" name="to"><br> 发件人:<input type="text" name="from"><br> 发件人密码:<input type="password" name="password"><br> 标题:<input type="text" name="subject"><br> 内容<br> <textarea name="content" rows="10" cols="80"></textarea><br> <input type="submit" value="提交"> </form> </body>交由后台的sendMailServlet处理,它的代码如下
public class SendMailServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String smtp = "smtp.163.com"; String from = req.getParameter("from"); String to = req.getParameter("to"); String copyto = "[email protected]"; String subject = req.getParameter("subject"); String content = req.getParameter("content"); String username=req.getParameter("from"); String password=req.getParameter("password"); Mail.sendAndCc(smtp, from, to, copyto, subject, content, username, password); if(Mail.send(smtp, from, copyto, subject, content, username, password)){ req.setAttribute("result", "发送成功请到邮箱查收"); }else{ req.setAttribute("result", "发送失败"); } req.getRequestDispatcher("MailResult.jsp").forward(req, resp); } }处理页面
<body> 结果显示:${result} </body>最后附上web.xml的配置文件
<servlet> <description>This is the description of my J2EE component</description> <display-name>This is the display name of my J2EE component</display-name> <servlet-name>SendMailServlet</servlet-name> <servlet-class>com.qzp.servlet.SendMailServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>SendMailServlet</servlet-name> <url-pattern>/SendMailServlet</url-pattern> </servlet-mapping>
点击提交完成邮件发送。