Springboot 系列(十三)使用邮件服务

简介: Springboot 系列(十三)使用邮件服务

在我们这个时代,邮件服务不管是对于工作上的交流,还是平时的各种邮件通知,都是一个十分重要的存在。Java 从很早时候就可以通过 Java mail 支持邮件服务。Spring 更是对 Java mail 进行了进一步的封装,抽象出了 JavaMailSender. 后来随着 Springboot 的出现,理所当然的出现了 spring-boot-starter-mail. 不管怎么说,每次的封装都让使用变得越来越简单。


Springboot mail 依赖


创建 Springboot 项目不提,先看一下总体目录结构。


微信图片_20220413145000.jpg

                                               项目结构


直接引入 Springboot 邮件服务所需的依赖。


<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 邮件服务 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <!-- Thymeleaf 模版,用于发送模版邮件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


Springboot mail 配置


使用邮件服务需要配置自己可以使用的邮箱信息,一般需要配置发送协议 SMTP、邮箱帐号(本次以126邮箱为例)、邮箱密码以及编码格式。


spring.mail.host=smtp.126.com
spring.mail.port=25
# 你的邮箱地址
spring.mail.username=niumoo@126.com 
# 你的授权码(126 和 163 以及 qq 邮箱 都需要授权码登录,没有授权码的直接登录网页版邮箱设置里设置)
spring.mail.password=password
spring.mail.default-encoding=UTF-8


Springboot mail 文本邮件


文本邮件是最简单也是最基础的一种邮件,使用 Spring 封装的 JavaMailSender 直接发送就可以了。


创建 MailService 类,注入 JavaMailSender 用于发送邮件,使用 @Value("${spring.mail.username}") 绑定配置文件中的参数用于设置邮件发送的来邮箱。使用 @Service 注解把 MailService 注入到 Spring 容器,使用 Lombok@Slf4j 引入日志。


/**
 * <p>
 * 邮件服务
 *
 * @Author niujinpeng
 * @Date 2019/3/10 21:45
 */
@Service
@Slf4j
public class MailService {
    @Value("${spring.mail.username}")
    private String from;
    @Autowired
    private JavaMailSender mailSender;
    /**
     * 发送简单文本邮件
     * 
     * @param to
     * @param subject
     * @param content
     */
    public void sendSimpleTextMail(String to, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(to);
        message.setSubject(subject);
        message.setText(content);
        message.setFrom(from);
        mailSender.send(message);
        log.info("【文本邮件】成功发送!to={}", to);
    }
}


创建 Springboot 的单元测试类测试文本邮件,实验中的收信人为了方便,都设置成了自己的邮箱。


@RunWith(SpringRunner.class)
@SpringBootTest
public class MailServiceTest {
    @Autowired
    private MailService mailService;
    @Autowired
    private TemplateEngine templateEngine;
    @Test
    public void sendSimpleTextMailTest() {
        String to = "niumoo@126.com";
        String subject = "Springboot 发送简单文本邮件";
        String content = "<p>第一封 Springboot 简单文本邮件</p>";
        mailService.sendSimpleTextMail(to, subject, content);
    }
}


运行单元测试,测试文本邮件的发送。


PS:如果运行报出异常 AuthenticationFailedException: 535 Error. 一般都是用户名和密码有误。


Caused by: javax.mail.AuthenticationFailedException: 535 Error: authentication failed
    at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:965)
    at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:876)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:780)
    at javax.mail.Service.connect(Service.java:366)
    at org.springframework.mail.javamail.JavaMailSenderImpl.connectTransport(JavaMailSenderImpl.java:517)
    at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:436)
    ... 34 more


正常运行输出成功发送的日志。


2019-03-11 23:35:14.743  INFO 13608 --- [           main] n.codingme.boot.service.MailServiceTest  : Started MailServiceTest in 3.964 seconds (JVM running for 5.749)
2019-03-11 23:35:24.718  INFO 13608 --- [           main] net.codingme.boot.service.MailService    : 【文本邮件】成功发送!to=niumoo@126.com


查看邮箱中的收信。


微信图片_20220413145102.jpg

                                                文本邮件


文本邮件正常收到,同时可见文本邮件中的 HTML 标签也不会被解析。


Springboot mail HTML 邮件


在上面的 MailService 类里新加一个方法 sendHtmlMail,用于测试 HTML 邮件。


/**
     * 发送 HTML 邮件
     * 
     * @param to
     * @param subject
     * @param content
     * @throws MessagingException
     */
    public void sendHtmlMail(String to, String subject, String content) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(message, true);
        messageHelper.setFrom(from);
        messageHelper.setTo(to);
        messageHelper.setSubject(subject);
        // true 为 HTML 邮件
        messageHelper.setText(content, true);
        mailSender.send(message);
        log.info("【HTML 邮件】成功发送!to={}", to);
    }


在测试方法中增加 HTML 邮件测试方法。


