SpringBoot整合(三)SpringBoot发送邮件

news2024/11/24 4:19:33

使用SpringBoot发送邮件

邮件发送其实是一个非常常见的需求,用户注册,找回密码等地方,都会用到,Spring Boot 中对于邮件发送,提供了相关的自动化配置类,使得邮件发送变得非常容易。

1、前置工作

目前国内大部分的邮件服务商都不允许直接使用用户名/密码的方式来在代码中发送邮件,都是要先申请授权码,这里以 QQ 邮箱为例,向大家演示授权码的申请流程:

首先我们需要先登录 QQ 邮箱网页版,点击上方的设置按钮:然后点击账户选项卡:在账户选项卡中找到开启POP3/SMTP选项,如下:

在这里插入图片描述

点击开启,开启相关功能,开启过程需要手机号码验证,按照步骤操作即可,不赘述。开启成功之后,即可获取一个授权码,将该号码保存好,一会使用。

2、引入依赖、配置邮箱基本信息

<!--集成发送邮件的功能-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

然后在yml配置文件中进行配置

spring:
  mail:
    host: smtp.qq.com # 设置邮箱主机
    port: 587 # SMTP 服务器的端口
    username: yyds@qq.com # 设置用户名
    password:  yyds # 设置密码,该处的密码是QQ邮箱开启SMTP的授权码而非QQ密码

mail:
  from: ${spring.mail.username}
  to: yyds@163.com

做完这些之后,Spring Boot 就会自动帮我们配置好邮件发送类,相关的配置在

org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration 类中,部分源码如下:

@Configuration
@ConditionalOnClass({ MimeMessage.class, MimeType.class, MailSender.class })
@ConditionalOnMissingBean(MailSender.class)
@Conditional(MailSenderCondition.class)
@EnableConfigurationProperties(MailProperties.class)
@Import({ MailSenderJndiConfiguration.class, MailSenderPropertiesConfiguration.class })
public class MailSenderAutoConfiguration {
    
}

可以看到,导入了另外一个配置 MailSenderPropertiesConfiguration 类,这个类中,提供了邮件发送相关的工具类,源码如下:

@Configuration
@ConditionalOnProperty(prefix = "spring.mail", name = "host")
class MailSenderPropertiesConfiguration {
        private final MailProperties properties;
        MailSenderPropertiesConfiguration(MailProperties properties) {
                this.properties = properties;
        }
        @Bean
        @ConditionalOnMissingBean
        public JavaMailSenderImpl mailSender() {
                JavaMailSenderImpl sender = new JavaMailSenderImpl();
                applyProperties(sender);
                return sender;
        }
}

可以看到,这里创建了一个 JavaMailSenderImpl 的实例, JavaMailSenderImplJavaMailSender 的一个实现,我们将使用 JavaMailSenderImpl 来完成邮件的发送工作。

3、Service层代码

自定义的MailProperties配置类,用于解析mail开头的配置属性

package com.yyds.domain;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix = "mail")
public class MailProperties {

    private String from;

    private String to;

}

service层

package com.yyds.service;

import freemarker.template.TemplateException;

import javax.mail.MessagingException;
import java.io.IOException;
import java.util.Map;

public interface MailService {

     void sendSimpleMail(String subject, String text) ;

     void sendHtmlMail(String subject, String text, Map<String, String> attachmentMap) throws MessagingException;

     void sendTemplateMail(String subject, Map<String, Object> params) throws MessagingException, IOException, TemplateException;
}

package com.yyds.service.impl;

import com.yyds.domain.MailProperties;
import com.yyds.service.MailService;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.IOException;
import java.util.Map;

@Service
public class MailServiceImpl implements MailService {

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private MailProperties myMailProperties;



    /**
     * 发送简单文本邮件
     */
    @Override
    public void sendSimpleMail(String subject, String text) {
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setFrom(myMailProperties.getFrom());
        mailMessage.setTo(myMailProperties.getTo());

        mailMessage.setSubject(subject);
        mailMessage.setText(text);

        javaMailSender.send(mailMessage);
    }

    /**
     * 发送带有链接和附件的复杂邮件
     */
    @Override
    public void sendHtmlMail(String subject, String text, Map<String, String> attachmentMap) throws MessagingException {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();

        //是否发送的邮件是富文本(附件,图片,html等)
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);

        messageHelper.setFrom(myMailProperties.getFrom());
        messageHelper.setTo(myMailProperties.getTo());

        messageHelper.setSubject(subject);
        messageHelper.setText(text, true);//重点,默认为false,显示原始html代码,无效果

        if(attachmentMap != null){
            attachmentMap.entrySet().stream().forEach(entrySet -> {
                try {
                    File file = new File(entrySet.getValue());
                    if(file.exists()){
                        messageHelper.addAttachment(entrySet.getKey(), new FileSystemResource(file));
                    }
                } catch (MessagingException e) {
                    e.printStackTrace();
                }
            });
        }

