Spring Boot基于FreeMarker发送模板邮件(带附件)

news2024/11/26 8:45:15

目录

    • 一、背景
    • 二、maven依赖
    • 三、编码实现
      • 3.1、邮件对象
      • 3.2、服务层
        • 3.2.1、抄送人
        • 3.2.2、嵌入式资源
        • 3.2.3、附件
      • 3.3、邮件模板
        • 3.3.1、模板引擎
      • 3.4、配置文件
    • 四、测试
      • 4.1、发送简单邮件
      • 4.2、发送复杂邮件
      • 4.3、效果图

一、背景

  邮件在工作中中经常被用到,场景非常的广泛,比如:注册账户,接收验证码,或者是公司发的公告,又或者是异常消息推送等等。本文中的Spring Boot 的版本是2.6.0

二、maven依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.alian</groupId>
    <artifactId>springEmail</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringEmail</name>
    <description>SpringEmail</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <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>

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

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

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.68</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.14</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

三、编码实现

3.1、邮件对象

Email.java

@Data
public class Email {

    /**
     * 邮件发送方
     */
    private String sender;

    /**
     * 邮件接收方
     */
    private List<String> receiverList = new ArrayList<>();

    /**
     * 邮件抄送方
     */
    private List<String> ccList = new ArrayList<>();

    /**
     * 邮件主题
     */
    private String subject;

    /**
     * 邮件内容
     */
    private String content;

    /**
     * 嵌入式资源(key:contentId,value:filePath)
     */
    private Map<String, String> inlineMap=new HashMap<>();

    /**
     * 附件列表(value:filePath)
     */
    private List<String> attachmentList = new ArrayList<>();

    public String[] getReceiverArray() {
        return this.receiverList.toArray(new String[0]);
    }

    public String[] getCcArray() {
        return this.ccList.toArray(new String[0]);
    }

    public String toJsonString() {
        return JSON.toJSONString(this);
    }
}

邮件对象主要包含:

  • 邮件发送方(sender)
  • 邮件接收方(receiverList),支持发送多人
  • 邮件抄送方(ccList),支持抄送多人
  • 邮件主题(subject)
  • 邮件内容(content),可以使用freeMark模板
  • 嵌入式资源(inlineMap),支持嵌入多个资源
  • 附件列表(attachmentList),支持多个附件发送

3.2、服务层

EmailService.java

@Slf4j
@Service
public class EmailService {

    @Autowired
    private JavaMailSenderImpl mailSender;

    @Autowired
    private FreeMarkerConfigurer configurer;

    public boolean sendSimpleEmail(Email email) {
        log.info("发送简单邮件信息:{}", email.toJsonString());
        // 实例化SimpleMailMessage
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        try {
            // 设置邮件发件人
            simpleMailMessage.setFrom(email.getSender());
            // 设置邮件接收人(可以多人)
            simpleMailMessage.setTo(email.getReceiverArray());
            // 设置邮件抄送
            String[] ccArray = email.getCcArray();
            if (ccArray.length > 0) {
                simpleMailMessage.setCc(ccArray); // 普通抄送[邮件接收人可以看到抄送给谁了]
//                simpleMailMessage.setBcc(); // 盲抄送[邮件接收人可以看不到抄送给谁了]
            }
            // 设置邮件主题
            simpleMailMessage.setSubject(email.getSubject());
            // 设置邮件内容
            simpleMailMessage.setText(email.getContent());
            // 发送简单邮件
            mailSender.send(simpleMailMessage);
            return true;
        } catch (Exception e) {
            log.error(null, e);
        }
        return false;
    }

