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);
                }
            });
}
相关推荐
sky丶Mamba3 分钟前
Spring Boot中获取application.yml中属性的几种方式
java·spring boot·后端
hakesashou4 分钟前
python如何比较字符串
linux·开发语言·python
yufei-coder29 分钟前
C#基础语法
开发语言·c#·.net
数据龙傲天29 分钟前
1688商品API接口:电商数据自动化的新引擎
java·大数据·sql·mysql
长天一色29 分钟前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
_.Switch41 分钟前
Python机器学习模型的部署与维护:版本管理、监控与更新策略
开发语言·人工智能·python·算法·机器学习
醉颜凉43 分钟前
银河麒麟桌面操作系统修改默认Shell为Bash
运维·服务器·开发语言·bash·kylin·国产化·银河麒麟操作系统
NiNg_1_2341 小时前
Vue3 Pinia持久化存储
开发语言·javascript·ecmascript
带带老表学爬虫1 小时前
java数据类型转换和注释
java·开发语言
qianbo_insist1 小时前
simple c++ 无锁队列
开发语言·c++