集成JavaMail


我们在发送Email接收Email中已经介绍了如何通过JavaMail来收发电子邮件。在Spring中,同样可以集成JavaMail。

因为在服务器端,主要以发送邮件为主,例如在注册成功、登录时、购物付款后通知用户,基本上不会遇到接收用户邮件的情况,所以本节我们只讨论如何在Spring中发送邮件。

在Spring中,发送邮件最终也是需要JavaMail,Spring只对JavaMail做了一点简单的封装,目的是简化代码。为了在Spring中集成JavaMail,我们在pom.xml中添加以下依赖:

  • org.springframework:spring-context-support:6.0.0
  • jakarta.mail:jakarta.mail-api:2.0.1
  • com.sun.mail:jakarta.mail:2.0.1

以及其他Web相关依赖。

我们希望用户在注册成功后能收到注册邮件,为此,我们先定义一个JavaMailSender的Bean:

  1. @Bean
  2. JavaMailSender createJavaMailSender(
  3. // smtp.properties:
  4. @Value("${smtp.host}") String host,
  5. @Value("${smtp.port}") int port,
  6. @Value("${smtp.auth}") String auth,
  7. @Value("${smtp.username}") String username,
  8. @Value("${smtp.password}") String password,
  9. @Value("${smtp.debug:true}") String debug)
  10. {
  11. var mailSender = new JavaMailSenderImpl();
  12. mailSender.setHost(host);
  13. mailSender.setPort(port);
  14. mailSender.setUsername(username);
  15. mailSender.setPassword(password);
  16. Properties props = mailSender.getJavaMailProperties();
  17. props.put("mail.transport.protocol", "smtp");
  18. props.put("mail.smtp.auth", auth);
  19. if (port == 587) {
  20. props.put("mail.smtp.starttls.enable", "true");
  21. }
  22. if (port == 465) {
  23. props.put("mail.smtp.socketFactory.port", "465");
  24. props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
  25. }
  26. props.put("mail.debug", debug);
  27. return mailSender;
  28. }

这个JavaMailSender接口的实现类是JavaMailSenderImpl,初始化时,传入的参数与JavaMail是完全一致的。

另外注意到需要注入的属性是从smtp.properties中读取的,因此,AppConfig导入的就不止一个.properties文件,可以导入多个:

  1. @Configuration
  2. @ComponentScan
  3. @EnableWebMvc
  4. @EnableTransactionManagement
  5. @PropertySource({ "classpath:/jdbc.properties", "classpath:/smtp.properties" })
  6. public class AppConfig {
  7. ...
  8. }

下一步是封装一个MailService,并定义sendRegistrationMail()方法:

  1. @Component
  2. public class MailService {
  3. @Value("${smtp.from}")
  4. String from;
  5. @Autowired
  6. JavaMailSender mailSender;
  7. public void sendRegistrationMail(User user) {
  8. try {
  9. MimeMessage mimeMessage = mailSender.createMimeMessage();
  10. MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, "utf-8");
  11. helper.setFrom(from);
  12. helper.setTo(user.getEmail());
  13. helper.setSubject("Welcome to Java course!");
  14. String html = String.format("<p>Hi, %s,</p><p>Welcome to Java course!</p><p>Sent at %s</p>", user.getName(), LocalDateTime.now());
  15. helper.setText(html, true);
  16. mailSender.send(mimeMessage);
  17. } catch (MessagingException e) {
  18. throw new RuntimeException(e);
  19. }
  20. }
  21. }

观察上述代码,MimeMessage是JavaMail的邮件对象,而MimeMessageHelper是Spring提供的用于简化设置MimeMessage的类,比如我们设置HTML邮件就可以直接调用setText(String text, boolean html)方法,而不必再调用比较繁琐的JavaMail接口方法。

最后一步是调用JavaMailSender.send()方法把邮件发送出去。

在MVC的某个Controller方法中,当用户注册成功后,我们就启动一个新线程来异步发送邮件:

  1. User user = userService.register(email, password, name);
  2. logger.info("user registered: {}", user.getEmail());
  3. // send registration mail:
  4. new Thread(() -> {
  5. mailService.sendRegistrationMail(user);
  6. }).start();

因为发送邮件是一种耗时的任务,从几秒到几分钟不等,因此,异步发送是保证页面能快速显示的必要措施。这里我们直接启动了一个新的线程,但实际上还有更优化的方法,我们在下一节讨论。

练习

集成JavaMail - 图1下载练习:使用Spring发送邮件 (推荐使用IDE练习插件快速下载)

小结

Spring可以集成JavaMail,通过简单的封装,能简化邮件发送代码。其核心是定义一个JavaMailSender的Bean,然后调用其send()方法。

读后有收获可以支付宝请作者喝咖啡:

集成JavaMail - 图2