    public boolean sendComplexEmail(Email email, String templateName, Map<String, Object> data) {
        log.info("发送复杂邮件信息:{}", email.toJsonString());
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        try {
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage,true,"UTF-8");
            // 设置邮件发件人
            messageHelper.setFrom(email.getSender());
            // 设置邮件接收人(可以多人)
            messageHelper.setTo(email.getReceiverArray());
            // 设置邮件抄送
            String[] ccArray = email.getCcArray();
            if (ccArray.length > 0) {
                messageHelper.setCc(ccArray); // 普通抄送[邮件接收人可以看到抄送给谁了]
//                messageHelper.setBcc(ccArray); // 盲抄送[邮件接收人可以看不到抄送给谁了]
            }
            // 设置邮件主题
            messageHelper.setSubject(email.getSubject());
            // 通过模板后去内容
            String content = getContent(templateName, data);
            // 设置邮件内容,第二个参数为true表示将发送内容设置为"text/html"
            messageHelper.setText(content, true);
            // 批量处理嵌入式资源
            Map<String, String> inlineMap = email.getInlineMap();
            for (Map.Entry<String, String> entry : inlineMap.entrySet()) {
                String contentId = entry.getKey();
                String filePath = entry.getValue();
                // 设置嵌入式资源
                messageHelper.addInline(contentId, new File(filePath));
            }
            // 批量处理附件
            List<String> attachmentList = email.getAttachmentList();
            for (int i = 0; i < attachmentList.size(); i++) {
                String filePath = attachmentList.get(i);
                String fileName = i + "-" + filePath.substring(filePath.lastIndexOf(File.separator));
                // 设置附件
                messageHelper.addAttachment(fileName, new File(filePath));
            }
            // 发送简单邮件
            mailSender.send(mimeMessage);
            return true;
        } catch (Exception e) {
            log.error(null, e);
        }
        return false;
    }

    public String getContent(String templateName, Map<String, Object> data) throws TemplateException, IOException {
        // 获取模板
        Template template = configurer.getConfiguration().getTemplate(templateName, "UTF-8");
        // 填充数据并把模板转为字符串
        return FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
    }

}

其中:

  • SimpleMailMessage:用来发送简单的文本邮件
  • MimeMessage:用来发送html邮件、带附件的邮件、有静态资源(图片)的邮件

  如果你的代码里有多个附件或者多嵌入式资源,就需要如下:

MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage,true,"UTF-8");

  第二个参数说明你有多个资源文件(嵌入式资源或者附件)

3.2.1、抄送人

  • 普通抄送 setCc():邮件接收人可以看到抄送给谁了
  • 盲抄送 setBcc():邮件接收人可以看不到抄送给谁了

3.2.2、嵌入式资源

  通过MimeMessageHelperaddInline方法可以添加嵌入式资源,比如在邮件里显示图片。

// 设置嵌入式资源
messageHelper.addInline(contentId, new File(filePath));

  需要注意的是

  • 如果模板是<img src=‘cid:CSDN1234’/>,那么contentId就是CSDN1234不要把cid:一起写入了
  • 有多个资源时,contentId不要重复了

3.2.3、附件

  通过MimeMessageHelperaddAttachment方法可以添加附件。

// 设置附件
messageHelper.addAttachment(fileName, new File(filePath));

  需要注意的是:这里的文件名fileName尽量不要相同,如果有相同的,最好加以区分

3.3、邮件模板

complex-email.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>${title}</title>
</head>
<body>
    <p>
        <img width="100" height="50" src='cid:CSDN1234'/>
        <img width="100" height="100"src='cid:Alian1223'/>
        </br>
        <span>欢迎使用CSDN博客系统</span>
    </p>
    <table>
        <tr>
            <td>平台地址:</td>
            <td><a href="${website}">${website}</a></td>
        </tr>
        <tr>
            <td>登录账号:</td>
            <td>${account}</td>
        </tr>
        <tr>
            <td>登录密码:</td>
            <td>${password}</td>
        </tr>
    </table>
    <p>
        温馨提示:密码有效期为90天,密码必须包含大小写字母数字及特殊符号且长度不小于8位,请妥善保管好密码,祝您工作顺利!
    </p>
</body>
</html>

  需要注意的是:我这里的模板文件complex-email.ftl放到resources目录下了

