基于web的java Mail的邮件发送系统的详解

本系统是基于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>

点击提交完成邮件发送。

以上就是一个完整的基于web的邮件发送系统。如有理解不到位的望大家指正。

时间: 2024-07-30 01:16:25

基于web的java Mail的邮件发送系统的详解的相关文章

Spring基于事件驱动模型的订阅发布模式代码实例详解

代码下载地址:http://www.zuidaima.com/share/1791499571923968.htm 原文:Spring基于事件驱动模型的订阅发布模式代码实例详解 事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理解它的几个关键点: 首先是一种对象间的一对多的关系:最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方): 当目标发送改变(发布),观察者(订阅者)就可以接收到改变: 观察者如何处理(如行人如何走,是快走/慢走/不走,目标不会管的

Java学习-007-Log4J 日志记录配置文件详解及实例源代码

此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:2015-1-30 13:54:02,请知悉. 所需的 jar 包下载链接为:http://yunpan.cn/cKE56sxqtQCfP  访问密码 63d8 有关 Log4J 日志文件中日志级别及文件配置的详细情况,在 Log4J 的配置文件(xml.properties)中有详细的介绍,敬请参阅!

JAVA学习篇--javaweb之Filter详解

在DRP项目中,多次提到了Filter,它解决了字符集的统一设置以及统一控制简单WebCache,从中我们可以体会到,它给我们带来的好处不仅仅是减少代码量这么简单,它的出现避免了我们每个页面重复的编写相同的代码,减少了我们的工作量,而且给维护带来了极大的便利,那么它是如何实现统一管理的呢?既然它能统一管理某些重复的操作,那么它和AOP有什么关系呢? Filter简介 ServletAPI中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过

用maven来创建scala和java项目代码环境(图文详解)(Intellij IDEA(Ultimate版本)、Intellij IDEA(Community版本)和Scala IDEA for Eclipse皆适用)(博主推荐)

为什么要写这篇博客? 首先,对于spark项目,强烈建议搭建,用Intellij IDEA(Ultimate版本),如果你还有另所爱好尝试Scala IDEA for Eclipse,有时间自己去玩玩.但最好追随大流. 对于hadoop项目,强烈建议用eclipse.   其次,出于有博友给我留言的索求需要,为了更高效率和高质量帮助大家,梳理写下这篇博客. 这篇博客 是在Scala IDEA for Eclipse里手动创建scala代码编写环境. 这篇博客 是在Scala IDEA for E

使用ssh开发rest web服务支持http etag header的教程详解

原创整理不易,转载请注明出处:使用ssh开发rest web服务支持http etag header的教程详解 代码下载地址:http://www.zuidaima.com/share/1777391667989504.htm 导言 REST方式的应用程序构架在近日所产生的巨大影响突出了Web应用程序的优雅设计的重要性.现在人们开始理解"WWW架构"内在的可测量性及弹性,并且已经开始探索使用其范例的更好的方式.在本文中,我们将讨论一个Web应用开发工具--"简陋的.卑下的&q

Java并发编程之---Lock框架详解

Java 并发开发:Lock 框架详解 摘要: 我们已经知道,synchronized 是Java的关键字,是Java的内置特性,在JVM层面实现了对临界资源的同步互斥访问,但 synchronized 粒度有些大,在处理实际问题时存在诸多局限性,比如响应中断等.Lock 提供了比 synchronized更广泛的锁操作,它能以更优雅的方式处理线程同步问题.本文以synchronized与Lock的对比为切入点,对Java中的Lock框架的枝干部分进行了详细介绍,最后给出了锁的一些相关概念. 一

JAVA通过JDBC连接Oracle数据库详解【转载】

JAVA通过JDBC连接Oracle数据库详解 (2011-03-15 00:10:03) 转载▼http://blog.sina.com.cn/s/blog_61da86dd0100q27w.html Java连接Oracle步骤: 1.注册加载驱动 驱动名:DRIVER="oracle.jdbc.driver.OracleDriver"; Class.forName("驱动类名"); 2.获得连接 数据库地址: URL="jdbc:oracle:thi

Android研究之为基于 x86 的 Android* 游戏选择合适的引擎详解

摘要 游戏开发人员知道 Android 中蕴藏着巨大的机遇. 在 Google Play 商店的前 100 款应用中,约一半是游戏应用(在利润最高的前 100 款应用中,它们所占的比例超过 90%). 如要跻身该市场,开发速度非常关键. 一些刚起步的独立开发人员更愿意从零开始来开发自己的所有代码:但是为了达到更高的质量而不用花费数年的时间进行开发,其他人可能会选择已有的游戏引擎.上章研究了英特尔 Android* 开发人员指南上的对等应用详解,在选择引擎时,你可以考虑以下几个因素: 成本 - 你

[转帖]基于VIM漏洞CVE-2019-12735的VIM宏后门病毒详解

基于VIM漏洞CVE-2019-12735的VIM宏后门病毒详解 不明觉厉 只要是人做的东西 就会有bug 就会有安全问题 就看发现bug 或者是发现安全问题 有没有收益了 会用linux的都是比较熟悉操作系统等概念的 不容易被钓鱼 反过来 很多用windows的能力会很差, 所以 windows上面显的更加脆弱. 这就好比开丰田车出事故的人 要比开众泰出事故的人要多很多一个道理. 众泰开的少 而且大家都可能会修车了.. https://www.freebuf.com/vuls/205516.h