发送邮件算是项目里常用的功能,大体上可以分为四类:
1. 只有文本的简单有邮件
2. 带附件的邮件
3. 带静态资源的邮件
4. 以及带附件的模板邮件。
SpringBoot中集成邮件功能还是非常简单的,主要依赖spring-boot-starter-mail就够了。
在pom.xml文件中添加依赖的包
发送一些固定模板的邮件,就会用到模板引擎,我们可以选择thymeleaf
或者freemarker
,这里我使用了前者。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
在application.yml中增加配置
这里的配置我们定义了SMTP服务地址,发件人的邮箱账号信息。
spring:
mail:
host: smtp.***.net
mailFrom: ***@***.com
username: ******
password: ******
default-encoding: UTF-8
properties:
mail:
smtp:
auth: true
timeout: 25000
再来定义一个配置类获取配置文件中的发送人:
@Data
@Component
public class EmailConfig {
/**
* 发件邮箱
*/
@Value("${spring.mail.mailFrom}")
private String emailFrom;
}
这里我项目依赖了lombok
包,使用@Data
注解省略了get及set方法。
上面的配置中,mailFrom是我定义的发件人邮箱,有企业的公共邮箱登陆是不带邮箱后缀的,这样mailFrom和username的值就是不同的。
倘若邮箱的登陆是带后缀的,那么mailFrom和username的值实际上是相同的,定义配置的时候mailFrom我们可以省略,发件人配置类注入的时候改成${spring.mail.username}
即可。
定义发送邮件接口
import org.thymeleaf.context.Context;
public interface MailService {
/**
* 发送简单邮件
* @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<String> attachments);
/**
* 发送内嵌静态资源邮件
* @param sendTo 收件人
* @param titel 标题
* @param content 内容
* @param attachments 资源id及路径
*/
public void sendInlineMail(String sendTo, String titel, String content, Map<String,String> attachments);
/**
* 发送模板邮件
* @param sendTo 收件人
* @param titel 标题
* @param context 内容参数
* @param attachments 附件
* @param templatePath 模板路径
*/
public void sendTemplateMail(String sendTo, String titel, Context context, List<String> attachments,String templatePath);
}
实现接口
由于业务上我们并不需要关注邮件的发送结果,因此设计上我们直接使用异步方式发送邮件。这里我采用最简单的方式,使用@Async
注解来使得实现类中的方法异步执行。当然如果你不需要,直接去掉注解就可以了。
import org.thymeleaf.context.Context;
@Async
@Service
public class MailServiceImpl implements MailService {
private static final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);
@Autowired
private EmailConfig emailConfig;
@Autowired
private JavaMailSender mailSender;
@Autowired
private TemplateEngine templateEngine;
/**
* 发送简单邮件
* @param sendTo 收件人
* @param titel 标题
* @param content 内容
*/
@Override
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);
try{
mailSender.send(message);
} catch (MailException e) {
logger.error("sendSimpleMail error.", e);
}
}
/**
* 发送简单带附件邮件
* @param sendTo 收件人
* @param titel 标题
* @param content 内容
* @param attachments 附件路径
*/
@Override
public void sendAttachmentsMail(String sendTo, String titel, String content, List<String> attachments) {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper;
try {
helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(emailConfig.getEmailFrom());
helper.setTo(sendTo);
helper.setSubject(titel);
helper.setText(content);
for (String filePath : attachments) {
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName, file);
}
mailSender.send(mimeMessage);
} catch (MessagingException e) {
logger.error("sendAttachmentsMail error.", e);
} catch (MailException e) {
logger.error("sendAttachmentsMail error.", e);
}
}
/**
* 发送内嵌静态资源邮件
* @param sendTo 收件人
* @param titel 标题
* @param content 内容
* @param attachments 资源id及路径
*/
@Override
public void sendInlineMail(String sendTo, String titel, String content, Map<String,String> attachments) {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper;
try {
helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(emailConfig.getEmailFrom());
helper.setTo(sendTo);
helper.setSubject(titel);
helper.setText(content, true);
for (Map.Entry<String, String> entry : attachments.entrySet()) {
FileSystemResource file = new FileSystemResource(new File(entry.getValue()));
helper.addInline(entry.getKey(), file);
}
mailSender.send(mimeMessage);
} catch (MessagingException e) {
logger.error("sendInlineMail error.", e);
} catch (MailException e) {
logger.error("sendInlineMail error.", e);
}
}
/**
* 发送模板邮件
* @param sendTo 收件人
* @param titel 标题
* @param context 内容参数
* @param attachments 附件
* @param templatePath 模板路径
*/
@Override
public void sendTemplateMail(String sendTo, String titel, Context context, List<String> attachments,String templatePath) {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper;
if(context==null){
context = new Context();
}
try {
helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(emailConfig.getEmailFrom());
helper.setTo(sendTo);
helper.setSubject(titel);
String html = templateEngine.process(templatePath,context);
helper.setText(html, true);
for (String filePath : attachments) {
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName, file);
}
mailSender.send(mimeMessage);
} catch (MessagingException e) {
logger.error("sendTemplateMail error.", e);
} catch (MailException e) {
logger.error("sendTemplateMail error.", e);
}
}
}
再来看下我们事先定义好的邮件模板 test.html
,放在 resources/templates/mail
目录下
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
您好[[${username}]], 欢迎来到sundayfine.com! <br/>
<a href="#" th:href="@{https://www.sundayfine.com/?{id}(id=${id})}">点击进入</a>
</body>
</html>
测试
public class MailServiceTest extends SpiritApplicationTests {
@Autowired
private MailService mailService;
//收件人邮箱
private String sendTo = "****@163.com";
/**
* 测试简单邮件
*/
@Test
public void sendSimpleMail() {
String title = "This is a simple mail.";
String content = "This is the content of the mail.";
mailService.sendSimpleMail(sendTo, title, content);
}
/**
* 测试带附件邮件
*/
@Test
public void sendAttachmentsMail() {
String title = "This is an email with attachments.";
String content ="This is the content of the mail.";
List<String> attachments = new ArrayList<String>();
attachments.add("E:\\web_pic\\006tNc79ly1fj8sf9847xj31kw11zhdw.jpg");
attachments.add("E:\\web_pic\\laptop-2590647_1280.jpg");
mailService.sendAttachmentsMail(sendTo,title,content, attachments);
}
/**
* 测试带静态资源邮件
*/
@Test
public void sendInlineMail() {
String title = "This is an email with some static resources.";
StringBuilder content = new StringBuilder();
HashMap<String, String> resMap = new HashMap<String, String>();
String rsc1Id = "resource1";
String rsc2Id = "resource2";
resMap.put(rsc1Id, "E:\\web_pic\\006tNc79ly1fj8sf9847xj31kw11zhdw.jpg");
resMap.put(rsc2Id, "E:\\web_pic\\laptop-2590647_1280.jpg");
content.append("<html><head><title>Title</title></head>");
content.append("<body>");
content.append("<image src=\'cid:" + rsc1Id + "\' /><br/>");
content.append("<image src=\'cid:" + rsc2Id + "\' />");
content.append("</body></html>");
mailService.sendInlineMail(sendTo, title, content.toString(), resMap);
}
/**
* 测试带附件的模板邮件
*/
@Test
public void sendTemplateMail() {
String title = "This is a template mail with attachments.";
Context context = new Context();
context.setVariable("id", "2091");
context.setVariable("username", "nj.sun");
List<String> attachments = new ArrayList<String>();
attachments.add("E:\\web_pic\\006tNc79ly1fj8sf9847xj31kw11zhdw.jpg");
attachments.add("E:\\web_pic\\laptop-2590647_1280.jpg");
mailService.sendTemplateMail(sendTo,title,context, attachments,"mail/test");
}
}
当然在系统中我们发送邮件时还需要记录发送的日志,包括发送的时间,邮件内容,状态,以及失败原因等等,这些可以自己加。上面的代码还算清晰就不多解释了,现在看看集成一个邮件服务是不是简单很多?