环境说明: Centos7, Docker1.13.1

准备

本篇以qq邮件为例

邮箱配置

  • 开启SMTP服务(Simple Mail Transfer Protocol 简单邮件传输协议)
  • 获取授权码

SpringBoot整合RabbitMq实现邮件发送_spring

依赖配置

  • 核心依赖
<!--amqb 通信-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--java mail-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  • yml的自动配置,注意这里要使用手动ack
spring:
# rabbitmq
rabbitmq:
host: 120.79.27.209
username: root
password: [password]
virtual-host: /
listener:
simple:
acknowledge-mode: manual
# qq mail
mail:
host: smtp.qq.com
username: 691409320@qq.com
password: [授权码]
default-encoding: utf-8
port: 587
properties:
mail.smtp.auth: true
mail.smtp.connectiontimeout: 5000
mail.smtp.timeout: 5000
mail.smtp.writetimeout: 5000
mail.smtp.starttls.enabl: true
# thymeleaf
thymeleaf:
cache: false

功能开发
以下模拟一个场景,用户提交注册信息后,将消息提交给队列,让后队列将发送邮件通知给用户

邮件发送
简单示例

  • 发送一个简单的文本内容的邮件
@SpringBootTest
@RunWith(SpringRunner.class)
public class MailApplicationTests {

@Autowired
private MailProperties mailProperties;

@Autowired
private JavaMailSender mailSender;

@Test
public void sendSampleMail() {
// 简单邮件类
SimpleMailMessage mailMessage = new SimpleMailMessage();
// 寄件人,默认是配置的username
mailMessage.setFrom(mailProperties.getUsername());
// 收件人,支持多个收件人
mailMessage.setTo("2633357327@qq.com");
// 邮件主题
mailMessage.setSubject("Test simple mail");
// 邮件的文本信息
mailMessage.setText("Hello this is test mail from java");

// 发送邮件
mailSender.send(mailMessage);
}
}

查看邮件

SpringBoot整合RabbitMq实现邮件发送_spring_02


详细功能

  • 自定义邮件表单实体
@Data
@Accessors(chain = true)
public class MailForm {
// 寄件人
private String from;

// 收件人
private List<String> to;

// 主题
private String subject;

// 文本
private String text;

// 本地附件路径
private List<String> attachmentPath;

// 模板名
private String templateName;

// 模板变量
private Map<String,Object> contextVar;
}
  • 邮件发送服务接口
public interface MailService {
/**
* 发送简单邮件
* @param form
*/
void sendSimpleMail(MailForm form);

/**
* 发送html邮件
* @param form
*/
void sendHtmlMail(MailForm form);

/**
* 发送模板邮件
* @param form
*/
void sendTemplateMail(MailForm form);
}
  • 实现类
@Service
@Slf4j
public class MailServiceImpl implements MailService {

@Autowired
private JavaMailSender mailSender;

@Autowired
private MailProperties mailProperties;

@Autowired
private TemplateEngine templateEngine;

@Override
public void sendSimpleMail(MailForm form) {
try {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom(mailProperties.getUsername());
List<String> to = form.getTo();
String[] toUsers = form.getTo().toArray(new String[to.size()]);
mailMessage.setTo(toUsers);
mailMessage.setSubject(form.getSubject());
mailMessage.setText(form.getText());

mailSender.send(mailMessage);
} catch (Exception e) {
log.error("邮件发送失败", e.getMessage());
throw new CustomException(ResultCodeEnum.MAIL_SEND_FAILED);
}
}

@Override
public void sendHtmlMail(MailForm form) {
try {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
messageHelper.setFrom(mailProperties.getUsername());
List<String> to = form.getTo();
String[] toUsers = form.getTo().toArray(new String[to.size()]);
messageHelper.setTo(toUsers);
messageHelper.setSubject(form.getSubject());
messageHelper.setText(form.getText(), true);

// 本地附件
if (form.getAttachmentPath() != null) {
List<String> pathList = form.getAttachmentPath();
for (String attachmentPath : pathList) {
File file = new File(attachmentPath);
if (file.exists()) {
String fileName = file.getName();
FileSystemResource fsr = new FileSystemResource(file);
messageHelper.addAttachment(fileName, fsr);
}
}
}

mailSender.send(mimeMessage);
} catch (Exception e) {
log.error("邮件发送失败", e.getMessage());
throw new CustomException(ResultCodeEnum.MAIL_SEND_FAILED);
}
}

@Override
public void sendTemplateMail(MailForm form) {
try {
Context context = new Context();
context.setLocale(Locale.CHINA);
context.setVariables(form.getContextVar());
String templateMail = templateEngine.process(form.getTemplateName(), context);
form.setText(templateMail);
sendHtmlMail(form);
} catch (Exception e) {
log.error("邮件发送失败", e.getMessage());
throw new CustomException(ResultCodeEnum.MAIL_SEND_FAILED);
}
}
}

RabbitMq配置
如没有安装rabbitmq,可参考Docker安装RabbitMq

  • 配置队列
@Configuration
public class RabbitmqConfig {

/** 邮件 **/
@Bean
public Queue mailQueue() {
return new Queue(MAIL_REGISTER_QUEUE, true, false, false, null);
}

@Bean
public Exchange mailExchange() {
return new TopicExchange(MAIL_REGISTER_EXCHANGE, true, false, null);
}

@Bean
public Binding orderBinding() {
return new Binding(MAIL_REGISTER_QUEUE, Binding.DestinationType.QUEUE, MAIL_REGISTER_EXCHANGE,
MAIL_REGISTER_ROUTING_KEY, null);
}

/** json输出 **/
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
  • 注册功能控制器
@RestController
@RequestMapping("/api/v1/register")
public class RegisterController {

@Autowired
RabbitTemplate rabbitTemplate;

/**
* 模拟注册,测试消息队列和邮件发送
*/
@PostMapping
public R mockRegister(@RequestBody UserForm form) {
User user = new User();
BeanUtils.copyProperties(form,user);
user.setId(UUID.randomUUID().toString().replace("-","").toUpperCase());

// 邮件通知
rabbitTemplate.convertAndSend(MqConstant.MAIL_REGISTER_EXCHANGE,MqConstant.MAIL_REGISTER_ROUTING_KEY,form);

// TODO 其他操作

return R.ok().message("注册成功,注册信息将邮件通知");
}
}
  • 监听邮件
@Service
@Slf4j
public class MailListenerService {

@Autowired
private MailService mailService;

@RabbitListener(queues = MqConstant.MAIL_REGISTER_QUEUE)
public void sendRegisterMail(Message message, Channel channel, UserForm form) throws IOException {
log.info("为用户发送注册信息:[{}]", form.getUsername());

try {
MailForm mailForm = new MailForm();
Map<String, Object> userMap = new HashMap<>();
userMap.put("username", form.getUsername());
userMap.put("password", form.getPassword());
mailForm.setTo(Arrays.asList(form.getEmail())).setSubject("注册通知").setTemplateName("register")
.setContextVar(userMap);
mailService.sendTemplateMail(mailForm);

channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
log.info("邮件发送成功");
} catch (IOException e) {
log.error("邮件发送失败", e.getMessage());
// 回复消息处理失败,并重新入队
// channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
throw new CustomException(ResultCodeEnum.MAIL_SEND_FAILED);
}
}
}
  • 开启RabbitMq @EnableRabbit

测试

使用postman测试

SpringBoot整合RabbitMq实现邮件发送_邮件发送_03


查看邮箱

SpringBoot整合RabbitMq实现邮件发送_springboot_04


详细过程,可参考源代码:https://gitee.com/beeworkshop/cloud-flow