Spring Boot 发送邮件

Maven 依赖

<!--mail-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

如果需要指定版本,也可以从mvn repo中找到你需要的版本号。

Spring Mail 服务简介

Spring mail 是Spring 框架提供的一个程序库,用于发送电子邮件,使我们不受底层邮件系统的限制,只关注客户端进行资源处理。Spring mail 包的内容如下:

在这里插入图片描述

  • MailSender 接口:核心接口,提供用于发送简单电子邮件的基本功能。
  • JavaMailSender 接口:上述MailSender的子接口。它支持MIME消息,并且通常与MimeMessageHelper类结合使用以创建MimeMessage。
  • JavaMailSenderImpl 类:提供JavaMailSender接口的实现。它支持MimeMessage和SimpleMailMessage。
  • SimpleMailMessage类:用于创建简单的邮件,包括from(发送者),to(接收者),cc(抄送),subject(主题)和text(文本)等字段。
  • MimeMessagePreparator接口:提供用于接收MIME消息的回调接口。
  • MimeMessageHelper类:用于创建MIME消息的帮助器类。它提供在HTML布局中对图像,典型邮件附件和文本内容的支持。

邮件服务配置

引入maven依赖之后,下一步就是使用spring.mail.*namespace 在 application.properties 文件中配置邮件服务。

spring:
  mail:
    default-encoding: UTF-8
    #邮件服务器的地址:例如smtp.qq.com,smtp.gmail.com
    host: localhost
    #登陆服务器的用户名和密码
    username: username
    password: password
    port: 25
    properties:
      mail:
        debug: false
        smtp:
          debug: false
          auth: true
          #启用tls连接
          starttls: true
    protocol: smtp
    test-connection: false

发送邮件

发送简单邮件

@Service
public class MailServiceImpl implements MailService {

    @Autowired
    private JavaMailSender javaMailSender;

    @Override
    public void sendSimpleMessage() {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("abc@qq.com");
        message.setTo("efd@qq.com");
        message.setSubject("Test send simple mail message");
        message.setText("Hello world!");

        javaMailSender.send(message);
    }
}

发送附件邮件

 @Override
    public void sendMessageWithAttachment() {
        MimeMessage message = javaMailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);

            helper.setTo("to@qq.com");
            helper.setFrom("from@qq.com");
            helper.setSubject("Send attachment file to email");
            helper.setText("attachment file...");

            FileSystemResource file = new FileSystemResource(new File("Absolute path"));
            helper.addAttachment("Invoice", file);
            
			javaMailSender.send(message);
        } catch (MessagingException ex) {
            logger.error("Failed to send email to. error={}", ex.getMessage());
        }
    }

发送模板邮件

Spring 中可以作为邮件模板的有几个选择:Velocity,Freemarker,Thymeleaf。 SpringBoot 1.4.0以后 Velocity 废弃了,官方建议用Freemarker。而Thymeleaf的效率没有freemaker高(评测见参考文章【4】)。

Freemarker 的语法可以参考官网的手册:https://freemarker.apache.org/docs/index.html
中文手册:https://sourceforge.net/projects/freemarker/files/chinese-manual/

同样,我们先引入 Freemarker 的 Maven 依赖。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

然后在项目的 /resoource/templates 目录下添加一个 Freemarker 模板文件 notification.flt

<html>
<head>
  <title>Hello world!</title>
</head>
<body>
  <h1>Hello</h1>
  <p>My name is ${name}</p>
 </body>
</html>

在 SpringBoot 的配置文件中加上 Freemarker 的相关配置:

spring:
  freemarker:
    template-loader-path: classpath:/templates/
    enabled: true
    cache: false
    charset: UTF-8
    content-type: text/html
    check-template-location: true

EmailServiceImpl 中使用 Freemarker 模板发送邮件:

@Service
public class MailServiceImpl implements MailService {

    private static final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;

    @Override
    public void sendMessageWithFreemarkerTemplate() {
        MimeMessage message = javaMailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);

