springboot仍然在狂速发展,才五个多月没有关注,现在看官网已经到1.5.3.RELEASE版本了。准备慢慢在写写springboot相关的文章,本篇文章使用springboot最新版本1.5.3进行开发。
发送邮件应该是网站的必备功能之一,什么注册验证,忘记密码或者是给用户发送营销信息。最早期的时候我们会使用JavaMail相关api来写发送邮件的相关代码,后来spring推出了JavaMailSender更加简化了邮件发送的过程,在之后springboot对此进行了封装就有了现在的spring-boot-starter-mail,本章文章的介绍主要来自于此包。
简单使用
1、pom包配置
pom包里面添加spring-boot-starter-mail包引用
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
2、在application.properties中添加邮箱配置
spring.mail.host=smtp.qiye.163.com //邮箱服务器地址
spring.mail.username=xxx@oo.com //用户名
spring.mail.password=xxyyooo //密码
spring.mail.default-encoding=UTF-8
mail.fromMail.addr=xxx@oo.com //以谁来发送邮件
3、编写mailService,这里只提出实现类。
@Component
public class MailServiceImpl implements MailService{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private JavaMailSender mailSender;
@Value("${mail.fromMail.addr}")
private String from;
@Override
public void sendSimpleMail(String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(to);
message.setSubject(subject);
message.setText(content);
try {
mailSender.send(message);
logger.info("简单邮件已经发送。");
} catch (Exception e) {
logger.error("发送简单邮件时发生异常!", e);
}
}
}
4、编写test类进行测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class MailServiceTest {
@Autowired
private MailService MailService;
@Test
public void testSimpleMail() throws Exception {
MailService.sendSimpleMail("ityouknow@126.com","test simple mail"," hello this is simple mail");
}
}
至此一个简单的文本发送就完成了。
加点料
但是在正常使用的过程中,我们通常在邮件中加入图片或者附件来丰富邮件的内容,下面讲介绍如何使用springboot来发送丰富的邮件。
发送html格式邮件
其它都不变在MailService添加sendHtmlMail方法.
public void sendHtmlMail(String to, String subject, String content) {
MimeMessage message = mailSender.createMimeMessage();
try {
//true表示需要创建一个multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
mailSender.send(message);
logger.info("html邮件发送成功");
} catch (MessagingException e) {
logger.error("发送html邮件时发生异常!", e);
}
}
在测试类中构建html内容,测试发送
@Test
public void testHtmlMail() throws Exception {
String content="<html>\n" +
"<body>\n" +
" <h3>hello world ! 这是一封Html邮件!</h3>\n" +
"</body>\n" +
"</html>";
MailService.sendHtmlMail("ityouknow@126.com","test simple mail",content);
}
发送带附件的邮件
在MailService添加sendAttachmentsMail方法.
public void sendAttachmentsMail(String to, String subject, String content, String filePath){
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName, file);
mailSender.send(message);
logger.info("带附件的邮件已经发送。");
} catch (MessagingException e) {
logger.error("发送带附件的邮件时发生异常!", e);
}
}
添加多个附件可以使用多条
helper.addAttachment(fileName, file)
在测试类中添加测试方法
@Test
public void sendAttachmentsMail() {
String filePath="e:\\tmp\\application.log";
mailService.sendAttachmentsMail("ityouknow@126.com", "主题:带附件的邮件", "有附件,请查收!", filePath);
}
发送带静态资源的邮件
邮件中的静态资源一般就是指图片,在MailService添加sendAttachmentsMail方法.
public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId){
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource res = new FileSystemResource(new File(rscPath));
helper.addInline(rscId, res);
mailSender.send(message);
logger.info("嵌入静态资源的邮件已经发送。");
} catch (MessagingException e) {
logger.error("发送嵌入静态资源的邮件时发生异常!", e);
}
}
在测试类中添加测试方法
@Test
public void sendInlineResourceMail() {
String rscId = "neo006";
String content="<html><body>这是有图片的邮件:<img src=\'cid:" + rscId + "\' ></body></html>";
String imgPath = "C:\\Users\\summer\\Pictures\\favicon.png";
mailService.sendInlineResourceMail("ityouknow@126.com", "主题:这是有图片的邮件", content, imgPath, rscId);
}
添加多个图片可以使用多条
<img src='cid:" + rscId + "' >
和helper.addInline(rscId, res)
来实现
到此所有的邮件发送服务已经完成了。
邮件系统
上面发送邮件的基础服务就这些了,但是如果我们要做成一个邮件系统的话还需要考虑以下几个问题:
邮件模板
我们会经常收到这样的邮件:
尊敬的neo用户:
恭喜您注册成为xxx网的用户,,同时感谢您对xxx的关注与支持并欢迎您使用xx的产品与服务。
...
其中只有neo这个用户名在变化,其它邮件内容均不变,如果每次发送邮件都需要手动拼接的话会不够优雅,并且每次模板的修改都需要改动代码的话也很不方便,因此对于这类邮件需求,都建议做成邮件模板来处理。模板的本质很简单,就是在模板中替换变化的参数,转换为html字符串即可,这里以thymeleaf
为例来演示。
1、pom中导入thymeleaf的包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2、在resorces/templates下创建emailTemplate.html
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
您好,这是验证邮件,请点击下面的链接完成验证,<br/>
<a href="#" th:href="@{ http://www.ityouknow.com/neo/{id}(id=${id}) }">激活账号</a>
</body>
</html>
3、解析模板并发送
@Test
public void sendTemplateMail() {
//创建邮件正文
Context context = new Context();
context.setVariable("id", "006");
String emailContent = templateEngine.process("emailTemplate", context);
mailService.sendHtmlMail("ityouknow@126.com","主题:这是模板邮件",emailContent);
}
发送失败
因为各种原因,总会有邮件发送失败的情况,比如:邮件发送过于频繁、网络异常等。在出现这种情况的时候,我们一般会考虑重新重试发送邮件,会分为以下几个步骤来实现:
- 1、接收到发送邮件请求,首先记录请求并且入库。
- 2、调用邮件发送接口发送邮件,并且将发送结果记录入库。
- 3、启动定时系统扫描时间段内,未发送成功并且重试次数小于3次的邮件,进行再次发送
异步发送
很多时候邮件发送并不是我们主业务必须关注的结果,比如通知类、提醒类的业务可以允许延时或者失败。这个时候可以采用异步的方式来发送邮件,加快主交易执行速度,在实际项目中可以采用MQ发送邮件相关参数,监听到消息队列之后启动发送邮件。
可以参考前期文章:springboot(八):RabbitMQ详解 来实现。
参考: spring boot 发送邮件
集成spring-boot-starter-mail发送邮件
项目GitHub地址 :
https://github.com/FrameReserve/TrainingBoot
Spring Boot(十二)集成spring-boot-starter-mail发送邮件,标记地址:
https://github.com/FrameReserve/TrainingBoot/releases/tag/0.0.12
pom.xml
增加:
spring-boot-starter-mail
spring-boot-starter-velocity -- 模板
- <!-- Email -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-mail</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-velocity</artifactId>
- </dependency>
Spring Boot配置文件:
QQ邮箱权限需要在QQ邮箱里设置,163则不用,问题比较少。
src/main/resources/application.yml
- mail:
- host: smtp.163.com
- username: 286352250@163.com
- password: 用户密码
- properties:
- mail:
- smtp:
- auth: true
- timeout: 25000
Email配置类:
后期经常使用发件人邮箱,在这统一定义。
src/main/java/com/training/core/email/EmailConfig.java
- package com.training.core.email;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.stereotype.Component;
- @Component
- public class EmailConfig {
- /**
- * 发件邮箱
- */
- @Value("${spring.mail.username}")
- private String emailFrom;
- public String getEmailFrom() {
- return emailFrom;
- }
- public void setEmailFrom(String emailFrom) {
- this.emailFrom = emailFrom;
- }
- }
定义Email Service,三种邮件风格:
1. 发送简单邮件。
2. 发送带附件简单邮件
3. 发送模板邮件。
src/main/java/com/training/core/email/EmailService.java
- package com.training.core.email;
- import java.io.File;
- import java.util.List;
- import java.util.Map;
- import com.training.core.dto.Pair;
- public interface EmailService {
- /**
- * 发送简单邮件
- * @param sendTo 收件人地址
- * @param titel 邮件标题
- * @param content 邮件内容
- */
- public void sendSimpleMail(String sendTo, String titel, String content);
- /**
- * 发送简单邮件
- * @param sendTo 收件人地址
- * @param titel 邮件标题
- * @param content 邮件内容
- * @param attachments<文件名,附件> 附件列表
- */
- public void sendAttachmentsMail(String sendTo, String titel, String content, List<Pair<String, File>> attachments);
- /**
- * 发送模板邮件
- * @param sendTo 收件人地址
- * @param titel 邮件标题
- * @param content<key, 内容> 邮件内容
- * @param attachments<文件名,附件> 附件列表
- */
- public void sendTemplateMail(String sendTo, String titel, Map<String, Object> content, List<Pair<String, File>> attachments);
- }
Email Service实现类:
src/main/java/com/training/core/email/EmailServiceImpl.java
- package com.training.core.email;
- import java.io.File;
- import java.util.List;
- import java.util.Map;
- import javax.mail.internet.MimeMessage;
- import org.apache.commons.collections.map.HashedMap;
- import org.apache.velocity.app.VelocityEngine;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.core.io.FileSystemResource;
- import org.springframework.mail.SimpleMailMessage;
- import org.springframework.mail.javamail.JavaMailSender;
- import org.springframework.mail.javamail.MimeMessageHelper;
- import org.springframework.stereotype.Service;
- import org.springframework.ui.velocity.VelocityEngineUtils;
- import com.training.core.dto.Pair;
- import com.training.core.exception.RuntimeServiceException;
- @Service
- public class EmailServiceImpl implements EmailService {
- @Autowired
- private EmailConfig emailConfig;
- @Autowired
- private JavaMailSender mailSender;
- @Autowired
- private VelocityEngine velocityEngine;
- public void sendSimpleMail(String sendTo, String titel, String content) {
- SimpleMailMessage message = new SimpleMailMessage();
- message.setFrom(emailConfig.getEmailFrom());
- message.setTo(sendTo);
- message.setSubject(titel);
- message.setText(content);
- mailSender.send(message);
- }
- public void sendAttachmentsMail(String sendTo, String titel, String content, List<Pair<String, File>> attachments) {
- MimeMessage mimeMessage = mailSender.createMimeMessage();
- try {
- MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
- helper.setFrom(emailConfig.getEmailFrom());
- helper.setTo(sendTo);
- helper.setSubject(titel);
- helper.setText(content);
- for (Pair<String, File> pair : attachments) {
- helper.addAttachment(pair.getLeft(), new FileSystemResource(pair.getRight()));
- }
- } catch (Exception e) {
- throw new RuntimeServiceException(e);
- }
- mailSender.send(mimeMessage);
- }
- public void sendInlineMail() {
- MimeMessage mimeMessage = mailSender.createMimeMessage();
- try {
- MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
- helper.setFrom(emailConfig.getEmailFrom());
- helper.setTo("286352250@163.com");
- helper.setSubject("主题:嵌入静态资源");
- helper.setText("<html><body><img src=\"cid:weixin\" ></body></html>", true);
- FileSystemResource file = new FileSystemResource(new File("weixin.jpg"));
- helper.addInline("weixin", file);
- } catch (Exception e) {
- throw new RuntimeServiceException(e);
- }
- mailSender.send(mimeMessage);
- }
- public void sendTemplateMail(String sendTo, String titel, Map<String, Object> content, List<Pair<String, File>> attachments) {
- MimeMessage mimeMessage = mailSender.createMimeMessage();
- try {
- MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
- helper.setFrom(emailConfig.getEmailFrom());
- helper.setTo(sendTo);
- helper.setSubject(titel);
- String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "template.vm", "UTF-8", content);
- helper.setText(text, true);
- for (Pair<String, File> pair : attachments) {
- helper.addAttachment(pair.getLeft(), new FileSystemResource(pair.getRight()));
- }
- } catch (Exception e) {
- throw new RuntimeServiceException(e);
- }
- mailSender.send(mimeMessage);
- }
- }
测试邮件发送:
src/main/java/com/training/email/controller/DemoEmailController.java
- package com.training.email.controller;
- import io.swagger.annotations.ApiOperation;
- import javax.annotation.Resource;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.ResponseBody;
- import org.springframework.web.bind.annotation.RestController;
- import com.training.core.controller.BaseController;
- import com.training.core.dto.ResultDataDto;
- import com.training.core.email.EmailService;
- @RestController
- @RequestMapping(value="/email")
- public class DemoEmailController extends BaseController {
- @Resource
- private EmailService emailService;
- /**
- * 测试邮件发送
- */
- @ApiOperation(value="测试邮件发送", notes="getEntityById")
- @RequestMapping(value = "/getTestDemoEmail", method = RequestMethod.GET)
- public @ResponseBody ResultDataDto getEntityById() throws Exception {
- String sendTo = "1265400024@qq.com";
- String titel = "测试邮件标题";
- String content = "测试邮件内容";
- emailService.sendSimpleMail(sendTo, titel, content);
- return ResultDataDto.addSuccess();
- }
- }
关于使用Java Mail 发邮件,连接超时问题
异常信息
send mail err:Mail server connection failed; nested exception is com.sun.mail.util.MailConnectException: Couldn’t connect to host, port: smtp.qq.com, 25; timeout -1
在本地windows 是可以发送成功的
怀疑是端口问题,好吧,我用的是 25 端口,开了之后还是连接超时。
那么就很有可能是你的服务器的运营商将25端口封禁了!
换其他端口
我直接用springboot 的模板发邮件
发邮件具体代码看这里:http://www.lrshuai.top/atc/show/41
默认的配置如下:
spring.mail.host=smtp.qq.com
spring.mail.username=1006059906@qq.com
spring.mail.password=这个是你的授权码
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.default-encoding=UTF-8
修改端口为465
spring.mail.host=smtp.qq.com
spring.mail.username=1006059906@qq.com
spring.mail.password=这个是你的授权码
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.default-encoding=UTF-8
spring.mail.port=465
spring.mail.properties.mail.smtp.socketFactory.port = 465
spring.mail.properties.mail.smtp.socketFactory.class = javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.socketFactory.fallback = false
这样就ok了,springboot 发邮件的示例代码:https://github.com/rstyro/spring-boot/tree/master/springboot-mail
https://blog.csdn.net/vbirdbest/article/details/79836854
本文展示一下如何使用spring mail来发送html邮件。
maven
<!-- email -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
发送图片
public void send(String from, String[] toMails, String subject, String text,
Map<String,Object> inlines) throws Exception{
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(from);
helper.setTo(toMails);
helper.setSubject(subject);
//support html
helper.setText(text, true);
// inline
if(inlines != null){
for(Map.Entry<String,Object> entry: inlines.entrySet()){
if(entry.getValue() instanceof ClassPathResource){
helper.addInline(entry.getKey(), (Resource) entry.getValue());
}
}
}
mailSender.send(mimeMessage);
}
测试
- 发送实例
ClassPathResource classPathResource = new ClassPathResource("image_2.png");
Map<String,Object> att = new HashMap<>();
att.put("image",classPathResource);
String content = "<html>
<body>
<h4>spring mail发送实例</h4>
<img src='cid:image'/><br>
</body>
</html>";
try{
mailService.send(new String[]{"xxxxx@163.com"},"spring mail发送实例",content,att);
}catch (Exception e){
e.printStackTrace();
}
- 异常
org.springframework.mail.MailSendException: Failed messages: com.sun.mail.smtp.SMTPSendFailedException: 554 DT:SPM 126 smtp7,DsmowAB3U6X1_LdZjIz+Aw--.26008S3 1505230070,please see http://mail.163.com/help/help_spam_16.htm?ip=123.65.107.103&hostid=smtp7&time=1505230070
; message exception details (1) are:
Failed message 1:
com.sun.mail.smtp.SMTPSendFailedException: 554 DT:SPM 126 smtp7,DsmowAB3U6X1_LdZjIz+Aw--.26008S3 1505230070,please see http://mail.163.com/help/help_spam_16.htm?ip=123.65.107.103&hostid=smtp7&time=1505230070
at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2267)
at com.sun.mail.smtp.SMTPTransport.finishData(SMTPTransport.java:2045)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1260)
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:448)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:345)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:340)
错误码554
554 DT:SPM 发送的邮件内容包含了未被许可的信息,或被系统识别为垃圾邮件。请检查是否有用户发送病毒或者垃圾邮件;
被网易邮箱识别为垃圾邮件了,有个歪招,就是把发送邮箱添加到cc里头
helper.setCc(from);