        javaMailSender.send(mimeMessage);
    }


    /**
     * 发送模版邮件
     */
    @Override
    public void sendTemplateMail(String subject, Map<String, Object> params) throws MessagingException, IOException, TemplateException {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();

        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);

        helper.setFrom(myMailProperties.getFrom());
        helper.setTo(myMailProperties.getTo());

        freemarker.template.Configuration configuration = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_19);
        TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), "/templates/");
        configuration.setTemplateLoader(templateLoader);
        Template template = configuration.getTemplate("mail.ftl");
        String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, params);


        helper.setSubject(subject);
        helper.setText(html, true);//重点,默认为false,显示原始html代码,无效果

        javaMailSender.send(mimeMessage);
    }
}

4、发送邮件

4.1 测试发送简单文本邮件

@SpringBootTest(classes = BootStartApplication.class)
public class MimeMailTest {

    @Autowired
    private MailService mailService;

    @Test
    public void sendMail() {
        mailService.sendSimpleMail("测试Springboot发送邮件", "发送邮件...");
    }
}

在这里插入图片描述

4.2 测试发送带有链接和附件的复杂邮件

package com.yyds;

import com.yyds.service.MailService;
import freemarker.template.TemplateException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.mail.MessagingException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@SpringBootTest(classes = BootStartApplication.class)
public class MimeMailTest {

    @Autowired
    private MailService mailService;


    @Test
    public void testMail() throws MessagingException {

        Map<String, String> attachmentMap = new HashMap<>();
        attachmentMap.put("附件", "D:\\D_ENL_MRO数据统计.xlsx");

        mailService.sendHtmlMail("测试Springboot发送带附件的邮件2", "欢迎进入<a href=\"http://www.baidu.com\">百度首页</a>", attachmentMap);

    }

}

在这里插入图片描述

4.3 测试发送发送模版邮件

首先需要引入 Freemarker 依赖:

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

然后在 resources/templates 目录下创建一个 mail.ftl 作为邮件发送模板:

在这里插入图片描述

<html>
    <body>
    <h3>你好, <span style="color: red;">${username}</span>, 这是一封模板邮件!</h3>
    </body>
</html>
package com.yyds;

import com.yyds.service.MailService;
import freemarker.template.TemplateException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.mail.MessagingException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@SpringBootTest(classes = BootStartApplication.class)
public class MimeMailTest {

    @Autowired
    private MailService mailService;



    @Test
    public void testFreemarkerMail() throws MessagingException, IOException, TemplateException {

        Map<String, Object> params = new HashMap<>();
        params.put("username", "Tom");

        mailService.sendTemplateMail("测试Springboot发送模版邮件", params);
    }

}

在这里插入图片描述

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

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

相关文章

[SSD固态硬盘技术 9] FTL详解

了解硬件特性有助于我们针对特性进行进一步的探索与优化。为了使闪存成为存储数据的友好介质&#xff0c;我们需要一种机制&#xff1a;将更新的信息写入新的空页&#xff0c;然后将 所有后续读取请求转移到其新地址确保新编程的页面均匀分布在所有可用闪存中&#xff0c;以便均…

【Python入门第五天】Python 变量

创建变量 变量是存放数据值的容器。 与其他编程语言不同&#xff0c;Python 没有声明变量的命令。 首次为其赋值时&#xff0c;才会创建变量。 实例 x 10 y "Bill" print(x) print(y)运行实例 变量不需要使用任何特定类型声明&#xff0c;甚至可以在设置后更改…

Jupyter 使用Anaconda 虚拟环境内核

Anaconda 虚拟环境中使用Jupyter Notebook 安装好Anaconda之后&#xff0c;进入Anaconda Prompt&#xff0c;创建虚拟环境&#xff0c;env_name是创建的环境的名字。 conda creat -n env_name python3.9等虚拟环境搭建好之后&#xff0c;激活环境。 conda activate env_name…

网络流与图(一)

线性规划问题是运筹学最基本的问题&#xff0c;我们已经学过不少的解决方法&#xff0c;今天继续学习针对线性规划问题的另一种高效算法——网络流问题&#xff08;network flow problem&#xff09;1网络流模型为了更好介绍该算法来龙去脉&#xff0c;与以往一样&#xff0c;从…

MongoDB 删除文档

MongoDB 删除文档 MongoDB remove() 、deleteMany()、deleteOne()函数是用来移除集合中的数据。 remove()删除文档 remove() 方法的基本语法格式如下所示&#xff1a; db.collection.remove(<query>,<justOne> ) 如果你的 MongoDB 是 2.6 版本以后的&#xff0c…

filter及backdrop-filter属性详解

