常见的邮件协议包括 :
SMTP : 简单邮件传输协议,用于发送电子邮件的传输协议
POP3 : 用于接收电子邮件的标准协议
IMAP : 互联网消息访问协议,是 POP3 的替代协议
这三种协议都有对应 SSL 加密传输的协议,分别是 SMTPS、 POP3S 和 IMAPS
JavaMail 体系结构
除 JavaMail 的核心包之外, JavaMail 还需要 JAF( JavaBeans Activation Framework)来处理不是纯文本的邮件内容。这包括 MIME(多用途互联网邮件扩展)、 URL 页面和文件附件等内容
JavaMail 是由 Sun 定义的一套收发电子邮件的 API,不同的厂商可以提供自己的实现类。但它并没有包含在 JDK 中,而是作为 Java EE 的一部分。
JavaMail 的关键对象
1> Properties : 属性对象,其中封装服务器地址、 端口、 用户名、 密码等信息,具体相关信息如下 :
属性名
属性类型
说明
mail.smtp.host
String
SMTP 服务器地址,如 smtp.sina.com.cn
mail.smtp.port
int
SMTP 服务器端口号,默认为 25
mail.smtp.auth
boolean
SMTP 服务器是否需要用户认证,默认为 false
mail.smtp.user
String
SMTP 默认的登录用户名
mail.smtp.from
String
默认的邮件发送源地址
mail.smtp.socketFactory.class
String
socket 工厂类类名,通过设置该属性可以覆盖提供者默认的实现。必须实现 javax.net.SocketFactory 接口
mail.smtp.socketFactory.port
int
指定 socket 工厂类所用的端口号,如果没有设定,则使用默认的端口
mail.smtp.socketFactory.fallback
boolean
设置为 true 时,当使用指定的 socket 类创建 socket 失败后,将使用 java.net.Socket 创建 socket。默认为 true
mail.smtp.timeout
int
I/O 连接超时时间,单位为毫秒,默认为永不超时
Session : 会话对象,是一堆配置信息的集合
Transport 和 Store : 传输和存储
使用 JavaMail 发送邮件实例
1> 引入 JavaMail 相关包
< dependency >
    < groupId > javax.mail </ groupId >
    < artifactId > mail </ artifactId >
    < version > 1.4 </ version >
