【Email】基于SpringBoot3.4.x集成发送邮件功能

【Email】基于SpringBoot3.4.x集成发送邮件功能

摘要

在业务系统开发过程中,经常有发送邮件的需求,希望可以系统在某个时候自动触发邮件,或者支持用户主动触发邮件,Spring Boot框架提供了发送邮件的功能,通过简单的配置即可实现。

有时候不仅要发送邮件,对邮件内容格式、样式还有更高要求,我们也可以利用模板引擎来实现,比如ThymeleafFreemarker等等。

本着"最新 "原则,这篇文章依然采用最新版的Spring Boot 3.4.0OpenJDK最新LTS21IntelliJ IDEA最新社区版2024.3.1

本地开发环境说明

开发用到的主要框架、工具版本如下

开发依赖 版本
Spring Boot 3.4.0
spring-boot-starter-mail 3.4.0
spring-boot-starter-thymeleaf 3.4.0
JDK 21
IntelliJ IDEA 2024.3.1

工程目录结构大致如下

pom.xml

xml 复制代码
<dependencies>
    <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>
</dependencies>

启动类

java 复制代码
package com.wen3.demo.email;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author: tangheng
 */
@SpringBootApplication
public class EmailDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(EmailDemoApplication.class, args);
    }
}

application.yaml

yaml 复制代码
spring:
  mail:
    host: "smtp.sina.com" # 发件服务器地址,不同邮件平台地址不同
    port: 25 #常用邮件端口25、109、110、143、465、995、993、994 如果开启了SSL安全则使用对应的端口号,25为非加密端口号
    username: xxxx@sina.com #发送邮件的账号
    password: xxxxxxxxxxxxxxxx #发送邮件账号的授权码,这里的授权码不是验证码.需要到邮箱
    default-encoding: utf-8 #设置编码
    properties: # 设置邮件超时时间防止服务器阻塞
      timeout: 5000
      connection-timeout: 5000
      write-timeout: 5000
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

写一个邮件模板

email-template.html内容如下

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>[[${title}]]</title>
</head>
<body>
<div style="background-color:#ECECEC; padding: 15px;">
    <table cellpadding="0" align="center"
           style="width: 600px; margin: 0px auto; text-align: left; position: relative; border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; font-size: 14px; font-family:微软雅黑, 黑体; line-height: 1.5; box-shadow: rgb(153, 153, 153) 0px 0px 5px; border-collapse: collapse; background-position: initial initial; background-repeat: initial initial;background:#fff;">
        <tbody>
        <tr>
            <th valign="middle"
                style="height: 25px; line-height: 25px; padding: 15px 35px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #42a3d3; background-color: #49bcff; border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px;">
                <font face="微软雅黑" size="5" style="color: rgb(255, 255, 255); ">测试邮件</font>
            </th>
        </tr>
        <tr>
            <td>
                <div style="padding:25px 35px 40px; background-color:#fff;">
                    <h2 style="margin: 5px 0px; ">
                        <font color="#333333" style="line-height: 20px; ">
                            <font style="line-height: 22px; " size="4">
                                亲爱的<b>[[${email}]]</b>用户,您好:</font>
                        </font>
                    </h2>
                    <p>首先感谢您加入【运维自助平台】!请在验证页面输入以下验证码:<br>
                        <b style="font-size: 18px">[[${code}]]</b><br>
                        本验证码5分钟内有效,为了保障您的账户安全,请勿向任何人提供此验证码。感谢您的支持!<br>
                        如果您有什么疑问可以联系管理员,Email: admin@xxx.com</p>
                    <p align="right">运维自助平台</p>
                    <p align="right">[[${date}]]</p>
                    <div style="width:700px;margin:0 auto;">
                        <div style="padding:10px 10px 0;border-top:1px solid #ccc;color:#747474;margin-bottom:20px;line-height:1.3em;font-size:12px;">
                            <p>本邮件系统自动发送,请勿回复!<br>
                                请保管好您的邮箱,避免账号被他人盗用
                            </p>
                            <p>©运维自助平台</p>
                        </div>
                    </div>
                </div>
            </td>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>

定义模板引擎工具类

TemplateUtil.java内容如下

java 复制代码
package com.wen3.demo.email.template;


import cn.hutool.core.date.DateUtil;
import jakarta.annotation.Resource;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.util.Date;

/**
 * @author: tangheng
 */
@Service
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TemplateUtil {

    @Resource
    private TemplateEngine templateEngine;

    /**
     * 获得验证码模板
     */
    public String getCaptchaTempl(String email, String code) {
        Context context = new Context();
        //设置模板所需的参数
        context.setVariable("title","验证码");
        context.setVariable("email",email);
        context.setVariable("code",code);
        context.setVariable("date", DateUtil.format(new Date(),"yyyy-MM-dd hh:mm:ss"));
        //通过模板类将动态参数传入HTML模板,并返回模板内容 参数一:模板名字,参数二:动态参数Web文本
        String content = templateEngine.process("/email-template", context);
        return content;
    }
}

定义一个邮件发送对象

