发送邮件算是项目里常用的功能,大体上可以分为四类:
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"); } }
当然在系统中我们发送邮件时还需要记录发送的日志,包括发送的时间,邮件内容,状态,以及失败原因等等,这些可以自己加。上面的代码还算清晰就不多解释了,现在看看集成一个邮件服务是不是简单很多?