@Test
    public void sendHtmlMailTest() throws MessagingException {
        String to = "niumoo@126.com";
        String subject = "Springboot 发送 HTML 邮件";
        String content = "<h2>Hi~</h2><p>第一封 Springboot HTML 邮件</p>";
        mailService.sendHtmlMail(to, subject, content);
    }


运行单元测试,查看收信情况。

微信图片_20220413145135.jpg

                                            HTML 邮件


HTML 邮件正常收到,HTML 标签也被解析成对应的样式。


Springboot mail 附件邮件


在上面的 MailService 类里新加一个方法 sendAttachmentMail,用于测试 附件邮件。


/**
     * 发送带附件的邮件
     * 
     * @param to
     * @param subject
     * @param content
     * @param fileArr
     */
    public void sendAttachmentMail(String to, String subject, String content, String... fileArr)
        throws MessagingException {
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
        messageHelper.setFrom(from);
        messageHelper.setTo(to);
        messageHelper.setSubject(subject);
        messageHelper.setText(content, true);
        // 添加附件
        for (String filePath : fileArr) {
            FileSystemResource fileResource = new FileSystemResource(new File(filePath));
            if (fileResource.exists()) {
                String filename = fileResource.getFilename();
                messageHelper.addAttachment(filename, fileResource);
            }
        }
        mailSender.send(mimeMessage);
        log.info("【附件邮件】成功发送!to={}", to);
    }


在测试方法中增加附件邮件测试方法。


@Test
    public void sendAttachmentTest() throws MessagingException {
        String to = "niumoo@126.com";
        String subject = "Springboot 发送 HTML 附件邮件";
        String content = "<h2>Hi~</h2><p>第一封 Springboot HTML 附件邮件</p>";
        String filePath = "pom.xml";
        mailService.sendAttachmentMail(to, subject, content, filePath, filePath);
    }


运行单元测试,查看收信情况。

微信图片_20220413145335.jpg

                                              附件邮件


带附件的邮件正常收到,多个附件的实现方式同理。


Springboot mail 图片邮件


图片邮件和其他的邮件方式略有不同,图片邮件需要先在内容中定义好图片的位置并出给一个记录 ID ,然后在把图片加到邮件中的对于的 ID 位置。


在上面的 MailService 类里新加一个方法 sendImgMail,用于测试 附件邮件。


/**
     * 发送带图片的邮件
     *
     * @param to
     * @param subject
     * @param content
     * @param imgMap
     */
    public void sendImgMail(String to, String subject, String content, Map<String, String> imgMap)
        throws MessagingException {
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
        messageHelper.setFrom(from);
        messageHelper.setTo(to);
        messageHelper.setSubject(subject);
        messageHelper.setText(content, true);
        // 添加图片
        for (Map.Entry<String, String> entry : imgMap.entrySet()) {
            FileSystemResource fileResource = new FileSystemResource(new File(entry.getValue()));
            if (fileResource.exists()) {
                String filename = fileResource.getFilename();
                messageHelper.addInline(entry.getKey(), fileResource);
            }
        }
        mailSender.send(mimeMessage);
        log.info("【图片邮件】成功发送!to={}", to);
    }

在测试方法中增加图片邮件测试方法,测试方法中使用的 apple.png 是项目里的一个图片。可以看上面的项目结构。

@Test
    public void sendImgTest() throws MessagingException {
        String to = "niumoo@126.com";
        String subject = "Springboot 发送 HTML 图片邮件";
        String content =
            "<h2>Hi~</h2><p>第一封 Springboot HTML 图片邮件</p><br/><img src=\"cid:img01\" /><img src=\"cid:img02\" />";
        String imgPath = "apple.png";
        Map<String, String> imgMap = new HashMap<>();
        imgMap.put("img01", imgPath);
        imgMap.put("img02", imgPath);
        mailService.sendImgMail(to, subject, content, imgMap);
    }


运行单元测试,查看收信情况。


微信图片_20220413145404.jpg

                                           图片邮件


两个图片正常显示在邮件里。


Springboot mail 模版邮件


模版邮件的用处很广泛,像经常收到的注册成功邮件或者是操作通知邮件等都是模版邮件,模版邮件往往只需要更改其中的几个变量。Springboot 中的模版邮件首选需要选择一款模版引擎,在引入依赖的时候已经增加了模版引擎 Thymeleaf.


模版邮件首先需要一个邮件模版,我们在 Templates 下新建一个 HTML 文件 RegisterSuccess.html. 其中的 username 是给我们自定义的。


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>注册成功通知</title>
</head>
<body>
<p>[[${username}]],您好!
</p>
<p>
    新的公钥已添加到你的账户:<br/>
    标题: HP-WIN10 <br/>
    如果公钥无法使用,你可以在这里重新添加: SSH Keys
</p>
</body>
</html>


在邮件服务 MailService 中注入模版引擎,然后编写邮件模版发送代码。


