SpringBoot集成邮件服务的完整实现方案

 更新时间:2026年07月23日 09:15:52   作者:半夜修仙  
本文详细讲解如何在Spring Boot项目中快速集成邮件发送功能,包括依赖引入、邮箱配置、工具类封装以及结合RabbitMQ实现异步发送,帮助开发者提升注册等业务场景的响应速度,避免阻塞主流程,需要的朋友可以参考下

1.引入邮箱依赖

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

2.配置邮箱

spring:
  mail:
    host: smtp.qq.com
    username: 你的QQ邮箱@qq.com
    password: 你的授权码  #需要自己去邮箱内开启SMTP服务
    default-encoding: UTF-8
    port: 465
    protocol: smtp
    properties:
      mail:
        smtp:
          auth: true
          ssl:
            enable: true
          socketFactory:
            class: javax.net.ssl.SSLSocketFactory

3.测试发送一封简单的邮件:

@Autowired
JavaMailSender javaMailSender;

@Test
public void test() throws Exception {
    // 创建一个邮件消息
    MimeMessage message = javaMailSender.createMimeMessage();
    // 创建 MimeMessageHelper
    MimeMessageHelper helper = new MimeMessageHelper(message, false);
    // 发件人邮箱和名称
    helper.setFrom("747692844@qq.com", "springdoc");
    // 收件人邮箱
    helper.setTo("admin@springboot.io");
    // 邮件标题
    helper.setSubject("Hello");
    // 邮件正文,第二个参数表示是否是HTML正文
    helper.setText("Hello <strong> World</strong>! ", true);
    // 发送
    javaMailSender.send(message);
}

实际代码-前置条件:

1.将邮件发送功能封装在一个公共类里,方便其他地方调用

  • 依赖:工具类在 common → 所有子服务不用重复导 mail 依赖;
  • yml 配置:无论工具放哪,每个要发邮件的微服务都必须自己配 mail 配置
  • 调用:其他服务注入 MailUtil 直接调用,不用再写创建 MimeMessage 那套底层代码
package com.bite.common.utils;

import jakarta.mail.internet.MimeMessage;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

import java.util.Optional;

public class Mail {
    private JavaMailSender javaMailSender;
    private MailProperties mailProperties;

    public Mail(JavaMailSender javaMailSender, MailProperties mailProperties) {
        this.javaMailSender = javaMailSender;
        this.mailProperties = this.mailProperties;
    }

    public void send(String to, String subject, String content) throws Exception {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, false);
        //发件人名称
        String personal = Optional.ofNullable(mailProperties.getProperties().get("personal"))
                .orElse(mailProperties.getUsername());
        helper.setFrom(mailProperties.getUsername(), personal);
        helper.setTo(to);    //收件人
        helper.setSubject(subject);    //邮件主题
        helper.setText(content, true);

        javaMailSender.send(mimeMessage);
    }
}

2.写Spring 邮件配置类,哪个服务需要就写在哪个服务里,也可以提出来写在服务的公共类里

package com.bite.common.config;

import com.bite.common.utils.Mail;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;


@Configuration
public class MailConfig {
    @Bean
    @ConditionalOnProperty(prefix="spring.mail",name="username")
     //只有配置文件中存在spring.data.redis.host配置项时,
    // 才会把 Redis 工具类注册为 Bean 放入 Spring 容器;
    // 没配置该属性就不创建这个 Bean,防止未配置 Redis 时报错
    //如blog服务配置没有redis相关配置,所以该服务就不创建这个bean,而user服务则有这个redis配置,则创建这个Bean
    


public Mail mail(JavaMailSender javaMailSender, MailProperties mailProperties) {
        return new Mail(javaMailSender,mailProperties);

    }
}

例子展示:

某服务的注册业务(Service)代码:

@Override
    public Integer register(UserInfoRegisterRequest registerRequest) {
        //校验参数:
        checkUserInfo(registerRequest);
        //校验通过,才是用户注册,插入数据库
        UserInfo userInfo = BeanConvert.convertUserInfoByEncrypt(registerRequest);
        try{
            int result = userInfoMapper.insert(userInfo);
            if(result==1){
                //存储数据到redis中
                //若redis存储失败,会导致查询时查不到信息,那么就从数据库中去查询,所以此处的异常暂不处理
                redis.set(buildKey(userInfo.getUserName()), JsonUtil.toJson(userInfo),EXPIRE_TIME);

                //⭐注册成功主动推送用户数据到 RabbitMQ,交给消费者异步处理发邮件,不阻塞注册接口响应速度,这就是引入MQ的作用
                userInfo.setPassword("");
                rabbitTemplate.convertAndSend(Constants.USER_EXCHANGE_NAME,"",JsonUtil.toJson(userInfo));


                return userInfo.getId();
            }else{
                throw new BlogException("用户注册失败");
            }
        }catch (Exception e){
            log.error("用户注册失败,e:",e);
            throw new BlogException("用户注册失败");

        }

    }

通过这段代码主动推送用户数据到 RabbitMQ

(⭐)rabbitTemplate.convertAndSend(Constants.USER_EXCHANGE_NAME,"",JsonUtil.toJson(userInfo));

生产者

注册成功主动推送用户数据到 RabbitMQ,交给消费者异步处理发邮件,不阻塞注册接口响应速度

消费者

消费收到的用户数据并做出下一步操作,如:发送邮箱

package com.bite.user.listener;

import com.bite.common.constant.Constants;
import com.bite.common.utils.JsonUtil;
import com.bite.common.utils.Mail;
import com.bite.user.dataobject.UserInfo;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;


@Slf4j
@Component
public class UserQueueListener {
    //⭐
    @Autowired
    private Mail mail;
    
    //写法二(消费注解内直接声明交换机 / 队列 / 绑定,服务启动自动创建,无需额外配置类;缺点是 MQ 资源分散在各个监听类):
    @RabbitListener(bindings=@QueueBinding(
            value=@Queue(value=Constants.USER_QUEUE_NAME,durable="true"),
            exchange=@Exchange(value=Constants.USER_EXCHANGE_NAME,type= ExchangeTypes.FANOUT)
    ))
    public void handler(Message message, Channel channel) throws IOException {
        long deliveryTag=message.getMessageProperties().getDeliveryTag();
        try{
            String body = new String(message.getBody());
            log.info("收到用户信息,body:{}",body);
            //TODO 发送注册成功邮件
            UserInfo userInfo= JsonUtil.parseJson(body, UserInfo.class);
           //⭐发送邮箱
             mail.send(userInfo.getEmail(),"恭喜加入XM博客社区",buildContent(userInfo.getUserName()));
            


//确认
            channel.basicAck(deliveryTag,true);
        }catch(Exception e){
            //否定确认
            channel.basicNack(deliveryTag,true,true);
            log.error("邮件发送失败,e:",e);
        }
    }

//发送的邮箱内容
    private String buildContent(String userName){
        StringBuilder builder=new StringBuilder();
        builder.append("尊敬的").append(userName).append(",您好!").append("<br/>");
        builder.append("感谢您注册成为我们博客社区的一员!我们很高兴您加入我们的大家庭!<br/>");
        builder.append("您的注册信息如下:用户名: ").append(userName).append("<br/>");
        builder.append("为了您的账号安全,请妥善保管您的登录信息.如果使用过程中,遇到任何问题,欢迎联系我们的支持团队. XXXX@bXM.com <br/>");
        builder.append("再次感谢您的加入,我们期待看到您的精彩内容!<br/>")
                .append("最好的祝愿<br/>")
                .append("XM博客团队");

        return builder.toString();
    }
}

发送邮件前置条件:公共类里的:

①⭐把 Mail 工具类创建成Spring Bean,放进容器:

  • 这行代码把 Mail 工具类创建成Spring Bean,放进容器;
  • 自动注入 Spring 自带的邮件工具 JavaMailSender + 读取 yml 邮箱配置的 MailProperties
  • @ConditionalOnProperty:只有业务服务 yml 配置了spring.mail.username,才会创建 Mail 对象,没配邮箱就不生成,避免报错。
package com.bite.common.config;

import com.bite.common.utils.Mail;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;


@Configuration
public class MailConfig {
    @Bean
    @ConditionalOnProperty(prefix="spring.mail",name="username")
    public Mail mail(JavaMailSender javaMailSender, MailProperties mailProperties) {
        return new Mail(javaMailSender,mailProperties);

    }
}

