java 发送邮件 详解
2017-06-30 11:02
85 查看
常见的邮件协议包括 :
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 : 属性对象,其中封装服务器地址、 端口、 用户名、 密码等信息,具体相关信息如下 :
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 文件中定义 :
注 : 在 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"/>
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 连接超时时间,单位为毫秒,默认为永不超时 |
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 |
发送邮件频繁发送可能会被邮箱服务器识别为垃圾邮件,如 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"/>
相关文章推荐
- JavaWeb中使用JavaMail实现发送邮件功能实例详解
- Java --- 邮件发送详解
- 怎么用java发送带附件的邮件代码详解
- 代码详解java发送邮件
- Java邮件发送详解(可发送附件)
- java发送邮件方法
- Java使用javax.mail.jar发送邮件并允许发送附件
- Foxmail突然无法接收邮件(可发送)-详解
- java发送邮件常见问题(附源代码)
- JavaMail(JAVA邮件服务) API详解 (3)
- java邮件发送(转)
- 【干货】使用Java发送各种格式的邮件
- java发送qq邮件进行验证
- java开发的邮件发送程序
- Java发送邮件找回密码功能的实现
- 关于发送邮件提醒的错误:java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream
- Java发送带html标签内容的邮件
- Java发送邮件服务
- Java邮件发送:基于JavaMail
- java 发送邮件功能