环境说明: Centos7, Docker1.13.1
准备
本篇以qq邮件为例
邮箱配置
- 开启SMTP服务(Simple Mail Transfer Protocol 简单邮件传输协议)
- 获取授权码
依赖配置
- 核心依赖
<!--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);
}
}
查看邮件
详细功能
- 自定义邮件表单实体
@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测试
查看邮箱
详细过程,可参考源代码:https://gitee.com/beeworkshop/cloud-flow