Java 中 Spring Boot 框架下的 Email 开发

Email 开发

1. 核心依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

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

hutool工具包:

xml 复制代码
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.11</version>
</dependency>

2. 邮件实体类

  • 这个类更贴近我们的常见信息,用这个去构造邮箱框架的指定邮件类的构造。
java 复制代码
@Data
public class EmailMessage implements Serializable {

    private String sender;

    String[] recipient;

    String[] carbonCopy;

    private String title;

    private String content;

    private Date createTime;

    private static final long serialVersionUID = 1L;

    public void setRecipient(String... recipient) {
        this.recipient = recipient;
    }

    public void setCarbonCopy(String... cc) {
        this.carbonCopy = cc;
    }

    public void setRecipient(@NonNull String recipient) {
        this.recipient = new String[]{recipient};
    }

    public void setCarbonCopy(@NonNull String cc) {
        this.carbonCopy = new String[]{cc};
    }

    public String[] getRecipient() {
        return recipient;
    }

    public String[] getCarbonCopy() {
        return carbonCopy;
    }

    public String getRecipient(int i) {
        return recipient != null ? recipient[i] : null;
    }

    public String getCarbonCopy(int i) {
        return carbonCopy != null ? carbonCopy[i] : null;
    }

}

邮箱格式检查:

java 复制代码
public class EmailValidator {

    public static final String EMAIL_PATTERN = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
    
    public static boolean isEmailAccessible(String email) {
        return email.matches(EMAIL_PATTERN);
    }

}

3. 配置

yaml 复制代码
spring:
  mail:
    host: # 邮箱服务器地址(不填会无法启动成功)
    port: # 邮箱服务器端口
    username: # 发起者的邮箱地址
    password: # 密码(是调用邮箱接口的授权密码,不是邮箱账户密码)
    default-encoding: utf-8
    properties:
      mail:
        smtp:
          socketFactory:
            class: javax.net.ssl.SSLSocketFactory

yeah.net 邮箱为例(其他的邮箱也会有,举一反三)

根据指导即可,获得授权密码!

以smtp为例:

  • 这个就是host,可以查一下,port是465(其他的服务器 port是啥,一查便知)

4. 发送邮件(都是可群发的)

java 复制代码
@Component
@Slf4j
@RequiredArgsConstructor
public class EmailSender {

    private final JavaMailSender javaMailSender;

    private final TemplateEngine templateEngine;
    
    public SimpleMailMessage emailToSimpleMailMessage(EmailMessage emailMessage) {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom(emailMessage.getSender());
        simpleMailMessage.setTo(emailMessage.getRecipient());
        simpleMailMessage.setCc(emailMessage.getCarbonCopy());
        simpleMailMessage.setSubject(emailMessage.getTitle());
        simpleMailMessage.setText(emailMessage.getContent());
        return simpleMailMessage;
    }

    public MimeMessageHelper emailIntoMimeMessageByHelper(MimeMessage mimeMessage, EmailMessage emailMessage) {
        try {
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
            mimeMessageHelper.setFrom(emailMessage.getSender());
            mimeMessageHelper.setCc(emailMessage.getCarbonCopy());
            mimeMessageHelper.setSubject(emailMessage.getTitle());
            mimeMessageHelper.setTo(emailMessage.getRecipient());
            return mimeMessageHelper;
        } catch (MessagingException e) {
            throw new RuntimeException(e);
        }
    }
}

4.1 发送普通邮件(纯文本)

java 复制代码
public void sendSimpleMailMessage(EmailMessage emailMessage) {
    if (Objects.isNull(emailMessage)) {
        throw new RuntimeException("email不能为null!");
    }
    // 封装simpleMailMessage对象
    SimpleMailMessage simpleMailMessage = emailToSimpleMailMessage(emailMessage);
    // 发送
    javaMailSender.send(simpleMailMessage);
}

4.2 发送邮件待附件

java 复制代码
public void sendMailWithFile(EmailMessage emailMessage, File... files) {
    if (Objects.isNull(emailMessage)) {
        throw new RuntimeException("email不能为null!");
    }
    // 封装对象
    try {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper mimeMessageHelper = emailIntoMimeMessageByHelper(mimeMessage, emailMessage);
        // 添加附件
        for (File file : files) {
            if (Objects.nonNull(file)) {
                mimeMessageHelper.addAttachment(file.getName(), file);
            }
        }
        mimeMessageHelper.setText(emailMessage.getContent(), false);
        javaMailSender.send(mimeMessage);
    } catch (MessagingException e) {
        throw new RuntimeException(e);
    }
}

4.3 发送模板邮件

