由于我有两个项目,每个项目都需要用到邮件,所以把邮件拆分出来做成了一个单独的邮件服务,也方便以后的项目直接调用。
也就是现在有三个服务,服务A接收其他服务发送的消息,这个消息中会包含三个基本的信息,邮件标题、邮件内容、接收者的邮件号。服务B、C发送包含这三个信息的消息到服务A中,服务A拿到信息后最终发送邮件。
一、安装RabbitMQ
我的系统是Linux(Deepin),Windows的就不演示了,只需要以下三条命令。
RabbitMq需要erlang语言的支持,在安装RabbitMq之前需要安装erlang。
apt-get install erlang-nox
接着安装RabbitMQ
apt-get install rabbitmq-server
如果需要Web端可视化操作界面,还需要配置Management Plugin插件。
rabbitmq-plugins enable rabbitmq_management
安装成功后输入地址http://127.0.0.1:15672/进行登录,默认账号密码都为guest。
账号和密码可以到Web控制台去添加,也可以用RabbitMq的命令添加(rabbitmqctl add_user 用户名 密码)。如果RabbitMq在云服务器上,除了要开放端口,还要开启远程访问功能,处于安全的考虑,guest这个默认的用户只能通过http://localhost:15672 来登录,其他的IP无法直接使用这个账号。
二、获取邮箱授权码
这里演示获取QQ邮箱的授权码,163大致也一样,不过经测试,发现在使用163发送大量邮件后,过段时间再次发送就会都被标为垃圾邮件,系统拒绝发送。这里可能是我内容的原因(恩…所有内容大致都一样,只是个别话不同),但使用QQ时只是偶尔发不出去。
登录QQ邮箱后,点击设置—账号。
然后开启POP3/SMTP服务,默认是关闭的。
点击下面生成授权码,在发送短信校验后会给你一串字符,要保存好。
三、Spring Boot配置邮箱和RabbitMq
首先添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
在配置application.properties。
spring.mail.username是你的邮箱号,spring.mail.password为上面生成的授权码。这里如果要用163,需要把host改成smtp.163.com。
spring.mail.host=smtp.qq.com
spring.mail.username=XXXXXXX@qq.com
spring.mail.password=上面生成的授权码
spring.mail.port=465
spring.mail.protocol=smtp
spring.mail.default-encoding=UTF-8
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.imap.ssl.socketFactory.fallback=false
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
RabbitMq配置,host为主机地址。最下面设置的消息接收确认模式,这里设置的手动确认。
spring.rabbitmq.host=ip地址
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.listener.simple.acknowledge-mode=manual
四、接收其他服务发送的消息
首先定义一个消息实体,其他服务自然也要发送这个实体到消息接受者上。
public class EmailInfo implements Serializable {
private static final long serialVersionUID=1L;
/**
* 消息标题
*/
private String title;
/**
* 消息内容
*/
private String msg;
/**
* 接收者的邮箱号列表
*/
private List<String> sendTo;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public List<String> getSendTo() {
return sendTo;
}
public void setSendTo(List<String> sendTo) {
this.sendTo = sendTo;
}
public EmailInfo(String title, String msg, List<String> sendTo) {
this.title = title;
this.msg = msg;
this.sendTo = sendTo;
}
public EmailInfo() {
}
@Override
public String toString() {
return "EmailInfo{" +
"title='" + title + '\'' +
", msg='" + msg + '\'' +
", sendTo='" + sendTo + '\'' +
'}';
}
}
下面是消息接收。@RabbitListener注解可以直接创建交换器、队列、路由建,并且绑定。当这个队列中有消息时,会直接到process方法中处理,至于交换器和队列等概念在以后的文章中介绍或者自行学习, 使用 @Payload 和 @Headers 注解可以拿到消息中 body和headers 信息,也可以使用@Header获取单个 Header 属性,channel.basicAck方法为手动确认接收消息。
@Component
public class EmailReceiver {
@Autowired
JavaMailSender javaMailSender;
@RabbitHandler
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = "email-queue",durable = "true"),
exchange = @Exchange(name = "email-exchange",durable = "true",type = "topic"),
key = "email.*"
))
public void process(@Payload EmailInfo emailInfo,
@Headers Map<String,Object> header, Channel channel) {
Long tag =(Long) header.get(AmqpHeaders.DELIVERY_TAG);
try {
sendEmail(emailInfo);
channel.basicAck(tag,false);
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendEmail(EmailInfo info){
try {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("邮箱号");
java.lang.String[] strings = info.getSendTo().toArray(new String[]{});
message.setTo(strings);
message.setSubject(info.getTitle());
message.setText(info.getMsg());
javaMailSender.send(message);
}catch (Exception e){
System.out.println("发送失败"+e.getMessage());
}
}
}
五、其他服务投递消息
在其他服务中同样需要添加依赖,并且在application.properties配置RabbitMq,可参考上面。
发送消息就比较简单了,如下。
@Autowired
private AmqpTemplate amqpTemplate;
public void sendMail(String title,String msg,List<String> info){
EmailInfo emailInfo = new EmailInfo(title, msg, info);
amqpTemplate.convertAndSend("email-exchange","email.send",emailInfo);
}
六、测试
@RestController
public class RabbitContriller {
@Autowired
private AmqpTemplate amqpTemplate;
public void sendMail(String title,String msg,List<String> info){
EmailInfo emailInfo = new EmailInfo(title, msg, info);
amqpTemplate.convertAndSend("email-exchange","email.send",emailInfo);
}
@GetMapping("sendMq")
public String send(){
String context = "简单消息发送";
EmailInfo emailInfo = new EmailInfo("标题", context, Arrays.asList("2606710413@qq.com"));
amqpTemplate.convertAndSend("email-exchange","email.send",emailInfo);
return "发送成功";
}
}
访问这个地址后,不出意外,会收到此邮件。