            helper.setTo("to@qq.com");
            helper.setFrom("from@qq.com");
            helper.setSubject("Send freemarker template to email");

            HashMap<String, Object> models = new HashMap<>();
            models.put("name", "freemarker");

            Template template = freeMarkerConfigurer.getConfiguration().getTemplate("notification.flt");
            String text = FreeMarkerTemplateUtils.processTemplateIntoString(template, models);
            
            helper.setText(text);
            javaMailSender.send(message);
        } catch (Exception ex) {
            logger.error("Failed to send email to. error={}", ex.getMessage());
        }
    }
}

至此实现了三中方式:纯文本,富文本(图片/附件),Freemarker模版的邮件发送功能,接下来就来测试一下我们的邮件是否能发送出去吧。

测试邮件发送服务

我们为了测试邮件服务的发送功能,暂时可以先不用使用真正的邮件服务器,而是换成GreenMail
GreenMail是用于测试目的的电子邮件服务器,可以用于邮件集成测试或用于开发的轻量级沙盒邮件服务器。具体的使用方法可以参考官网上的用例

这里先引入GreenMail 的Maven依赖:

<dependency>
	<groupId>com.icegreen</groupId>
	<artifactId>greenmail</artifactId>
	<version>1.5.11</version>
	<scope>test</scope>
</dependency>

在Spring boot 的测试文件(application-test.yaml)中配置用于邮件服务的相关属性。

spring:
  mail:
    default-encoding: UTF-8
    host: localhost
    username: abc@qq.com
    password: password
    port: 3025
    properties:
      mail:
        debug: false
        smtp:
          debug: false
          auth: true
          starttls: true
    protocol: smtp
    test-connection: false

我们创建一个自定义的 JUnit Rule 来初始化和停止GreenMail邮件服务器。

public class SmtpServerRule extends ExternalResource {

	# 设置发送邮件服务的用户的用户名
    private static final String USER_PASSWORD = "password";
    # 设置发送邮件服务用户的密码
    private static final String USER_NAME = "abc@qq.com";

    private GreenMail smtpServer;

    @Override
    protected void before() throws Throwable {
        super.before();
        smtpServer = new GreenMail(ServerSetupTest.SMTP);
        smtpServer.start();
        // setup user on the mail server
        smtpServer.setUser(USER_NAME, USER_PASSWORD);
    }

    public MimeMessage[] getMessage() {
        return smtpServer.getReceivedMessages();
    }

    @Override
    protected void after() {
        super.after();
        smtpServer.stop();
    }
}

然后就可以开始写我们的测试用例了。
我们使用JUnit @Rule注解配置SmtpServerRule。这标记了在每个集成测试之前和之后要调用的自定义规则。并允许我们拦截传入的电子邮件。最后,我们做出一些断言并验证发送的电子邮件是否等于接收的电子邮件。

@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class MailServiceImplTest {

    @Rule
    public SmtpServerRule smtpServerRule = new SmtpServerRule();

    @Autowired
    private MailService mailService;

    @Test
    public void sendSimpleMessage() throws MessagingException {
        mailService.sendSimpleMessage();

        MimeMessage[] messages = smtpServerRule.getMessage();
        assertEquals("Test send simple mail message", messages[0].getSubject());
        assertEquals("abc@qq.com", messages[0].getFrom()[0].toString());
        assertEquals("efd@qq.com", messages[0].getAllRecipients()[0].toString());
    }
}

另外的两种邮件参考上面的代码实现。

总结

在这篇文章中,我们展示了如何通过Spring Boot应用程序设置和发送电子邮件。所有这些示例和代码片段的实现都可以在MyGitHub项目中找到。

参考文章

【1】Testing mail code in Spring Boot application

【2】Spring Mail Integration Testing with JUnit and GreenMail Example

【3】Guide to Spring Email

【4】SpringBoot开发案例之整合mail发送服务

posted @ 2020-09-17 14:49  chenxueqiang  阅读(325)  评论(0编辑  收藏  举报