3.3.1、模板引擎

  FreeMarker是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。因为我们发送邮件可能会有很多种,频繁改动代码不方便,所以我们采用模板,增加一个模板,然后把参数传入即可。

@Autowired
private FreeMarkerConfigurer configurer;

public String getContent(String templateName, Map<String, Object> data) throws TemplateException, IOException {
    // 获取模板
    Template template = configurer.getConfiguration().getTemplate(templateName, "UTF-8");
    // 填充数据并把模板转为字符串
    return FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
}

  我们通过FreeMarkerConfigurer来获取到我们的模板,然后通过Spring提供的方法FreeMarkerTemplateUtils.processTemplateIntoString(template, data)完成数据的封装。

  当我们使用MimeMessage发送html邮件时,设置邮件内容时,第二个参数为true表示将发送内容设置为"text/html",不然就会把内容当成文本发送了。

// 设置邮件内容,第二个参数为true表示将发送内容设置为"text/html"
messageHelper.setText(content, true);

3.4、配置文件

application.properties

#服务端口
server.port=8080
#上下文路径
server.servlet.context-path=/email

#163邮箱
#配置邮件发送的服务器
spring.mail.host=smtp.163.com
#邮件的发送者
spring.mail.username=你的163邮箱
#邮箱申请的授权码
spring.mail.password=你的授权码

#邮件的编码格式
spring.mail.default-encoding=UTF-8
#邮件服务器连接超时
spring.mail.properties.mail.smtp.connectiontimeout=10000
#邮件接收超时
spring.mail.properties.mail.smtp.timeout=20000
#邮件发送超时
spring.mail.properties.mail.smtp.writetimeout=10000

我上面是使用163邮箱发送,如果你想用QQ邮箱或者企业微信邮箱则类似如下配置:

QQ邮箱

##qq邮箱配置(开启POP3,设置客户端授权码)
##配置邮件发送的服务器
#spring.mail.host=smtp.qq.com
##邮件的发送者
#spring.mail.username=你的QQ@qq.com
##邮箱申请的授权码
#spring.mail.password=你的授权码

企业微信邮箱

##企业微信邮箱
##配置邮件发送的服务器
#spring.mail.host=smtp.exmail.qq.com
##邮件的发送者
#spring.mail.username=你的企业微信邮箱
##邮箱申请的授权码
#spring.mail.password=你的授权码
  • 上面的password不是邮箱登录密码,是开启POP3之后设置的客户端授权码
  • 默认端口2525,当我们使用465端口时,新增如下配置:
spring.mail.port=465
spring.mail.properties.mail.smtp.ssl.enable=true

四、测试

4.1、发送简单邮件

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class SimpleEmailTest {

    @Autowired
    private EmailService emailService;

    @Test
    public void sendSimpleEmail() {
        List<String> receiverList = new ArrayList<>();
        receiverList.add("zhanglian@wtsd.cn");
        Email email = new Email();
        email.setSender("wtsd_ywdl@163.com");
        email.setReceiverList(receiverList);
        email.setSubject("发送简单邮件测试(纯文本)");
        email.setContent("文章你都没有看完,好意思说有5年Java功力???");
        boolean b = emailService.sendSimpleEmail(email);
        log.info("发送结果:{}", b);
    }

}

4.2、发送复杂邮件

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class ComplexEmailTest {

    @Autowired
    private EmailService emailService;

    @Test
    public void sendComplexEmail() {
        List<String> receiverList = new ArrayList<>();
        receiverList.add("zhanglian@wtsd.cn");

        // 邮件对象
        Email email = new Email();
        email.setSender("wtsd_ywdl@163.com");
        email.setReceiverList(receiverList);
        email.setSubject("发送复杂邮件测试(带附件)");

        // 嵌入式资源
        Map<String, String> inlineMap = email.getInlineMap();
        inlineMap.put("CSDN1234", "C:\\myFile\\CSDN\\csdn.png");
        inlineMap.put("Alian1223", "C:\\myFile\\CSDN\\alian.png");
        email.setInlineMap(inlineMap);

        // 附件
        List<String> attachmentList = email.getAttachmentList();
        attachmentList.add("C:\\myFile\\CSDN\\csdn.png");
        attachmentList.add("C:\\myFile\\CSDN\\alian.png");
        email.setAttachmentList(attachmentList);

        // 设置模板数据
        Map<String, Object> data = new HashMap<>();
        data.put("title", "注册成功");
        data.put("website", "https://blog.csdn.net/Alian_1223");
        data.put("account", "alian");
        data.put("password", "Alian1234");
        boolean b = emailService.sendComplexEmail(email, "complex-email.ftl", data);
        log.info("发送结果:{}", b);
    }

}