@Autowired
    private TemplateEngine templateEngine;
    /**
     * 发送模版邮件
     * 
     * @param to
     * @param subject
     * @param paramMap
     * @param template
     * @throws MessagingException
     */
    public void sendTemplateMail(String to, String subject, Map<String, Object> paramMap, String template)
        throws MessagingException {
        Context context = new Context();
        // 设置变量的值
        context.setVariables(paramMap);
        String emailContent = templateEngine.process(template, context);
        sendHtmlMail(to, subject, emailContent);
        log.info("【模版邮件】成功发送!paramsMap={},template={}", paramMap, template);
    }


在单元单元测试中增加模版邮件测试方法,然后发送邮件测试。


@Test
    public void sendTemplateMailTest() throws MessagingException {
        String to = "niumoo@126.com";
        String subject = "Springboot 发送 模版邮件";
        Map<String, Object> paramMap = new HashMap();
        paramMap.put("username", "Darcy");
        mailService.sendTemplateMail(to, subject, paramMap, "RegisterSuccess");
    }


查看收信情况。


微信图片_20220413145438.jpg

                                                      模版邮件


可以发现模版邮件已经正常发送了。


Springboot mail 补充


上面的例子中,是 Springboot 邮件服务的基本用法,代码也有很多重复,和实际的使用情况相比还有很多不足,比如缺少异常处理机制,在发送失败时的重试机制也没有,实际情况中邮件服务往往对实时性不高,多说情况下会用于异步请求

相关文章
|
2月前
|
Java Spring
Spring boot 运行服务jar外配置配置文件方式总结
Spring boot 运行服务jar外配置配置文件方式总结
401 0
|
22天前
|
前端开发 JavaScript Java
【实操】SpringBoot监听Iphone15邮件提醒,Selenium+Python自动化抢购脚本
本文介绍了一个结合SpringBoot和Python的实用功能,旨在监控iPhone 15的库存状态并通过邮件提醒用户。系统采用SpringBoot监听苹果官网API,解析JSON数据判断是否有货,并展示最近的库存记录。此外,还能自动触发Selenium+Python脚本实现自动化购买。文中详细介绍了技术栈、接口分析、邮件配置及自动化脚本的设置方法。该项目不仅适用于熟悉后端开发的人员,也适合回顾Layui和Jquery等前端技术。
39 0
【实操】SpringBoot监听Iphone15邮件提醒,Selenium+Python自动化抢购脚本
|
1天前
|
缓存 前端开发 Java
springboot 的单体服务 字典参数转译
本文介绍了如何在Spring Boot项目中使用缓存来管理字典参数,并确保前后端数据一致性。首先,通过`@EnableCaching`启用缓存功能,接着创建一个自定义的字典缓存类`DicCache`。然后,通过配置类将`DicCache`添加到`cacheManager`中。此外,对字典服务进行改造,使用`@CachePut`和`@CacheEvict`注解保证数据一致性。最后,实现自定义注解`@DicSerializer`和序列化处理类`DictSerializerHandel`,用于在序列化过程中自动转换字典值。通过这种方式,可最小化代码改动并提高系统性能。
springboot 的单体服务 字典参数转译
消息中间件 缓存 监控
29 0
|
1月前
|
小程序 JavaScript Java
微信小程序+SpringBoot接入后台服务,接口数据来自后端
这篇文章介绍了如何将微信小程序与SpringBoot后端服务进行数据交互,包括后端接口的编写、小程序获取接口数据的方法,以及数据在小程序中的展示。同时,还涉及到了使用Vue搭建后台管理系统,方便数据的查看和管理。
微信小程序+SpringBoot接入后台服务,接口数据来自后端
|
1月前
|
Java Windows
SpringBoot Windows 自启动 - 通过 Windows Service 服务实现
SpringBoot Windows 自启动 - 通过 Windows Service 服务实现
38 2
|
1月前
|
Java 开发者 Spring
"揭秘SpringBoot魔法SPI机制:一键解锁服务扩展新姿势,让你的应用灵活飞天!"
【8月更文挑战第11天】SPI(Service Provider Interface)是Java的服务提供发现机制,用于运行时动态查找和加载服务实现。SpringBoot在其基础上进行了封装和优化,通过`spring.factories`文件提供更集中的配置方式,便于框架扩展和组件替换。本文通过定义接口`HelloService`及其实现类`HelloServiceImpl`,并在`spring.factories`中配置,结合`SpringFactoriesLoader`加载服务,展示了SpringBoot SPI机制的工作流程和优势。
39 5
|
1月前
|
NoSQL Java Linux
springboot+redis+虚拟机 springboot连接linux虚拟机中的redis服务
该博客文章介绍了如何在Spring Boot项目中通过配置和代码实现连接运行在Linux虚拟机上的Redis服务,并提供了详细的步骤和测试结果截图。
springboot+redis+虚拟机 springboot连接linux虚拟机中的redis服务
|
2月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的母婴全程服务管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的母婴全程服务管理系统附带文章源码部署视频讲解等
36 1
基于springboot+vue.js+uniapp的母婴全程服务管理系统附带文章源码部署视频讲解等
|
2月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的志愿服务管理系统设计和实现(源码+LW+部署讲解)
基于SpringBoot+Vue的志愿服务管理系统设计和实现(源码+LW+部署讲解)
47 6