Springboot整合实现邮件发送的原理详解

 更新时间:2021年06月19日 10:24:32   作者:小灰灰~~  
SpringBoot集成邮件服务非常简单,通过简单的学习即可快速掌握邮件业务类的核心逻辑和企业邮件的日常服务,本文给大家分享Springboot整合实现邮件发送的原理,一起看看吧

通常在实际项目中,也有其他很多地方会用到邮件发送,比如通过邮件注册账户/找回密码,通过邮件发送订阅信息等等。SpringBoot集成邮件服务非常简单,通过简单的学习即可快速掌握邮件业务类的核心逻辑和企业邮件的日常服务

开发前准备

首先注册发件邮箱并设置客户端授权码,这里以QQ 免费邮箱为例,其他的邮箱的配置也大同小异。

登录 QQ 邮箱,点击设置->账户,开启IMAP/SMTP服务,并生成授权码。

基础知识

电子邮件需要在邮件客户端和邮件服务器之间,以及两个邮件服务器之间进行邮件传递,那就必须要遵守一定的规则,这个规则就是邮件传输协议。下面我们分别简单介绍几种协议:

  • 什么是SMTP? SMTP全称为Simple Mail Transfer Protocol(简单邮件传输协议),它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP认证要求必须提供账号和密码才能登陆服务器,其设计目的在于避免用户受到垃圾邮件的侵扰。
  • 什么是IMAP? IMAP全称为Internet Message Access Protocol(互联网邮件访问协议),IMAP允许从邮件服务器上获取邮件的信息、下载邮件等。IMAP与POP类似,都是一种邮件获取协议。
  • 什么是POP3? POP3全称为Post Office Protocol 3(邮局协议),POP3支持客户端远程管理服务器端的邮件。POP3常用于“离线”邮件处理,即允许客户端下载服务器邮件,然后服务器上的邮件将会被删除。目前很多POP3的邮件服务器只提供下载邮件功能,服务器本身并不删除邮件,这种属于改进版的POP3协议。
  • IMAP和POP3协议有什么不同呢? 两者最大的区别在于,IMAP允许双向通信,即在客户端的操作会反馈到服务器上,例如在客户端收取邮件、标记已读等操作,服务器会跟着同步这些操作。而对于POP协议虽然也允许客户端下载服务器邮件,但是在客户端的操作并不会同步到服务器上面的,例如在客户端收取或标记已读邮件,服务器不会同步这些操作。

用户要在Internet上提供电子邮件功能,必须有专门的电子邮件服务器。这些邮件服务器就类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中。

邮件服务器就好像是互联网世界的邮局。按照功能划分,邮件服务器可以划分为两种类型:

SMTP邮件服务器:用户替用户发送邮件和接收外面发送给本地用户的邮件。 POP3/IMAP邮件服务器:用户帮助用户读取SMTP邮件服务器接收进来的邮件。

进阶知识

  • 什么是JavaMailSenderJavaMailSenderImplJavaMailSenderJavaMailSenderImpl 是Spring官方提供的集成邮件服务的接口和实现类,以简单高效的设计著称,目前是Java后端发送邮件和集成邮件服务的主流工具。
  • 如何通过JavaMailSenderImpl发送邮件? 非常简单,直接在业务类注入JavaMailSenderImpl并调用send方法发送邮件。其中简单邮件可以通过SimpleMailMessage来发送邮件,而复杂的邮件(例如添加附件)可以借助MimeMessageHelper来构建MimeMessage发送邮件。例如:
@Autowired
    private JavaMailSenderImpl mailSender;
    @Override
    public void sendInlineAndAttachMail(String to, String subject, String content,  String filePath,String                       rscPath, String rscId) {
        logger.info("发送带图片邮件开始:{},{},{},{},{}", to, subject, content, rscPath, rscId);
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper;
        try {
            helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);
            FileSystemResource file = new FileSystemResource(new File(filePath));
            String fileName = file.getFilename();
            helper.addAttachment(fileName, file);
            FileSystemResource res = new FileSystemResource(new File(rscPath));
            helper.addInline(rscId, res);//重复使用添加多个图片
            mailSender.send(message);
            logger.info("发送带图片和附件邮件成功");
        } catch (MessagingException e) {
            logger.error("发送带图片和附件邮件失败", e);
        }
    }