4.3、效果图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/86274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高分子PEG:8Arm PEG-DBCO,八臂聚乙二醇环辛炔 MV1K 2K 3.4K 5K

【中文名称】八臂聚乙二醇环辛炔 【英文名称】 8Arm PEG-DBCO&#xff0c;DBCO PEG 8Arm 【结 构 式】 【CAS号】N/A 【分子量】1000&#xff0c;2000&#xff0c;3400&#xff0c;5000&#xff0c;10000&#xff0c;20000 【基团部分】DBCO 【纯度标准】95% 【包装规格】1g&…

【Lilishop商城】No3-8.模块详细设计,订单模块-2(订单)的详细设计

仅涉及后端&#xff0c;全部目录看顶部专栏&#xff0c;代码、文档、接口路径在&#xff1a; 【Lilishop商城】记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客 全篇会结合业务介绍重点设计逻辑&#xff0c;其中重点包括接口类、业务类&#xff0c;具体的结合源代…

ssm+Vue计算机毕业设计校园社团管理系统(程序+LW文档)

ssmVue计算机毕业设计校园社团管理系统&#xff08;程序LW文档&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技…

Android入门第46天-使用BroadCast来模拟异地登录事件发生后的主动退出另一个设备重登录

简介 随着对BroadCast的越来越深入&#xff0c;我们今天要实现一个稍微复杂一点的BroadCast。即我们常用来有时APP打开时如果多个设备同时登录一个帐号&#xff0c;而我们只允许一个设备登录一个帐号时&#xff0c;此时我们的APP会弹一个对话框如&#xff1a;您的账号在别处登…

结合面试详细分析 HashMap 源码

个人文档站点&#xff1a;小熊学Java 1、底层结构 相信大家都已经听过很多了&#xff0c;这里就不多阐述了&#xff0c;至于什么时候是数组&#xff0c;什么时候会变成链表&#xff0c;后续会讲解&#xff0c;别急&#xff01; JDK版本数据结构JDK1.7数组链表JDK1.8数组 &…

腾讯云数据万象:智能+存储双驱动,数倍提升内容生产效能

伴随数字经济市场稳步扩张&#xff0c; AI和富媒体融合的场景式体验、营销模式、分享渠道已经成为数字商业中不可或缺的部分。12月1日&#xff0c;在2022腾讯全球数字生态大会存储专场&#xff0c;腾讯云数据万象发布产品更新&#xff0c;与腾讯云对象存储COS共同打造智能存储生…

[附源码]Nodejs计算机毕业设计基于JAVA语言的国货美妆店管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

JavaScript-DOM操作表单

目录 表单事件 表单方法 操作表单 获取表单的值 表单内容html checkbox的获取办法 表单事件 注意&#xff1a;onsubmit,onreset只能给表单添加 表单.submit ;表单.onreset; form.onsubmitfunction(){alert(表单即将被提交);};form.onresetfunction(){alert(表单即将被重…

ChatGPT:竟然精通ENVI IDL、ArcGIS等软件!

目录 01 使用途径 02 使用 01 使用途径 我试了很多网站&#xff0c;包括注册登录、插件、镜像网站&#xff0c;微信机器人&#xff0c;QQ机器人&#xff0c;但是目前这些或多或少都由于OpenAI的限制无法正常使用。所以总的来说需要科学上网并且需要国外手机号&#xff0c;这有…