②:⭐邮箱发送操作实现逻辑:

封装底层发邮件逻辑:创建邮件、设置发件人 / 收件人 / HTML 正文、调用发送 API。 提供对外暴露的方法:send(String to, String subject, String content)

package com.bite.common.utils;

import jakarta.mail.internet.MimeMessage;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

import java.util.Optional;


public class Mail {
    private JavaMailSender javaMailSender;
    private MailProperties mailProperties;

    public Mail(JavaMailSender javaMailSender, MailProperties mailProperties) {
        this.javaMailSender = javaMailSender;
        this.mailProperties = mailProperties;
    }

    public void send(String to, String subject, String content) throws Exception {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, false);
        //发件人名称
        String personal = Optional.ofNullable(mailProperties.getProperties().get("personal"))
                .orElse(mailProperties.getUsername());
        helper.setFrom(mailProperties.getUsername(), personal);
        helper.setTo(to);    //收件人
        helper.setSubject(subject);    //邮件主题
        helper.setText(content, true);

        javaMailSender.send(mimeMessage);
    }
}

三者关系:

  • 消费者类写 ;
@Autowired
private Mail mail;
  • Spring 会从容器中找到 Mailconfig注册好的 Mail Bean 注入进来;--②
  • 调用 mail.send(邮箱,标题,正文),本质就是执行工具类里封装好的邮件发送代码.--①

以上就是SpringBoot集成邮件服务的完整实现方案的详细内容,更多关于SpringBoot集成邮件服务的资料请关注脚本之家其它相关文章!

相关文章

  • Java8中的 Lambda表达式教程

    Java8中的 Lambda表达式教程

    这篇文章主要介绍了 Java8中的 Lambda表达式教程,需要的朋友可以参考下
    2017-02-02
  • Java使用Swagger接口框架方法详解

    Java使用Swagger接口框架方法详解

    这篇文章主要介绍了Java使用Swagger接口框架方法,Swagger是一个方便我们更好的编写API文档的框架,而且Swagger可以模拟http请求调用,感兴趣的同学可以参考下文
    2023-05-05
  • Spring Cloud Gateway 启动流程源码分析

    Spring Cloud Gateway 启动流程源码分析

    文章详细分析了Spring Cloud Gateway 4.1.0启动过程,从依赖引入、启动类配置到NettyServer的启动,解析了关键方法和类的调用链,并探讨了线程池的配置和潜在风险,感兴趣的朋友跟随小编一起看看吧
    2026-01-01
  • JAVA自定义注解使用指南

    JAVA自定义注解使用指南

    注解是一种特殊的接口,用于为Java代码提供元数据,它们不会直接影响代码的执行,但可以被编译器、开发工具或运行时环境读取和使用,本文给大家介绍JAVA自定义注解的相关知识,感兴趣的朋友一起看看吧
    2025-11-11
  • 基于Java中字符串内存位置详解

    基于Java中字符串内存位置详解

    下面小编就为大家带来一篇基于Java中字符串内存位置详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • Spring Boot高效数据聚合之道深入讲解

    Spring Boot高效数据聚合之道深入讲解

    这篇文章主要给大家介绍了关于Spring Boot高效数据聚合之道的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-06-06
  • Java IO流对象的序列化和反序列化实例详解

    Java IO流对象的序列化和反序列化实例详解

    这篇文章主要介绍了Java IO流对象的序列化和反序列化实例详解的相关资料,需要的朋友可以参考下
    2017-05-05
  • 设置Log4j2监控间隔的三种方法

    设置Log4j2监控间隔的三种方法

    在 Log4j2 中,可以通过在配置文件中设置 monitorInterval 属性来指定监控配置文件变化的时间间隔,这个属性告诉 Log4j2 每隔多少秒检查一次配置文件是否有变化,本文介绍了具体的设置方法和示例,需要的朋友可以参考下
    2025-04-04
  • java之使用stream对日期排序方式

    java之使用stream对日期排序方式

    这篇文章主要介绍了java之使用stream对日期排序方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • 简单注解实现集群同步锁(spring+redis+注解)

    简单注解实现集群同步锁(spring+redis+注解)

    本文主要介绍了简单注解实现集群同步锁的步骤与方法。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01

最新评论