java 复制代码
public void sendModelMail(EmailMessage emailMessage, String template, Object modelMessage) {
    if (Objects.isNull(emailMessage)) {
        throw new RuntimeException("email不能为null!");
    }
    // 封装对象
    try {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper mimeMessageHelper = emailIntoMimeMessageByHelper(mimeMessage, emailMessage);
        // 构造模板消息
        Context context = new Context();
        context.setVariables(BeanUtil.beanToMap(modelMessage));
        //合并模板与数据
        String content = templateEngine.process(template, context);
        mimeMessageHelper.setText(content, true);
        javaMailSender.send(mimeMessage);
    } catch (MessagingException e) {
        throw new RuntimeException(e);
    }
}

其中,template是模板html的路径,以类路径(resources)下的templates包为根目录!

邮件显示的一些对html语法的兼容问题,可以参考文章:HTML邮件 兼容问题_foxmail对html样式支持不好-CSDN博客

一个模板html例子:

  • 经典的邮箱验证登录
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>邮箱验证</title>
  </head>
  <body>
    <span>
      &nbsp;下面是您的身份验证码:
    </span>
    <br />
    <font style="font-size: 50pt">
      &nbsp;<span th:text="${code}"></span>
    </font>
    <br />
    <span>&nbsp;请在&nbsp;</span>
    <font style="font-size: 20pt; color: brown">
      <span th:text="${minutes}"></span>
    </font>
    <span>&nbsp;分钟内完成验证,如非本人操作,请忽略!</span>
  </body>
</html>

原理:将传入的Map的键值对,替换到html里

4.4 发送模板邮件带附件

java 复制代码
public void sendModelMailWithFile(EmailMessage emailMessage, String template, Object modelMessage, File... files) {
    if (Objects.isNull(emailMessage)) {
        throw new RuntimeException("email不能为null!");
    }
    // 封装对象
    try {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper mimeMessageHelper = emailIntoMimeMessageByHelper(mimeMessage, emailMessage);
        // 构造模板消息
        Context context = new Context();
        context.setVariables(BeanUtil.beanToMap(modelMessage));
        //合并模板与数据
        String content = templateEngine.process(template, context);
        mimeMessageHelper.setText(content, true);
        // 添加附件
        for (File file : files) {
            if (Objects.nonNull(file)) {
                mimeMessageHelper.addAttachment(file.getName(), file);
            }
        }
        javaMailSender.send(mimeMessage);
    } catch (MessagingException e) {
        throw new RuntimeException(e);
    }
}

4.5 根据收件人自定义发送模板邮件并且带附件

java 复制代码
public <T, R> void customizedSendEmail(EmailMessage emailMessage, String template, Function<T, R> function, File... files) {
    if (Objects.isNull(emailMessage)) {
        throw new RuntimeException("email不能为null!");
    }
    String sender = emailMessage.getSender();
    String[] carbonCopy = emailMessage.getCarbonCopy();
    String title = emailMessage.getTitle();
    Arrays.stream(emailMessage.getRecipient())
            .parallel()
            .distinct()
            .forEach(s -> {
                try {
                    // 封装对象
                    MimeMessage mimeMessage = javaMailSender.createMimeMessage();
                    MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
                    mimeMessageHelper.setTo(s);
                    mimeMessageHelper.setFrom(sender);
                    mimeMessageHelper.setCc(carbonCopy);
                    mimeMessageHelper.setSubject(title);
                    // 添加附件
                    for (File file : files) {
                        if (Objects.nonNull(file)) {
                            mimeMessageHelper.addAttachment(file.getName(), file);
                        }
                    }
                    // 构造模板消息
                    Context context = new Context();
                    Object modelMessage = function.apply((T) s);
                    context.setVariables(BeanUtil.beanToMap(modelMessage));
                    //合并模板与数据
                    String content = templateEngine.process(template, context);
                    // 通过mimeMessageHelper设置到mimeMessage里
                    mimeMessageHelper.setText(content, true);
                    //发送
                    javaMailSender.send(mimeMessage);
                } catch (MessagingException e) {
                    throw new RuntimeException(e);
                }
            });
}
相关推荐
七夜zippoe5 分钟前
事件驱动架构:构建高并发松耦合系统的Python实战
开发语言·python·架构·eda·事件驱动
古城小栈11 分钟前
Rust Trait 敲黑板
开发语言·rust
hashiqimiya36 分钟前
springboot事务触发滚动与不滚蛋
java·spring boot·后端
因我你好久不见39 分钟前
Windows部署springboot jar支持开机自启动
windows·spring boot·jar
FL171713141 小时前
MATLAB的Sensitivity Analyzer
开发语言·matlab
PPPHUANG1 小时前
一次 CompletableFuture 误用,如何耗尽 IO 线程池并拖垮整个系统
java·后端·代码规范
恩创软件开发1 小时前
创业日常2026-1-8
java·经验分享·微信小程序·小程序
lly2024061 小时前
jEasyUI 设置排序指南
开发语言
一起努力啊~2 小时前
算法刷题--长度最小的子数组
开发语言·数据结构·算法·leetcode