</ dependency >
2> 
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.util.Properties;
public class MailUtils  {
    private String host = "" ; // smtp服务器
    private String from = "" ; // 发件人地址
    private String to = "" ; // 收件人地址
    private String affix = "" ; // 附件地址
    private String affixName = "" ; // 附件名称
    private String user = "" ; // 用户名
    private String pwd = "" ; // 密码
    private String subject = "" ; // 邮件标题
    public void setAddress(String from, String to, String subject)  {
        this . from = from;
        this . to = to;
        this . subject = subject;
    }
    public void setAffix(String affix, String affixName)  {
        this . affix = affix;
        this . affixName = affixName;
    }
    public void send(String host, String user, String pwd, String content)  {
        this . host = host;
        this . user = user;
        this . pwd = pwd;
        Properties props = new Properties();
        // 设置发送邮件的邮件服务器的属性(这里使用网易的smtp服务器)
        props.put( "mail.smtp.host" , host);
        // 需要经过授权,也就是有户名和密码的校验,这样才能通过验证(一定要有这一条)
        props.put( "mail.smtp.auth" , "true" );
        // 用刚刚设置好的props对象构建一个session
        Session session = Session. getDefaultInstance (props);
        // 有了这句便可以在发送邮件的过程中在console处显示过程信息,供调试使
        // 用(你可以在控制台(console)上看到发送邮件的过程)
        session.setDebug( true );
        // 用session为参数定义消息对象
        MimeMessage message = new MimeMessage(session);
        try  {
            // 加载发件人地址
            message.setFrom( new InternetAddress( from ));
            // 加载收件人地址
            message.addRecipient(Message.RecipientType. TO , new InternetAddress( to ));
            // 加载标题
            message.setSubject( subject );
            // 向multipart对象中添加邮件的各个部分内容,包括文本内容和附件
            Multipart multipart = new MimeMultipart();
            // 设置邮件的文本内容
            BodyPart contentPart = new MimeBodyPart();
            contentPart.setText(content);
            multipart.addBodyPart(contentPart);
            // 添加附件
            BodyPart messageBodyPart = new MimeBodyPart();
            DataSource source = new FileDataSource( affix );
            // 添加附件的内容
            messageBodyPart.setDataHandler( new DataHandler(source));
            // 添加附件的标题
            // 这里很重要,通过下面的Base64编码的转换可以保证你的中文附件标题名在发送时不会变成乱码
            sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
            messageBodyPart.setFileName( "=?GBK?B?" + enc.encode( affixName .getBytes()) + "?=" );
            multipart.addBodyPart(messageBodyPart);
            // 将multipart对象放到message中
            message.setContent(multipart);
            // 保存邮件
            message.saveChanges();
            // 发送邮件
            Transport transport = session.getTransport( "smtp" );
            // 连接服务器的邮箱
            transport.connect(host, user, pwd);
            // 把邮件发送出去
            transport.sendMessage(message, message.getAllRecipients());
            transport.close();
        }
        catch (Exception e)  {
            e.printStackTrace();
        }
    }
    public static void main(String[] args)  {
        MailUtils cn = new MailUtils();
        // 设置发件人地址、收件人地址和邮件标题
        cn.setAddress( " chenshun131@163.com " , " 1539831174@qq.com " , "一个带附件的JavaMail邮件" );
        // 设置要发送附件的位置和标题
        cn.setAffix( "/Users/chenshun131/Desktop/附录A.pdf" , "123.pdf" );
        /**
         * 设置smtp服务器以及邮箱的帐号和密码
         * 用QQ 邮箱作为发生者不好使 (原因不明)
         * 163 邮箱可以,但是必须开启  POP3/SMTP服务 和 IMAP/SMTP服务
         * 因为程序属于第三方登录,所以登录密码必须使用163的授权码
         */
        // 注意: [授权码和你平时登录的密码是不一样的]
        cn.send( " smtp.163.com " , " chenshun131@163.com " , "" , "邮件的具体内容在此" );
    }
}
直接使用 JavaMail 编写邮件收发程序并不是一件轻松的事情,这归咎于 JavaMail 零散而复杂的 API 以及各种强制需要处理的检查型异常。Spring 对使用 JavaMail 发送邮件进行了很大程度的简化,它为 80%的需求提供了简单的处理方法,剩下的需求则可以通过直接调用 JavaMailAPI 完成
Spring 在 org.springframework.mail 包里通过 MailMessage 和 MailSender 这两个高层抽象接口描述了,两个最重要的内容 : 邮件消息和邮件发送者
MailMessage : 抽象的邮件消息,该接口描述了邮件消息的通用模型,允许开发者通过多个简洁的属性设置方法填充邮件消息的各项内容
MailMessage 有两个实现类: SimpleMailMessage 和 MimeMailMessage,前者都是完全符合 Bean 风格的实现类,后者通过内置 JavaMail 的 MimeMessage 提供实现。在发送简单文本型邮件时, SimpleMailMessage 就可以满足要求,如果 发送复杂的邮件,则可以利用 MimeMailMessage 或直接使用MimeMessage
MailSender : 抽象的邮件发送者,邮件发送者负责将邮件发送到指定的地址上,该接口只用于发送简单的邮件。如果需要发送复杂的邮件,则需要使用 JavaMailSender 子接口
Spring 的邮件异常体系
Spring 在 org.springframework.mail.javamail 包下提供了对 JavaMail 邮件系统的支持。首先,通过 JavaMailSenderImpl 可以方便地创建 JavaMail 环境;其次,通过 MimeMessageHelper 构造出 MimeMessage 对象
向邮件中添加附件或内嵌文件时,文件对应的 MIME 类型是一个很重要的信息,因为 Outlook、Foxmail 等邮件客户端软件必须根据 MIME 类型决定如何处理邮件中的内嵌文件。文件扩展名和 MIME 类型的对应关联在 activation.jar/META-INF 目录下的
mimetypes.default 文件中定义 :
MIME 类型的规范名
文件扩展名
text/html
html htm HTML HTM
text/plain
txt text TXT TEXT
image/gif
gif GIF
image/ief
ief
image/jpeg
jpeg jpg jpe JPG
image/tiff
tiff tif
image/x-xwindowdump
xwd
application/postscript
ai eps ps
application/rtf
rtf
application/x-tex
tex
application/x-texinfo
texinfo texi
application/x-troff
t tr roff
audio/basic
au
audio/midi
midi mid
audio/x-aifc
aifc
audio/x-aiff
aif aiff
audio/x-mpeg
mpeg mpg
audio/x-wav
wav
video/mpeg
mpeg mpg mpe
video/quicktime
qt mov
video/x-msvideo
avi
注 : 在 http://www.w3school.com.cn/media/media_mimeref.asp  可以找到所有 MIME 类型的信息
发送邮件频繁发送可能会被邮箱服务器识别为垃圾邮件,如 163邮箱可能会出现  554 DT:SPM 发送的邮件内容包含了未被许可的信息,或被系统识别为垃圾邮件。请检查是否有用户发送病毒或者垃圾邮件;
通过 Spring 的 JavaMail 发送各种形式的邮件
例如如下代码
@Autowired
private JavaMailSender sender ;
public void sendSimpleMail() { // 发送纯文本邮件
    SimpleMailMessage msg = new SimpleMailMessage();
    msg.setFrom( " chenshun131@163.com " );
    msg.setTo( " chenshun131@gmail.com " );
    msg.setReplyTo( " 1539831174@qq.com " );
    msg.setCc( " 1539831174@qq.com " );
    msg.setSubject( "注册成功" );
    msg.setText( "恭喜,您在宝宝淘论坛已经注册成功!您的用户ID为:1234567890" );
    sender .send(msg);
}
public void sendHtmlMail() throws MessagingException { // 发送 HTML 类型的邮件
    MimeMessage msg = sender .createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(msg, false , "utf-8" ); // 推荐使用 utf-8 编码
    helper.setFrom( " chenshun131@163.com " );
    helper.setTo( new String[]{ " chenshun131@gmail.com " , " 1539831174@qq.com " });
    helper.setSubject( "注册成功" );
    String htmlText = "<html><head>"
            + "<meta http-equiv= \" content-type \" content= \" text/html; charset=utf-8 \" >"
            + "</head><body>" + "恭喜,您在宝宝淘论坛已经注册成功!您的用户ID为:"
            + "<font size='20' size='30'>1234567890</font> </body></html>" ;
    helper.setText(htmlText, true );
    sender .send(msg);
}
/**
* 对于一个 Web 应用程序来说,一般情况下,我们不推荐使用内嵌文件的邮件,用
* 户大可将这些资源文件放在一台 Web 资源服务器上,然后简单地通过 URL 来引用这
* 些文件。这带来了明显的好处:邮件体积缩小很多,并且提高了邮件的收发效率,同
* 时邮件的展现效果并不会受到影响
*/
public void sendInlineMail() throws MessagingException { // 发送带内嵌文件的邮件
    MimeMessage msg = sender .createMimeMessage();
    // 内嵌文件邮件是 multipart类型,第二个入参需要设置为 true
    MimeMessageHelper helper = new MimeMessageHelper(msg, true , "utf-8" );
    helper.setFrom( " chenshun131@163.com " );
    helper.setTo( new String[]{ " chenshun131@gmail.com " , " 1539831174@qq.com " });
    helper.setSubject( "宝宝淘论坛注册成功" );
    String htmlText = "<html><head>"
            + "<meta http-equiv= \" content-type \" content= \" text/html; charset=utf-8 \" >"
            + "</head><body>" + "欢迎访问宝宝淘论坛!</hr>(我想显示一些其他信息)"
            + "<div><img src= \" cid:img01 \" ></img></div>" + "</body></html>" ;
    helper.setText(htmlText, true );
    ClassPathResource img = new ClassPathResource( "bbt.gif" );
    helper.addInline( "img01" , img);
    sender .send(msg);
}
public void sendAttachmentMail() throws Exception { // 发送带附件的邮件
    MimeMessage msg = sender .createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(msg, true , "utf-8" );
    helper.setFrom( " chenshun131@163.com " );
    helper.setTo( new String[]{ " chenshun131@gmail.com " , " 1539831174@qq.com " });
    helper.setSubject( "宝宝淘论坛注册成功" );
    helper.setText( "欢迎访问宝宝淘论坛!" );
    ClassPathResource file1 = new ClassPathResource( "bbt.zip" );
    helper.addAttachment( "file01.zip" , file1.getFile());
    ClassPathResource file2 = new ClassPathResource( "file.doc" );
    helper.addAttachment( "file02.doc" , file2.getFile());
    sender .send(msg);
}
// 双版本邮件,在 Foxmail 中,用户在默认情况下看到纯文件版本的邮件,可以通过点击工具栏的“ HTML”按钮查看 HTML 版本的邮件
public void sendAlternativeMail() throws Exception { // 发送纯文本和 HTML 双版本的邮件
    MimeMessagePreparator mmp = new MimeMessagePreparator() {
        public void prepare(MimeMessage msg) throws Exception {
            MimeMessageHelper helper = new MimeMessageHelper(msg, true , "utf-8" );
            helper.setFrom( " chenshun131@163.com " );
            helper.setTo( new String[]{ " chenshun131@gmail.com " , " 1539831174@qq.com " });
            helper.setSubject( "注册成功" );
            MimeMultipart mmPart = new MimeMultipart( "alternative" ); // 创建双版本邮件内容
            msg.setContent(mmPart);
            // 创建纯文本版本的邮件体
            BodyPart plainTextPart = new MimeBodyPart();
            plainTextPart.setText( "欢迎访问宝宝淘论坛!(创建纯文本版本的邮件体)" );
            mmPart.addBodyPart(plainTextPart);
            // 创建 HTML 版本的邮件体
            BodyPart htmlPart = new MimeBodyPart();
            String htmlText = "<html><head>"
                    + "<meta http-equiv= \" content-type \" content= \" text/html; charset=utf-8 \" >"
                    + "</head><body><font size='20' size='30'>"
                    + "欢迎访问宝宝淘论坛! (创建 HTML 版本的邮件体)</font>" + "</body></html>" ;
            htmlPart.setContent(htmlText, "text/html;charset=utf-8" );
            mmPart.addBodyPart(htmlPart);
        }
    };
    sender .send(mmp);
}
需要在 Spring 工程中引入两个库
< dependency >
    < groupId > javax.mail </ groupId >
    < artifactId > mail </ artifactId >
    < version > 1.4 </ version >