为什么JavaMailSenderImpl 能够开箱即用 ? 所谓开箱即用其实就是基于官方内置的自动配置,翻看源码可知晓邮件自动配置类(MailSenderPropertiesConfiguration) 为上下文提供了邮件服务实例(JavaMailSenderImpl)。具体源码如下:

@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;
    }

其中MailProperties是关于邮件服务器的配置信息,具体源码如下:

@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties {
    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private String host;
    private Integer port;
    private String username;
    private String password;
    private String protocol = "smtp";
    private Charset defaultEncoding = DEFAULT_CHARSET;
    private Map<String, String> properties = new HashMap<>();
}

Spring Boot 集成邮件发送主要分为以下三步:

加入依赖

pom.xml依赖spring-boot-starter-mail模块:

<!--javax.mail 邮件发送-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

配置邮件

在配置文件 application.properties 中配置邮件的相关参数,其中指定了邮件的协议、端口以及邮件账户和授权码等。具体内容如下:

#邮件配置
#SMTP服务器地址
spring.mail.host=smtp.qq.com    
#登陆账号
spring.mail.username=2590742958@qq.com
#注意这里不是邮箱密码,而是SMTP授权密码
spring.mail.password=lvlpxkujplqbdh
spring.mail.default-encoding=UTF-8
#开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true
#以下项不用改动
spring.mail.properties.mail.smtp.starttls.enable: true
spring.mail.roperties.mail.smtp.starttls.required: true

编写邮件发送service,contorller类等。

public class MailServiceImpl implements MailService {
    private final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);
    //使用@Value注入application.properties中指定的用户名
    @Value("${spring.mail.username}")
    private String from;
​
    @Autowired
    //用于发送文件
    private JavaMailSender mailSender;
     @Override
    public void sendAttachmentMail(String to, String subject, String content, String filePath) {
​
        logger.info("发送带附件邮件开始:{},{},{},{}", to, subject, content, filePath);
        MimeMessage message = mailSender.createMimeMessage();
​
        MimeMessageHelper helper;
        try {
            helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);
            FileSystemResource file = new FileSystemResource(new File(filePath));
            String fileName = file.getFilename();
            helper.addAttachment(fileName, file);//添加附件,可多次调用该方法添加多个附件
            mailSender.send(message);
            logger.info("发送带附件邮件成功");
        } catch (MessagingException e) {
            logger.error("发送带附件邮件失败", e);
        }

在发送邮件的同时,我们可以自定义参数从而生成丰富多彩的邮件,如下

public interface MailService {
    /**
     * 发送普通文本邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     */
    void sendSimpleMail(String to, String subject, String content);
    /**
     * 发送HTML邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容(可以包含<html>等标签)
     */
    void sendHtmlMail(String to, String subject, String content);
    /**
     * 发送带附件的邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     * @param filePath 附件路径
     */
    void sendAttachmentMail(String to, String subject, String content, String filePath);
    /**
     * 发送带图片的邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 文本
     * @param rscPath 图片路径
     * @param rscId 图片ID,用于在<img>标签中使用,从而显示图片
     */
    void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId);
    /**
     * 发送带图片的邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 文本
     * @param rscPath 图片路径
     * @param filePath 附件路径
     * @param rscId 图片ID,用于在<img>标签中使用,从而显示图片
     */
    void sendInlineAndAttachMail(String to, String subject, String content,String filePath, String              rscPath, String rscId);
}

测试邮件发送

编写控制器层,这里使用的是Thymeleaf模板邮件,是常见的模板邮件,比如说我们注册账户,登录认证所收到的邮件即为模板邮件,特点就是内容不变,只是一些特点信息比如说验证码、认证链接等是动态变化的。在模板页面中,id是动态变化的,需要我们传参设置,其实就是传参后,将页面解析为HTML字符串,作为我们邮件发送的主体内容