CCIE-重认证-300-410-补充题库-必须的哟

实验题 VRF router bgp 65000 bgp router-id x bgp log-neighbor-cha address-fa ipv4 vrf green red con neigh x remote-as 65000 neigh x act 重复red inter e0/0 ip vrf for red ip add x x 重复e0/1,for green inter e0/2.100 enc dot 100 ip vrf for red ip add x x …

无工具情况下linux数据库命(postgresql)令行建表操作文档

首先将帮助文档下的test.sql放在服务器的某个位置。sql文件如下图&#xff1a; /*Navicat Premium Data TransferSource Server : postgres-123Source Server Type : PostgreSQLSource Server Version : 100010Source Host : 192.168.3.123:5432Source C…

完全开源的代码生成器之code-generator

什么是code-generator code-generator是一个低代码平台, 可以解决90%单表增删改查工作量, 你可以通过自定义代码模板来生成适合自己的代码。 目前该系统主要针对的是语言是java, 数据源是mysql(其他数据库待测试)&#xff0c;数据源支持mysql, oracle, dm, PostgreSql等数据库…

[附源码]计算机毕业设计的在线作业批改系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

Revit 中注释族的应用详解及公共族库工具

一、Revit 中注释族的应用详解&#xff1a; 注释族是用来表示二维注释的族文件&#xff0c;它被广泛用于很多构件的二维视图表现。下面以一个实例来说明注释族的应用 1、注释族创建实例 用“公制常规注释.rft”族样板创建一个注释族&#xff0c;在“族类别和族参数”对话框中选…

视觉SLAM ch9

状态估计的概率解释&#xff1a;位姿x和路标y服从某种概率分布&#xff0c;目的是通过某些运动数据u&#xff08;比如惯性测量传感器IMU输入&#xff09;和观测数据z&#xff08;比如拍摄到的照片像素点的值&#xff09;来确定状态量x和y的分布。 一、关于卡尔曼滤波器和扩展卡…

ssm+Vue计算机毕业设计校园食堂订餐系统(程序+LW文档)

ssmVue计算机毕业设计校园食堂订餐系统&#xff08;程序LW文档&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技…

Vim解决问题的方式

目录1 认识 . 命令2 不要自我重复3 以退为进4 执行、重复、回退5 查找并手动替换1 认识 . 命令 . 命令让我们重复上次的修改&#xff0c;它是Vim中最为强大的多面手。我们来练习下&#xff0c;如何快速的在vim进行操作&#xff0c;由下图形&#xff1a; 转成如下图形&#x…

win10下CH340模块下载stc89c52程序

没想到读研究生了还有水课需要用上51单片机&#xff0c;本科的时候一直是用开发板烧录程序的&#xff0c;这次舍不得花钱买开发板只能瞎折腾了。 准备材料 1.ch340转接板&#xff0c;最普通的那种3~5块钱 2.买的是一个焊接好的小单片机系统 &#xff08;BB一句&#xff0c;这…

内皮细胞生长添加剂(ECGF/ECGS)丨艾美捷解决方案

内皮细胞生长添加剂&#xff08;ECGF/ECGS&#xff09;是一种内皮细胞体外培养不可缺少的补充物质&#xff0c;可以优化细胞的体外生长环境&#xff0c;促进内皮细胞的正常增殖和生长。ECGF/ECGS是一种无菌浓缩&#xff08;100X&#xff09;溶液&#xff0c;含有正常人内皮细胞…

仅5天注册用户超百万,爆火ChatGPT究竟是什么?

作者&#xff1a;qizailiu&#xff0c;腾讯 IEG 应用研究员&#xff0c;来自腾讯技术工程 OpenAI 近期发布聊天机器人模型 ChatGPT&#xff0c;迅速出圈全网。它以对话方式进行交互。以更贴近人的对话方式与使用者互动&#xff0c;可以回答问题、承认错误、挑战不正确的前提、拒…