在小明经历的多个项目开发中,总会遇到 消息通知 的场景,比如某个广告主提交一个表单,我们要通知提醒运营人员及时查看。
消息通知的形式也有很多,比如:短信、邮件、app推送等,本文主要给大家描述一下 邮件 通知的形式,因为邮件相比较其他通知渠道更方便实用(免费),除了简单文本邮件(已经满足大多数情形),本文还会重点说一下集成 Thymeleaf 模版引擎,使用 HTML 的形式发送邮件,尽管 HTML 内容不是标准化的消息格式,但是许多邮件客户端至少支持标记语言的子集,这种方式相比较纯文本展现形式更加友好。
一个普通再也普通不了的SpringBoot项目
还是那句老话,在SpringBoot看来一切都是这么便捷。它已经集成邮件发送所必需的库模块,我们只需将以下依赖添加到 pom.xml
即可。
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
Spring框架中用于Java邮件支持的接口和类组织如下:
MailSender
的子接口。它支持MIME消息,并且主要与 MimeMessageHelper
类一起用于创建 MimeMessage
。建议在此接口实现类 JavaMailSenderImpl
中使用 MimeMessagePreparator
机制; JavaMailSender
的接口,它支持 MimeMessage
和 SimpleMailMessage
; 在以下部分中,我将向大家展示如何使用这些接口和类:
下面举例163邮箱(最常用的):
spring: mail: host: smtp.163.com # 发件服务器 username: coderxm@163.com # 账号 password: xxxx # 密码(163需要授权第三方登录密码,请查看设置-客户端授权码密码开通) port: 465 protocol: smtp default-encoding: utf-8 # 下面这些配置大家不用深究,主要用于配置ssl properties: mail: imap: ssl: socketFactory: fallback: false smtp: auth: true ssl: enable: true socketFactory: class: com.fintech.modules.base.util.mail.MailSSLSocketFactory starttls: enable: true required: true test-connection: false
按照常见的代码结构,我们先定义一个发送邮件的 接口 ,负责创建和发送新的邮件消息。
public interface EmailService { /** * 发送简单文本内容 * @param to 发件人 * @param subject 主题 * @param text 内容 */ void sendSimpleMessage(String to, String subject, String text); }
我们可以将一些常用的配置添加到yml配置文件当中
# 邮件配置 xiaoming: email: subject: "程序员小明" from: "coderxm@163.com" to: "xiaohong@163.com" # 抄送人:类型定义为数组,可以配置多个 cc: - "xiaogang@163.com"
然后再通过注解注入到一个实体类中,这样很优雅,随用随取:
@Configuration @ConfigurationProperties(prefix = "xiaoming.email") @Data public class EmailConfig { private String subject; private String from; private String to; private String[] cc; }
我们再定义一个类去实现这个接口:
@Slf4j @Service public class EmailServiceImpl implements EmailService { @Autowired public JavaMailSender emailSender; @Autowired private EmailConfig emailConfig; @Override public void sendSimpleMessage(String to, String subject, String text) { try { SimpleMailMessage message = new SimpleMailMessage(); message.setTo(to); message.setFrom("coderxm@163.com"); message.setSubject(subject); message.setText(text); emailSender.send(message); } catch (MailException exception) { log.error(ExceptionUtil.stacktraceToString(exception)); } } }
我们做一个简单的测试:简单的邮件是否能够发送成功。
@RunWith(SpringRunner.class) @SpringBootTest public class EmailTest { @Autowired private EmailService emailService; @Test public void testSimple(){ emailService.sendSimpleMessage("ligang@163.com","XX篮球","你好,我想让周琦代言!"); } }
正在洋洋得意(准备划水)的时候,我们的产品突然对我说,“用简单的文本发送邮件也太简陋了吧,显示不出来我们的产品档次”,然后给我了一个样式,让我以这种形式发送,好啊,什么都难不倒小明。我连忙找到我们的前端,(假装低三下四地)让她帮忙排一个页面给我(这个工作我实在不想做,一是懒,二是人家前端肯定比我专业啊),为了保密,我简化一下,大概是这样的:
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head></head> <body> 姓 名:<span th:text="${userName}"></span> 性 别:<span th:text="${gender}"></span> </body> </html>
其实样式很好看的,但是这都不是重点,我们就以此作为模版举个例子,语法使用的都是thymeleaf,在此处就不再赘述,如果有想了解的可以去官网找。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
创建另一个服务类,它主要通过读取html模版封装数据准备邮件内容,在我们之前的示例中,这是一个简单的文本消息。
@Service public class MailContentBuilder { @Autowired private TemplateEngine templateEngine; @Autowired public MailContentBuilder(TemplateEngine templateEngine) { this.templateEngine = templateEngine; } public String build(Map<String, Object> message) { Context context = new Context(); context.setVariables(message); return templateEngine.process("email", context); } }
在 EmailService
增加接口:
public interface EmailService { /** * 发送简单文本内容 * @param to 发件人 * @param subject 主题 * @param text 内容 */ void sendSimpleMessage(String to, String subject, String text); /** * 传递多个变量,用于动态更换页面模版内容 * @param emailInfoMap */ void prepareAndSend(Map<String,Object> emailInfoMap); }
在 EmailServiceImpl
增加发送html形式邮件的实现方法:
@Override public void prepareAndSend(Map<String,Object> emailInfoMap) { MimeMessagePreparator messagePreparator = mimeMessage -> { MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage); messageHelper.setFrom(emailConfig.getFrom()); messageHelper.setTo(emailConfig.getTo()); messageHelper.setCc(emailConfig.getCc()); messageHelper.setSubject(emailConfig.getSubject()); // messageHelper.setText(message); String content = mailContentBuilder.build(info); messageHelper.setText(content,true); }; try { emailSender.send(messagePreparator); } catch (MailException e) { // runtime exception; compiler will not force you to handle it } }
@RunWith(SpringRunner.class) @SpringBootTest public class EmailTest { @Autowired private EmailService emailService; @Test public void testHtml(){ HashMap<String, Object> map = new HashMap<>(); map.put("userName","程序员小明"); map.put("gender","男"); emailService.prepareAndSend(map); } }
整个Springboot发送邮件的场景已经复盘结束,大家如果有用到的速速体验吧!