java 复制代码
package com.wen3.demo.email.dto;


import lombok.*;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;
import lombok.experimental.SuperBuilder;

import java.util.List;

/**
 * 邮件发送对象
 *
 * @author: tangheng
 */
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@SuperBuilder
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
public class EMailCmd {

    List<String> tos;
    String subject;
    String text;
}

封装一个邮件发送器

java 复制代码
package com.wen3.demo.email.sender;


import com.wen3.demo.email.dto.EMailCmd;
import jakarta.annotation.Resource;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.AccessLevel;
import lombok.SneakyThrows;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

/**
 * @author: tangheng
 */
@Slf4j
@Service
@FieldDefaults(level = AccessLevel.PRIVATE)
public class EmailSender {

    @Resource
    JavaMailSender mailSender;

    public void sendEMail(EMailCmd eMailCmd) {
        try {
            SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
            simpleMailMessage.setFrom("太空眼睛<best5721@sina.com>"); //设置发送邮件账号
            simpleMailMessage.setTo(eMailCmd.getTos().toArray(String[]::new)); //设置接收邮件的人,可以多个
            simpleMailMessage.setSubject(eMailCmd.getSubject()); //设置发送邮件的主题
            simpleMailMessage.setText(eMailCmd.getText()); //设置发送邮件的内容
            mailSender.send(simpleMailMessage);
        } catch (MailException e) {
            log.error("邮件发送失败!");
        }
    }

    @SneakyThrows
    public void sendHtmlEMail(EMailCmd eMailCmd) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper minehelper = new MimeMessageHelper(message, true);
            minehelper.setFrom("太空眼睛<best5721@sina.com>");
//            minehelper.setFrom("best5721@sina.com", "太空眼睛");
            minehelper.setTo(eMailCmd.getTos().toArray(String[]::new)); //设置接收邮件的人,可以多个
            minehelper.setSubject(eMailCmd.getSubject()); //设置发送邮件的主题
            minehelper.setText(eMailCmd.getText(),true); //设置发送邮件的内容 第二个设置为true则可以发送带HTML的邮件
            mailSender.send(message);
        } catch (MessagingException e) {
            log.error("邮件发送失败!");
        }
    }
}

邮件地址的格式可以写成best5721@sina.com

也可以写成太空眼睛<best5721@sina.com>

单元测试

邮件模板单元测试

java 复制代码
package com.wen3.demo.email.template;

import cn.hutool.core.util.RandomUtil;
import com.wen3.demo.email.EmailDemoSpringBootTestBase;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class TemplateUtilTest extends EmailDemoSpringBootTestBase {

    @Resource
    TemplateUtil templateUtil;

    @Test
    void getCaptchaTempl() {
        String email = "tangheng";
        String code = RandomUtil.randomNumbers(5);
        String testResult = templateUtil.getCaptchaTempl(email,code);
        log.info("testResult: {}", testResult);
        assertNotNull(testResult);
    }
}

发送邮件单元测试

java 复制代码
package com.wen3.demo.email.sender;

import cn.hutool.core.util.RandomUtil;
import com.wen3.demo.email.EmailDemoSpringBootTestBase;
import com.wen3.demo.email.dto.EMailCmd;
import com.wen3.demo.email.template.TemplateUtil;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.mail.MailProperties;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

class EmailSenderTest extends EmailDemoSpringBootTestBase {

    @Resource
    EmailSender emailSender;
    @Resource
    TemplateUtil templateUtil;
    @Resource
    MailProperties mailProperties;

    @Test
    void sendHtmlEMail() {
        String to = "friendly1234@126.com";
        EMailCmd eMailCmd = EMailCmd.builder()
                .tos(List.of(to))
                .subject("测试邮件")
                .text(templateUtil.getCaptchaTempl(to, RandomUtil.randomNumbers(5)))
                .build();
        emailSender.sendHtmlEMail(eMailCmd);
    }
}

邮件效果

参考资料

相关推荐
吾疾唯君医16 小时前
Java SpringBoot集成积木报表实操记录
java·spring boot·spring·导出excel·积木报表·数据文件下载
正儿八经的少年19 小时前
Spring Boot 两种激活配置方式的作用与区别
java·spring boot·后端
疯狂成瘾者19 小时前
Spring Boot 项目中的 SMTP 邮件验证码服务技术解析
java·spring boot·后端
xifangge202520 小时前
【深度排障】从 OS 底层寻址剖析 javac 不是内部或外部命令 核心报错:变量空间隔离与自动化部署终极范式
java·开发语言·jdk·自动化
啃臭21 小时前
AOP和反射
java·spring boot
河阿里21 小时前
SpringBoot:Spring Task定时任务完整使用教学
java·spring boot·spring
向阳而生66021 小时前
iframe 使用全解析:语法、避坑与实操指南(新手友好)
html
五阿哥永琪1 天前
从0开始做一个导出功能,完整流程
spring boot
a1117761 天前
细胞结构实验室(react 开源)
前端·javascript·开源·html
java1234_小锋1 天前
SpringBoot可以同时处理多少请求?
java·spring boot·后端