常见的邮件协议包括 :
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 发送邮件 详解相关推荐
- Java发送邮件详解
Java发送邮件详解 本期我们学习Java如何发送邮件,Java发送邮件是以后工作较为常用的一个Java技能,想Web的邮箱验证.邮件提醒等功能,后期我也会编写一个教务的成绩提醒系统,其中,提醒的功能 ...
- Apache Thrift - java开发详解
2019独角兽企业重金招聘Python工程师标准>>> Apache Thrift - java开发详解 博客分类: java 架构 中间件 1.添加依赖 jar <depen ...
- Java泛型详解-史上讲解最详细的,没有之一
目录 1. 概述 2. 一个栗子 3. 特性 4. 泛型的使用 4.1 泛型类 4.2 泛型接口 4.3 泛型通配符 4.4 泛型方法 4.4.1 泛型方法的基本用法 4.4.2 类中的泛型方法 4. ...
- Java虚拟机详解----JVM常见问题总结
[正文] 声明:本文只是做一个总结,有关jvm的详细知识可以参考本人之前的系列文章,尤其是那篇:Java虚拟机详解04----GC算法和种类.那篇文章和本文是面试时的重点. 面试必问关键词:JVM垃圾 ...
- java 泛型详解、Java中的泛型方法、 java泛型详解
本文参考java 泛型详解.Java中的泛型方法. java泛型详解 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用. 什么是泛型?为什么要使用泛型? 泛型,即& ...
- 最详细的java泛型详解
来源:最详细的java泛型详解 对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下. 本文参考java 泛型详解.Java中的泛型方法. ja ...
- Java异常详解及如何处理
来源:Java异常详解及如何处理 简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常.异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误给用户?或者用C语言 ...
- Java基础——Java NIO详解(一)
一.基本概念 1.I/0简介 I/O即输入输出,是计算机与外界世界的一个借口.IO操作的实际主题是操作系统.在java编程中,一般使用流的方式来处理IO,所有的IO都被视作是单个字节的移动,通过str ...
- Java基础——Java NIO详解(二)
一.简介 在我的上一篇文章Java NIO详解(一)中介绍了关于标准输入输出NIO相关知识, 本篇将重点介绍基于网络编程NIO(异步IO). 二.异步IO 异步 I/O 是一种没有阻塞地读写数据的方法 ...
最新文章
- Windows下配置Chrome WebDriver
- tomcat设置https访问
- Java集合:ConcurrentHashMap(JDK 1.7 JDK 1.8)
- jQuery插件开发
- sqlserver执行更新语句失败报错42S22
- Youtube深度学习推荐系统
- [渝粤教育] 重庆工业职业技术学院 汽车安全与舒适系统维修 参考 资料
- 机器学习与Scikit Learn学习库
- Ruby on Rails 和 J2EE:两者能否共存?
- jq发送动态变量_「系统架构」Nginx调优之变量的使用(3)
- Tomcat学习总结(16)—— Tomcat优化时的参数分析
- Leetcode 刷题笔记(二十九) ——动态规划篇之子序列问题:编辑距离
- POST和GET请求区别
- 京东黑科技引爆车联网时代 你的爱车升级了吗?
- 【Webcam设计】x264对OpenCV Mat的编解码
- ssh登陆忽略known_hosts文件(ssh 登陆提示Host key verification failed.)
- 阿里服务器配置随笔记 centos 服务器 Linux 部分命令合集
- Linux进阶 | Docker部署nginx的web服务,VOLUME的使用详解,实现数据持久化!
- Definition of Dichotomy
- “磁”话有理(七)——磁集成类型之电感与电感集成
热门文章
- 提高数据库查询效率的方法
- pinyin4j 内存溢出
- 一直被模仿,从未被超越_longware_新浪博客
- win10 go环境配置
- 点击率如何计算?靠点击率怎么赚钱呢?
- 培训管理,剃头担子还是豆腐脑担子
- 工厂方法及其设计原则
- 移动生产力成手机重要竞争点,S Pen如何令Note 8脱颖而出?
- java悬浮窗锁定_怎么通过悬浮窗录音?再也不用担心文本被遮挡!
- Bessie Goes Moo