Spring集成邮箱功能
1.引入邮箱依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-mail/artifactId /dependency2.配置邮箱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.SSLSocketFactory3.测试发送一封简单的邮件:Autowired JavaMailSender javaMailSender; Test public void test() throws Exception { // 创建一个邮件消息 MimeMessage message javaMailSender.createMimeMessage(); // 创建 MimeMessageHelper MimeMessageHelper helper new MimeMessageHelper(message, false); // 发件人邮箱和名称 helper.setFrom(747692844qq.com, springdoc); // 收件人邮箱 helper.setTo(adminspringboot.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(prefixspring.mail,nameusername) //只有配置文件中存在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(result1){ //存储数据到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(bindingsQueueBinding( valueQueue(valueConstants.USER_QUEUE_NAME,durabletrue), exchangeExchange(valueConstants.USER_EXCHANGE_NAME,type ExchangeTypes.FANOUT) )) public void handler(Message message, Channel channel) throws IOException { long deliveryTagmessage.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 buildernew StringBuilder(); builder.append(尊敬的).append(userName).append(,您好!).append(br/); builder.append(感谢您注册成为我们博客社区的一员!我们很高兴您加入我们的大家庭!br/); builder.append(您的注册信息如下:用户名: ).append(userName).append(br/); builder.append(为了您的账号安全,请妥善保管您的登录信息.如果使用过程中遇到任何问题欢迎联系我们的支持团队. XXXXbXM.com br/); builder.append(再次感谢您的加入我们期待看到您的精彩内容br/) .append(最好的祝愿br/) .append(XM博客团队); return builder.toString(); } }发送邮件前置条件:公共类里的:①⭐把Mail工具类创建成Spring Bean放进容器:这行代码把Mail工具类创建成Spring Bean放进容器自动注入 Spring 自带的邮件工具JavaMailSender 读取 yml 邮箱配置的MailPropertiesConditionalOnProperty只有业务服务 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(prefixspring.mail,nameusername) 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(邮箱,标题,正文)本质就是执行工具类里封装好的邮件发送代码.--①