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