@Controller
public class MailContorller {
​
    @Autowired
    private MailService mailService;
    @Autowired
    private TemplateEngine templateEngine;
    @Resource
    private UserService userService;
​
    //这一步是获取application.properties中设置的发件人邮箱地址
    @Value("${spring.mail.username}")
    private String Email;
​
    @RequestMapping("/sendTemplate")
    /**  指定模板发送邮件  */
    public String sendTemplate(@RequestParam("Email") String Email, Model model) {
        //具体的业务
        User usermail= userService.retrieve(Email);
        System.out.println(usermail);
        if (usermail !=null){
            //向Thymeleaf模板传值,并解析成字符串
            //通过Context构造模版中变量需要的值
            Context context = new Context();
            context.setVariable("id", "001");
            String emailContent = templateEngine.process("emailTemplate", context);
            mailService.sendHtmlMail(Email,"密码找回验证", emailContent);
            return "Login";
        }
        else if(StringUtils.isEmpty(Email)){
            model.addAttribute("yuoxiang","邮箱信息不能为空");
            return "Login";
        }
        else {
            model.addAttribute("yuoxiang","邮箱错误或者与绑定账号不一致");
            return "Login";
        }
    }

然后我们需要在template文件夹下创建emailTemplate.html,设计我们需求的模板样式

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>密码验证</title>
</head>
<body>
<span style="color:#5ed02b;font-weight:600;font-size: 18px">您好,欢迎您的查看,这是一封验证邮件,请根据下面系统找回的密码完成登录,感谢您的支持!</span><br>
</body>
</html>

调用发送复杂邮件方法后,根据获取动态输入的邮箱地址,成功后就可以在 QQ 邮箱中收到邮件:

总结:Springboot整合邮件发送的原理和实现

以上就是Springboot整合实现邮件发送的原理详解的详细内容,更多关于Springboot邮件发送的资料请关注脚本之家其它相关文章!

相关文章

  • 约定优于配置_动力节点Java学院整理

    约定优于配置_动力节点Java学院整理

    以前做项目,总是写Ant配置文件,满足于自己更灵活的配置,而没有去思考,这么做到底值不值得
    2017-08-08
  • JAVA中常用的设计模式:单例模式,工厂模式,观察者模式

    JAVA中常用的设计模式:单例模式,工厂模式,观察者模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
    2020-04-04
  • 使用Spring中的scope配置和@scope注解

    使用Spring中的scope配置和@scope注解

    这篇文章主要介绍了使用Spring中的scope配置和@scope注解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Spring Boot结合ECharts案例演示示例

    Spring Boot结合ECharts案例演示示例

    本文主要主要介绍了Spring Boot结合ECharts案例演示示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Java实现字符串和输入流的相互转换

    Java实现字符串和输入流的相互转换

    这篇文章主要介绍了Java实现字符串和输入流的相互转换方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • 详解Java异常处理中throw与throws关键字的用法区别

    详解Java异常处理中throw与throws关键字的用法区别

    这篇文章主要介绍了详解Java异常处理中throw与throws关键字的用法区别,这也是Java面试题目中的常客,需要的朋友可以参考下
    2015-11-11
  • springboot调用webservice-soap接口的实现

    springboot调用webservice-soap接口的实现

    接口协议目前广泛使用的有http协议和RPC协议和webservice,本文主要介绍了springboot调用webservice-soap接口的实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Java如何实现海量数据判重

    Java如何实现海量数据判重

    在海量数据如何确定一个值是否存在?这是一道非常经典的面试场景题,那怎么回答这个问题呢?下面小编就来和大家详细的聊一聊,感兴趣的可以一起学习一下
    2023-09-09
  • IDEA如何进行全局搜索图文教程

    IDEA如何进行全局搜索图文教程

    idea全称为IntelliJ IDEA,在业界被公认为最好用的Java开发工具之一,下面这篇文章主要给大家介绍了关于IDEA如何进行全局搜索的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • Java的Swing编程中使用SwingWorker线程模式及顶层容器

    Java的Swing编程中使用SwingWorker线程模式及顶层容器

    这篇文章主要介绍了在Java的Swing编程中使用SwingWorker线程模式及顶层容器的方法,适用于客户端图形化界面软件的开发,需要的朋友可以参考下
    2016-01-01

最新评论