filter属性详解 filter 属性定义了元素(通常是<img>)的可视效果(例如&#xff1a;模糊与饱和度)。 filter: none | blur() | brightness() | contrast() | drop-shadow() | grayscale() | hue-rotate() | invert() | opacity() | saturate() | sepia() | url();下面运用…

聚观早报 |字节开展类ChatGPT研究;特斯拉前AI负责人将加入OpenAI

今日要闻&#xff1a;字节开展类ChatGPT研究&#xff1b;丰田汽车第三财季净利润同比下降8.1% 特斯拉前AI负责人将加入OpenAI&#xff1b;快手&#xff1a;正在开展大规模语言模型研究&#xff1b;劳斯莱斯CEO称客户希望更多电动汽车 字节开展类ChatGPT研究 北京时间 2 月 9 日…

零代码做分析报表的bi软件才是好软件

有些数据分析软件对IT的依赖比较重&#xff0c;在制作报表的过程中需要用到SQL&#xff0c;这就导致了IT人员懂技术不懂业务&#xff0c;业务人员懂业务不懂技术&#xff0c;数据分析做来做去总是差点什么的局面。要是遇到了IT部门相对较弱的情况&#xff0c;还会加重IT负担&am…

字符串函数能有什么坏心思?

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;夏目的C语言宝藏 &#x1f4ac;总结&#xff1a;希望你看完之…

又发现一个ChatGPT国内镜像站,无次数限制也无广告

ChatGPT 美国OpenAI研发的聊天机器人程序&#xff0c;于2022年11月30日发布。ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过学习和理解人类的语言来进行对话&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;…

传统目标检测实战:Sift/ORB+Match

传统目标检测实战&#xff1a;Sift/ORBMatch 文章目录传统目标检测实战&#xff1a;Sift/ORBMatch1. 前言2. 先验知识3. 项目框架4. 工具函数&#xff08;utils.py&#xff09;5. 检测待测图像&#xff08;test_xxxx.py&#xff09;5.1 使用图像缩放金字塔&#xff08;test_PG.…

大数据技术架构(组件)31——Spark:Optimize--->JVM On Compute

2.1.9.4、Optimize--->JVM On Compute首要的一个问题就是GC,那么先来了解下其原理&#xff1a;1、内存管理其实就是对象的管理&#xff0c;包括对象的分配和释放&#xff0c;如果显式的释放对象&#xff0c;只要把该对象赋值为null&#xff0c;即该对象变为不可达.GC将负责回…

ISYSTEM调试实践9-winIDEA Analyzer功能2

上一篇文章介绍了如何启动Trace,并配置。本文简单介绍一下Analyzer的输出结果&#xff0c;具体每个窗口的内容。 1、程序溯源 Profiler Timeline介绍了函数在时间轴上的执行调用情况。鼠标左键可以设置具体时间点&#xff0c;CTRL 左键和CTRL 右键设置观测的时间窗口&#xf…

技术树基础——16排它平方数(Bigdecimal,int,string,数组的转换)

题目&#xff1a;03879 * 203879 41566646641这有什么神奇呢&#xff1f;仔细观察&#xff0c;203879 是个6位数&#xff0c;并且它的每个数位上的数字都是不同的&#xff0c;并且它平方后的所有数位上都不出现组成它自身的数字。具有这样特点的6位数还有一个&#xff0c;请你…

openFeign源码学习

openFeign这个框架要解决的问题是&#xff1a;通常在调用远程接口的时候&#xff0c;如果是http请求&#xff0c;需要我们通过restTemplate去拼接调用参数和连接&#xff0c;然后发起调用&#xff0c;openFeign帮我们把拼接参数的这个过程包装了起来&#xff0c;通过代理对象的…

[WUSTCTF2020]level1 题解

1.查壳 64bit elf 还有一个文本文件&#xff0c;打开 打开是一串数字 根据这个txt文件的名称Output&#xff0c;可以猜测&#xff0c;这个文件的内容可能是程序的输出 2.静态分析 找到main函数反汇编 v7 __readfsqword(0x28u); stream fopen("flag", "r…

二叉搜索树之AVL树

AVL树的概念二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年 发明了一种解决上…

PCCW-HKT Futurera NFT 作品集来袭!

欢迎来到 Futurera&#xff0c;未来的虚拟城市&#xff01; 凭借庞大的 web2 资源&#xff0c;在全球首创的虚拟 5G 移动网络技术的鼎力支持下&#xff0c;Futurera 正力争跨越元宇宙的边界。 NFT 系列介绍 为庆祝 The Sandbox 中 Futurera 体验的开放&#xff0c;我们发布了一…

LSTM已死,Transformer当立(LSTM is dead. Long Live Transformers! ):下

2017 年,Google 在论文 Attention is All you need 中提出了 Transformer 模型,其使用 Self-Attention 结构取代了在 NLP 任务中常用的 RNN 网络结构。而且实验也证明Transformer 在效果上已经完败传统的 RNN 网络。Transformer 的整体模型架构如下图所示。尽管它看起来还是很…

python网络爬虫—快速入门(理论+实战)(七)

系列文章目录 &#xff08;1&#xff09;python网络爬虫—快速入门&#xff08;理论实战&#xff09;&#xff08;一&#xff09; &#xff08;2&#xff09;python网络爬虫—快速入门&#xff08;理论实战&#xff09;&#xff08;二&#xff09; &#xff08;3&#xff09; p…