Spring集成邮箱功能

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(邮箱,标题,正文),本质就是执行工具类里封装好的邮件发送代码.--①

相关推荐
曾阿伦1 小时前
Maven 构建工程化指南
java·maven
Esaka_Forever1 小时前
Prompting Techniques提示词工程核心知识梳理
人工智能·github
宠友信息1 小时前
从重复请求到订单同步看内容社区源码的处理思路
java·spring boot·redis·后端·mysql·spring
带刺的坐椅1 小时前
用 Solon TeamAgent 落地供应链异常管理与自动补货
java·ai·llm·agent·solon·供应链
潇凝子潇1 小时前
UnsupportedOperationException
java·前端·数据库
码农学院2 小时前
电子产品企业泉州网络推广如何精准触达目标采购商
开发语言·php
qq_33776320192 小时前
国际期货资管系统开发方案|内外盘交易平台源码授权与二次开发支持
java·c语言·开发语言·c++·c#
不定积分要+C_yyy2 小时前
Java关键字final三种用法、核心特性与高频易错点
java·开发语言
xexpertS4 小时前
队列积压治理:如何避免异步系统出现难以恢复的消息积压
java·开发语言