Java 实现邮件的发送,使用 JavaMail 和 Spring 实现
一、使用 JavaMail
JavaMail 是 Java 处理电子邮件相关的编程接口,但是没有被加在标准的Java开发工具包中(Java Development Kit),所以我们使用 JavaMail 需要另外下载依赖包
javax.mail.jar
包实现了 SMTP、IMAP 和 POP3 协议
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
1、发送一个简单邮件
下面是用 qq 邮箱发送一个简单的纯文本邮件的例子
public class SentSimpleMail {
private static final String MAIL_HOST = "smtp.qq.com"; // 发送邮件的主机
private static final String FROM = "827952316@qq.com"; // 发件人邮箱地址
/**
* 用qq邮箱发送一个简单邮件
*
* @param subject
* @param text
* @param toRecipients 接收邮件,逗号分隔
* @throws AddressException
* @throws MessagingException
*/
public void sentSimpleMail(String subject, String text, String toRecipients)
throws AddressException, MessagingException {
/*
* 初始化JavaMail会话
*/
Properties props = System.getProperties(); // 获得系统属性配置,用于连接邮件服务器的参数配置
props.setProperty("mail.smtp.host", MAIL_HOST); // 发送邮件的主机
props.setProperty("mail.smtp.auth", "true");
Session session = Session.getInstance(props, null);// 获得Session对象
session.setDebug(true); // 设置是否显示debug信息,true 会在控制台显示相关信息
/*
* 创建邮件消息,发送邮件
*/
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(FROM));
// To: 收件人
// message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(toRecipient));
message.setRecipients(MimeMessage.RecipientType.TO, InternetAddress.parse(toRecipients, false));
// To: 增加收件人(可选)
// message.addRecipient(MimeMessage.RecipientType.TO, new InternetAddress(toRecipient);
// Cc: 抄送(可选)
// message.setRecipient(MimeMessage.RecipientType.CC, new InternetAddress(ccRecipient));
// Bcc: 密送(可选)
// message.setRecipient(MimeMessage.RecipientType.BCC, new InternetAddress(bccRecipient));
message.setSubject(subject); // 邮件标题
message.setText(text); // 邮件内容
// 简单发送邮件的方式
Transport.send(message, FROM, "xxxxxxxxxxx"); // 授权码
}
public static void main(String[] args) throws AddressException, MessagingException {
new SentSimpleMail().sentSimpleMail("标题", "邮件内容", "827952316@qq.com");
}
}
授权
如果需要提供用户名和密码给e-mail服务器来达到用户认证的目的,需要另外添加授权信息
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.user", "${user}");
props.setProperty("mail.password", "${password}");
或者在发送的时候加上用户和授权码,如
Transport.send(message, FROM, "xxxxxxxxxxx"); // 授权码
如在使用 qq 邮箱发送邮件需要获取授权码,在邮箱的“设置-账户”中设置
2、发送基于 HTML 内容的邮件
发送邮件的内容为 HTML 时,需要把 Mimemessage 的 ContentType 设为 “text/html”
message.setDataHandler(new DataHandler( new ByteArrayDataSource("<h1>This is html message</h1>", "text/html")));
或者
message.setContent("<h1>This is html message</h1>", "text/html" );
3、带有附件的邮件
MimeMessage 继承Message,表示整封邮件
MimeBodyPart 表示邮件的一个MIME消息
MimeMultipart 表示一个由多个MIME消息组合成的组合MIME消息
public class SendMail {
public void sendMail(String subject, String text, String toRecipients)
throws AddressException, MessagingException, IOException {
String host = "smtp.qq.com"; // 发送邮件的主机
String from = "827952316@qq.com"; // 发件人邮箱地址
/*
* 初始化JavaMail会话
*/
Properties props = System.getProperties(); // 获得系统属性配置,用于连接邮件服务器的参数配置
props.setProperty("mail.smtp.host", host); // 发送邮件的主机
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.user", from);
props.setProperty("mail.password", "xxxxxxxxxxxxxxx"); //密码或者授权码
Session session = Session.getInstance(props, null);// 获得Session对象
session.setDebug(true); // 设置是否显示debug信息,true 会在控制台显示相关信息
/*
* 创建邮件消息,发送邮件
*/
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipients(MimeMessage.RecipientType.TO, InternetAddress.parse(toRecipients, false));
message.setSubject(subject); // 邮件标题
//创建多重消息
MimeMultipart mp = new MimeMultipart();
// 文本部分
MimeBodyPart textPart = new MimeBodyPart();
textPart.setText(text);
// 附件部分
MimeBodyPart filePart = new MimeBodyPart();
filePart.attachFile("D:/0.jpeg");
filePart.setFileName("0.jpeg");
mp.addBodyPart(textPart);
mp.addBodyPart(filePart);
message.setContent(mp);
Transport.send(message);
}
public static void main(String[] args) throws AddressException, MessagingException, IOException {
new SendMail().sendMail("标题", "邮件内容", "827952316@qq.com");
}
}
二、使用 Spring 发送邮件
在 spring 中,关于邮件(JavaMail)的集成 API 是在 spring-context-supprot 中的 org.springframework.mail
包中,需要 JavaMail 的类库支持。
在项目中,邮件功能可能是一个横切关注点,很可能为 AOP 的一个切面
MailSender 是发送电子邮件的核心接口。SimpleMailMessage 类封装了简单的邮件属性(例如from和to)的简单值
1、基本用法
1)MailSender 和 SimpleMailMessage 的用法
使用 MailSender 和 SimpleMailMessage 来发送邮件
@Component
public class SendMailManagerImpl implements SendMailManager {
@Autowired
private MailSender mailSender;
@Autowired
private SimpleMailMessage templateMessage;
@Override
public void sendMail(String[] to) {
// SimpleMailMessage
SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
msg.setTo(to);//接收人
msg.setText("邮件内容"); //这里的邮件内容是 文本类型
// msg.setCc(cc);// 抄送
// msg.setBcc(bcc);// 密送
// msg.setReplyTo(replyTo);// 回复
// msg.setSentDate(new Date());// 发送时间
// msg.setSubject(subject);// 主题
// msg.setFrom(from);// 发送人
try{
this.mailSender.send(msg);
}
catch (MailException ex) {
System.out.println(ex.getMessage());
}
}
}
我们在 xml 中配置 MailSender 和 模板消息
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.qq.com" />
<!-- 如果需要账号密码授权 -->
<property name="username" value="827952316@qq.com"/>
<property name="password" value="xxxxxxxxxxxxxxxx"/>
</bean>
<!-- 可以做一个模板,把邮件的通用内容放到这里 -->
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage">
<property name="from" value="827952316@qq.com" />
<property name="subject" value="统一标题" />
</bean>
2)使用 JavaMailSender 和 MimeMessagePreparator
上面的例子是利用了 spring 所封装的 SimpleMailMessage 类。不过 Spring 框架的邮件支持也附带了标准 JavaMail 实现,JavaMailSender 类可以使用 JavaMail 的 MimeMessage 类
@Component
public class SendMailManagerImpl2 implements SendMailManager {
@Autowired
private JavaMailSender mailSender;
public void sendMail(String[] to) {
MimeMessagePreparator preparator = (MimeMessage mimeMessage) -> {
Arrays.asList(to).stream().forEach(x -> {
try {
mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(x));
} catch (MessagingException e) {
System.err.println(e.getMessage());
}
});
mimeMessage.setFrom(new InternetAddress("827952316@qq.com"));
mimeMessage.setText("邮件内容");
};
try {
this.mailSender.send(preparator);
}
catch (MailException ex) {
System.err.println(ex.getMessage());
}
}
}
2、使用 MimeMessageHelper 处理 JavaMail 消息
使用 MimeMessageHelper 可以很方便的创建处理 JavaMail 的 MimeMessage 对象
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("smtp.qq.com");
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setTo("test@qq.com");
helper.setText("邮件内容");
sender.send(message);
当我们想要邮件有附件和内联资源的时候,使用 MimeMessageHelper 就很方便了
1)发送带有附件和内联资源的邮件
我们发送邮件通常会需要有附件或者是内联资源(比如,内嵌的图片),在创建这些相当复杂的邮件,SimpleMailMessage 就不好用了,使用 MimeMessageHelper 帮我们创建 MimeMessage 对象
@Component
public class SendMailManagerImpl3 implements SendMailManager {
@Autowired
private JavaMailSender mailSender;
public void sendMail(String[] to) {
MimeMessage message = mailSender.createMimeMessage();
try {
// 使用 true 表示要创建一个有多部分的邮件
MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
helper.setFrom("827952316@qq.com");
helper.setTo(to);
// 使用 true 表示邮件内容为 HTML,在这里引用内联资源 图片
helper.setText("<html><body><h1>邮件内容</h1><img src='cid:inlineImg'/></body></html>", true);
// 添加附件
FileSystemResource file = new FileSystemResource(new File("D:/0.jpeg"));
helper.addAttachment("CoolImage.jpeg", file);
// 添加内联资源(在html中引用)
FileSystemResource res = new FileSystemResource(new File("D:/0.jpeg"));
helper.addInline("inlineImg", res);
this.mailSender.send(message);
} catch (MailException | MessagingException ex) {
System.err.println(ex.getMessage());
}
}
}
使用内联资源的时候要指定 Content-ID,MimeMessage在邮件内容中添加。添加文本和资源的顺序非常重要。要先添加文本,然后再添加资源
3、使用模板创建邮件
通常我们在使用代码创建邮件是都不会是简单的纯文本邮件,在使用Java代码创建基于HTML的电子邮件内容非常繁琐且容易出错,而且更改电子邮件内容的显示结构需要编写Java代码,重新编译,重新部署
使用模板是可以解决这些问题的,使用模板库(例如FreeMarker、Velocity、Thymeleaf)来定义电子邮件内容的显示结构。从 Spring 4.3 之后,Velocity支持已被弃用。这里我们使用 FreeMaker 模板发送邮件做个例子
首先我们添加依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
1)配置 bean
FreeMarker 配置
<!-- web项目中 -->
<!-- <bean id="freeMarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/config/template/" />
<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> -->
<!-- 非web -->
<bean id="freeMarkerConfiguration" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
<property name="templateLoaderPath" value="classpath:template/ftl/" />
</bean>
2)通过模板获得邮件内容
FreeMarker 模板 user.ftl
<html>
<body>
<h3>username: ${user.username}</h3>
<p>password : ${user.password}</p>
<span>Sent using FreeMarker Template</span>
</body>
</html>
使用 FreeMarker 模板获得邮件内容
@Component
public class TemplateManagerImpl implements SendMailManager {
@Autowired
private JavaMailSender mailSender;
@Autowired
private Configuration freeMarkerConfiguration;
@Override
public void sendMail(String[] to,User user) {
MimeMessage message = mailSender.createMimeMessage();
try {
// 使用 true 表示要创建一个有多部分的邮件
MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
helper.setFrom("827952316@qq.com");
helper.setTo(to);
helper.setSubject("标题");
//获取模板
Map<String, Object> model = new HashMap<String, Object>();
model.put("user", user);
String text = geFreeMarkerTemplateContent(model);
// 使用 true 表示邮件内容为 HTML
helper.setText(text, true);
this.mailSender.send(message);
} catch (MailException | MessagingException ex) {
System.err.println(ex.getMessage());
}
}
/**
* 获得模板内容
* @param model
* @return
*/
private String geFreeMarkerTemplateContent(Map<String, Object> model) {
String content = null;
try {
content = FreeMarkerTemplateUtils.processTemplateIntoString(freeMarkerConfiguration.getTemplate("user.ftl"), model);
} catch (Exception e) {
System.err.println(e.getMessage());
}
return content;
}
}
邮件如下