</ dependency >
< dependency >
    < groupId > org.freemarker </ groupId >
    < artifactId > freemarker </ artifactId >
    < version > 2.3.23 </ version >
</ dependency >
在 spring-mvc.xml 中配置发送者邮件相关信息
< bean id ="sender"
      class ="org.springframework.mail.javamail.JavaMailSenderImpl"
      p :host =" smtp.163.com "
      p :username ="chenshun131"
      p :password ="xxxx" >
    < property name ="javaMailProperties" >
        < props >
            < prop key ="mail.smtp.auth" > true </ prop >
        </ props >
    </ property >
</ bean >
在实际应用中发送邮件
邮件发送程序直接在代码中构建邮件内容,对于一些简单的邮件来说,这种方式是可行的。但如果邮件体的内容很复杂,这种方式的弊端将马上暴露出来 —— 直接使用 Servlet 构造复杂内容网页非常复杂
对于 HTML 格式的邮件来说,除少部分内容外,大部分的 HTML 代码都是固定的,因此,在实际应用中,常采用的办法是制作好邮件模板,在发送邮件时,通过模板解析构建最终邮件内容
由于发送邮件相对来说是比较重量级的操作,它受限于邮件服务器和网络的性能,可能需要好几秒的时间。如果直接在业务流程的线程中采用同步的方式发送邮件,业务流程的响应速度将会受到很大的影响。为了降低这种影响,在实际的应用系统中,一般需要采用异步邮件发送方式,使用单独的线程发送邮件,甚至使用 JMS 消息提交邮件发送任务,由单独的邮件发送服务器负责实际邮件发送的任务
使用邮件模板
在开源领域, Velocity 和 FreeMarker 是广泛使用的两个模板框架,由于 FreeMarker 的后发优势其更受青睐度。模版的原理其实很简单,就是用动态的数据替换模板中的特殊标签,生成最终的内容
Spring 为 Freemarker 提供了一个 FreeMarkerConfigurer,通过这个类可以方便地创建Freemarker 的基础设施,然后就可以在此基础上获取 Freemarker 的基础组件实例
例如如下代码 :
@Autowired
private JavaMailSender sender ;
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer ;
@Test
public void sendTemplateMail() throws MessagingException {
    MimeMessage msg = sender .createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(msg, false , "utf-8" );
    helper.setFrom( " chenshun131@163.com " );
    helper.setTo( new String[]{ " chenshun131@gmail.com " , " 1539831174@qq.com " });
    helper.setSubject( "宝宝淘论坛注册成功:基于模板" );
    String htmlText = getMailText( "1234567890" ); // 使用模板产生HTML 邮件体内容
    helper.setText(htmlText, true );
    sender .send(msg);
}
private String getMailText(String userId) { // 通过模板构造邮件内容
    String htmlText = null ;
    try {
        Template tpl = freeMarkerConfigurer .getConfiguration().getTemplate( "registerUser.ftl" ); // 通过指定模板名获取 Freemarker 模板实例
        Map map = new HashMap(); // 通过 Map 传递动态数据
        map.put( "userId" , userId); // 注意动态数据的名字必须和模板标签中指定属性相匹配
        htmlText = FreeMarkerTemplateUtils. processTemplateIntoString (tpl, map); // 解析模板并替换动态数据,产生最终的内容
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    return htmlText;
}
在 spring-mvc.xml 中配置 freemarker发送者邮件相关信息
< bean id ="freeMarkerConfigurer"
      class ="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"
      p :templateLoaderPath ="classpath:mailTemplate/" >
    < property name ="freemarkerSettings" >
        < props >
            < prop key ="template_update_delay" > 1800 </ prop >
            < prop key ="default_encoding" > UTF-8 </ prop >
            < prop key ="locale" > zh_CN </ prop >
        </ props >
    </ property >
</ bean >
registerUser.ftl 中的信息
< html >
    < head >
       < meta http-equiv= "content-type" content= "text/html; charset=utf-8" >
    </ head >
   < body >
        恭喜,您在宝宝淘论坛已经注册成功!您的用户ID为: < font size= '20' size= '30' > ${ userId } </ font >
   </ body >
</ html >
异步发送邮件
例如如下代码 :
@Autowired
private TaskExecutor taskExecutor ; // 拥有异步执行能力的任务执行器
@Test
public void sendAsyncMail() {
    taskExecutor .execute( new Runnable() {
        public void run() {
            try {
                sendTemplateMail(); // 异步调用 sendTemplateMail()方法发送邮件
                System. out .println( "邮件发送成功!" );
            } catch (Exception e) {
                System. out .println( "邮件发送失败!,异常信息:" + e.getMessage());
            }
        }
    });
}
在 spring-mvc.xml 中配置任务执行器信息
< bean id ="taskExecutor"
      class ="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
      p :corePoolSize ="10"
      p :maxPoolSize ="30" />

java 发送邮件 详解相关推荐

  1. Java发送邮件详解

    Java发送邮件详解 本期我们学习Java如何发送邮件,Java发送邮件是以后工作较为常用的一个Java技能,想Web的邮箱验证.邮件提醒等功能,后期我也会编写一个教务的成绩提醒系统,其中,提醒的功能 ...

  2. Apache Thrift - java开发详解

    2019独角兽企业重金招聘Python工程师标准>>> Apache Thrift - java开发详解 博客分类: java 架构 中间件 1.添加依赖 jar <depen ...

  3. Java泛型详解-史上讲解最详细的,没有之一

    目录 1. 概述 2. 一个栗子 3. 特性 4. 泛型的使用 4.1 泛型类 4.2 泛型接口 4.3 泛型通配符 4.4 泛型方法 4.4.1 泛型方法的基本用法 4.4.2 类中的泛型方法 4. ...

  4. Java虚拟机详解----JVM常见问题总结

    [正文] 声明:本文只是做一个总结,有关jvm的详细知识可以参考本人之前的系列文章,尤其是那篇:Java虚拟机详解04----GC算法和种类.那篇文章和本文是面试时的重点. 面试必问关键词:JVM垃圾 ...

  5. java 泛型详解、Java中的泛型方法、 java泛型详解

    本文参考java 泛型详解.Java中的泛型方法. java泛型详解 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用. 什么是泛型?为什么要使用泛型? 泛型,即& ...

  6. 最详细的java泛型详解

    来源:最详细的java泛型详解 对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下. 本文参考java 泛型详解.Java中的泛型方法. ja ...

  7. Java异常详解及如何处理

    来源:Java异常详解及如何处理 简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常.异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误给用户?或者用C语言 ...

  8. Java基础——Java NIO详解(一)

    一.基本概念 1.I/0简介 I/O即输入输出,是计算机与外界世界的一个借口.IO操作的实际主题是操作系统.在java编程中,一般使用流的方式来处理IO,所有的IO都被视作是单个字节的移动,通过str ...

  9. Java基础——Java NIO详解(二)

    一.简介 在我的上一篇文章Java NIO详解(一)中介绍了关于标准输入输出NIO相关知识, 本篇将重点介绍基于网络编程NIO(异步IO). 二.异步IO 异步 I/O 是一种没有阻塞地读写数据的方法 ...

最新文章

  1. Windows下配置Chrome WebDriver
  2. tomcat设置https访问
  3. Java集合:ConcurrentHashMap(JDK 1.7 JDK 1.8)
  4. jQuery插件开发
  5. sqlserver执行更新语句失败报错42S22
  6. Youtube深度学习推荐系统
  7. [渝粤教育] 重庆工业职业技术学院 汽车安全与舒适系统维修 参考 资料
  8. 机器学习与Scikit Learn学习库
  9. Ruby on Rails 和 J2EE:两者能否共存?
  10. jq发送动态变量_「系统架构」Nginx调优之变量的使用(3)
  11. Tomcat学习总结(16)—— Tomcat优化时的参数分析
  12. Leetcode 刷题笔记(二十九) ——动态规划篇之子序列问题:编辑距离
  13. POST和GET请求区别
  14. 京东黑科技引爆车联网时代 你的爱车升级了吗?
  15. 【Webcam设计】x264对OpenCV Mat的编解码
  16. ssh登陆忽略known_hosts文件(ssh 登陆提示Host key verification failed.)
  17. 阿里服务器配置随笔记 centos 服务器 Linux 部分命令合集
  18. Linux进阶 | Docker部署nginx的web服务,VOLUME的使用详解,实现数据持久化!
  19. Definition of Dichotomy
  20. “磁”话有理(七)——磁集成类型之电感与电感集成

热门文章

  1. 提高数据库查询效率的方法
  2. pinyin4j 内存溢出
  3. 一直被模仿,从未被超越_longware_新浪博客
  4. win10 go环境配置
  5. 点击率如何计算?靠点击率怎么赚钱呢?
  6. 培训管理,剃头担子还是豆腐脑担子
  7. 工厂方法及其设计原则
  8. 移动生产力成手机重要竞争点,S Pen如何令Note 8脱颖而出?
  9. java悬浮窗锁定_怎么通过悬浮窗录音?再也不用担心文本被遮挡!
  10. Bessie Goes Moo