SpringBoot实现QQ邮箱发送功能
一. 前言
1、互联网发展到现在,相必大家都知道发送邮件应该是网站的必备功能之一:用户注册发送邮箱验证、忘记密码、监控提醒以及发送营销信息等。
Spring提供一个邮件框架: Spring Email
2、Spring Email抽象的核心是MailSender接口,MailSender的实现能够把Email发送给邮件服务器,由邮件服务器实现邮件发送的功能。
早期发送邮件是通过Java自带的JavaMail类来发送邮件的,不过需要自己封装消息体,后来Spring推出了JavaMailSender类大大简化了发送邮件的过程,JavaMailSender继承自MailSender,提供了更强大的邮件发送功能,可支持不同类型的邮件发送。再到现在的Spring Boot又对其进行封装从而出现了spring-boot-starter-mail,进一步优化和完善邮件发送功能。
3、 邮件协议
什么是SMTP?
SMTP全称为Simple Mail Transfer Protocol(简单邮件传输协议),它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP认证要求必须提供账号和密码才能登陆服务器,其设计目的在于避免用户受到垃圾邮件的侵扰。
什么是IMAP?
IMAP全称为Internet Message Access Protocol(互联网邮件访问协议),IMAP允许从邮件服务器上获取邮件的信息、下载邮件等。IMAP与POP类似,都是一种邮件获取协议。
什么是POP3?
POP3全称为Post Office Protocol 3(邮局协议),POP3支持客户端远程管理服务器端的邮件。POP3常用于“离线”邮件处理,即允许客户端下载服务器邮件,然后服务器上的邮件将会被删除。目前很多POP3的邮件服务器只提供下载邮件功能,服务器本身并不删除邮件,这种属于改进版的POP3协议。
4、进阶知识
什么是JavaMailSender和JavaMailSenderImpl?
javaMailSender和JavaMailSenderImpl是Spring官方提供的集成邮件服务的接口和实现类,以简单高效的设计著称,目前是Java后端发送邮件和集成邮件服务的主流工具。
如何通过JavaMailSenderImpl发送邮件?
非常简单,直接在业务类注入JavaMailSenderImpl并调用send方法发送邮件。其中简单邮件可以通过SimpleMailMessage来发送邮件,而复杂的邮件(例如添加附件)可以借助MimeMessageHelper来构建MimeMessage发送邮件。
二. SpringBoot集成邮箱
1.以文本形式发送邮件
1.1.准备工作
开通邮箱SMTP服务,这里以163为例:
开启后会发来一个授权码,你保存起来,之后这样就可以发送邮件了。
1.2.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- email依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
1.3.配置application.yml文件
spring:
# 邮件配置
mail:
# 邮件服务器地址
host: smtp.qq.com
# 你的邮箱地址
username: *****@qq.com
# 授权码
password: *****
# 编码格式
default-encoding: utf-8
# 协议
protocol: smtp
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
1.4.实体MailBean类
package com.xxxx.springbootemail.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class MailBean implements Serializable {
private static final long serialVersionUID = -2116367492649751914L;
private String recipient;//邮件接收人
private String subject; //邮件主题
private String content; //邮件内容
}
创建RespBean 类
package com.xxxx.springbootemail.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 公共返回对象
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RespBean {
private long code;
private String message;
private Object obj;
/**
* 成功返回结果
* @param message
* @return
*/
public static RespBean success(String message){
return new RespBean(200,message,null);
}
/**
* 成功返回结果
* @param message
* @param data
* @return
*/
public static RespBean success(String message,Object data){
return new RespBean(200,message,data);
}
/**
* 失败返回结果
* @param message
* @return
*/
public static RespBean error(String message){
return new RespBean(500,message,null);
}
/**
* 失败返回结果
* @param message
* @param data
* @return
*/
public static RespBean error(String message,Object data){
return new RespBean(500,message,data);
}
}
创建User类
package com.xxxx.springbootemail.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {
private static final long serialVersionUID = -2116367492649751914L;
//用户名
private String name;
//密码
private String password;
//邮箱
private String mailbox;
}
1.5.创建MailUtil类
package com.xxxx.springbootemail.utils;
import com.xxxx.springbootemail.pojo.MailBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;
@Component
public class MailUtil {
@Value("${spring.mail.username}")
private String MAIL_SENDER; //邮件发送者
@Autowired
private JavaMailSender javaMailSender;//注入QQ发送邮件的bean
private Logger logger = LoggerFactory.getLogger(MailUtil.class);
/**
* 发送文本邮件
*
* @param mailBean
*/
public void sendSimpleMail(MailBean mailBean) {
try {
SimpleMailMessage mailMessage= new SimpleMailMessage();
mailMessage.setFrom(MAIL_SENDER);//发送者
mailMessage.setTo(mailBean.getRecipient());//接收者
mailMessage.setSubject(mailBean.getSubject());//邮件标题
mailMessage.setText(mailBean.getContent());//邮件内容
javaMailSender.send(mailMessage);//发送邮箱
} catch (Exception e) {
logger.error("邮件发送失败", e.getMessage());
}
}
}
其中:
字段 | 内容 |
---|---|
from | 即为邮件发送者,一般设置在配置文件中 |
to | 邮件接收者,此参数可以为数组,同时发送多人 |
subject | 邮件主题 |
Text | 邮件内容 |
content | 邮件的主体 |
copyTo | 抄送人 |
1.6.编写Controller类
package com.xxxx.springbootemail.controller;
import com.xxxx.springbootemail.pojo.MailBean;
import com.xxxx.springbootemail.pojo.RespBean;
import com.xxxx.springbootemail.pojo.User;
import com.xxxx.springbootemail.utils.MailUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
@Controller
public class Mail {
@Autowired
private MailUtil mailUtil;
@PostMapping("/mails")
@ResponseBody
public RespBean doMail(User user){
System.out.println("数据: " + user);
if (user != null){
MailBean mailBean = new MailBean();
mailBean.setRecipient(user.getMailbox());//接收者
mailBean.setSubject("用户信息");//标题
//内容主体
mailBean.setContent("SpringBootMail发送一个简单格式的邮件,时间为:" + new Date());
mailUtil.sendSimpleMail(mailBean);
return RespBean.success("查询成功",user);
}
return RespBean.error("发送失败!");
}
}
1.7.编写html模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/mails" method="post">
<span>用户名:</span>
<input type="text" name="name">
<span>密码:</span>
<input type="password" name="password">
<span>邮箱:</span>
<input type="email" name="mailbox">
<input type="submit" value="提交">
</form>
</body>
</html>
1.8.测试
这里邮件就发送成功了!!!!!!
2. 以HTML形式发送邮件
与文本格式邮件代码对比,富文本HTML邮件发送使用MimeMessageHelper类,把setText()方法的消息文本设置为html,并将第二个参数设置为true,表示这是html的富文本。MimeMessageHelper支持发送复杂邮件模板,支持文本、附件、HTML、图片等。
2.1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2.2.创建email.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3 th:text="|尊敬的${username} :|"></h3><br />
<img src="http://gtms02.alicdn.com/tps/i2/T1YoblFq4cXXa94Hfd-32-32.png" /> 您有代金券即将到期,逾期失效,请尽早使用。<a th:href = "${url}" >点此查看</a>
<br />
</body>
</html>
2.3.编写MailUtil类
/**
* 发送HTML模板
* @param mailBean
*/
public void sendHTMLMail(MailBean mailBean) {
MimeMessage mimeMailMessage = null;
try {
mimeMailMessage = javaMailSender.createMimeMessage();
//true 表示需要创建一个multipart message
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
mimeMessageHelper.setFrom(MAIL_SENDER);//发送者
mimeMessageHelper.setTo(mailBean.getRecipient());//接受者
mimeMessageHelper.setSubject(mailBean.getSubject());//邮件标题
//这里的 true,你加了的话,它发送你HTML页面里面的内容
//不加的话,默认是 false,它发送整个HTML页面代码
mimeMessageHelper.setText(mailBean.getContent(), true);
//邮件抄送
javaMailSender.send(mimeMailMessage);//发送邮件
} catch (Exception e) {
logger.error("邮件发送失败", e.getMessage());
}
}
2.4.编写Controller类
@Autowired
private TemplateEngine templateEngine;
@PostMapping("/mails2")
@ResponseBody
public RespBean doMail2(User user){
System.out.println("数据: " + user);
//以HTML模板发送邮件
if (user != null){
//注意:Context 类是在org.thymeleaf.context.Context包下的。
Context context = new Context();
//html中填充动态属性值
context.setVariable("username", "码农用户");
context.setVariable("url", "https://www.aliyun.com/?utm_content=se_1000301881");
//注意:process第一个参数名称要和templates下的模板名称一致。要不然会报错
//org.thymeleaf.exceptions.TemplateInputException: Error resolving template [email]
String emailContent = templateEngine.process("email", context);
MailBean mailBean = new MailBean();
mailBean.setRecipient(user.getMailbox());
mailBean.setSubject("主题:这是模板邮件");
mailBean.setContent(emailContent);
mailUtil.sendHTMLMail(mailBean);
return RespBean.success("查询成功",user);
}
return RespBean.error("发送失败!");
}
2.5.测试
三. SpringBoot+RabbitMQ
利用Springboot集成邮箱,如果邮箱内容太大的话,发送消息会很慢,会阻挡程序继续运行下去,所以利用RabbitMQ的话,可以分开进行,发送邮件继续发,程序也可以继续往下运行。
3.1. 导入依赖
<!-- rabbitmq依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- email依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
3.2. 配置application.yml文件
server:
port: 8083
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/xadmin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
hikari:
# 连接池名
pool-name: DateHikariCP
# 最小空闲连接数
minimum-idle: 5
# 空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 180000
# 最大连接数,默认10
maximum-pool-size: 10
# 从连接池返回的连接的自动提交
auto-commit: true
# 连接最大存活时间,0表示永久存活,默认1800000(30分钟)
max-lifetime: 1800000
# 连接超时时间,默认30000(30秒)
connection-timeout: 30000
# 测试连接是否可用的查询语句
connection-test-query: SELECT 1
# 邮件配置
mail:
# 邮件服务器地址
host: smtp.qq.com
# 你的邮箱地址
username: *****@qq.com
# 授权码
password: *****
# 编码格式
default-encoding: utf-8
# 协议
protocol: smtp
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
# rabbitmq配置
rabbitmq:
# 服务器地址
host: *****
# 端口
port: 5672
# 用户名
username: admin
# 密码
password: admin
# 权限
virtual-host: /shop
# Mybatis-plus配置
mybatis-plus:
# 配置Mapper映射文件
mapper-locations: classpath*:/mapper/*Dao.xml
# 配置MyBatis数据返回类型别名(默认别名是类名)
type-aliases-package: com.zb.demo.entity
configuration:
# 自动驼峰命名
map-underscore-to-camel-case: false
# Mybatis SQL 打印(方法接口所在的包,不是Mapper.xml所在的包)
logging:
level:
cn.yeb.server.mapper: debug
3.3.配置RabbitMQ
3.3.1. 配置Config
package com.example.demo3.config;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
/**
* 创建一个队列
* @return
*/
@Bean
public Queue mailQueue() {
return new Queue("mq.email");//队列名称
}
}
3.3.2.配置MailReceiver
package com.example.demo3.utils;
import com.example.demo3.entity.TUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Date;
/**
* 消息接收者
*/
@Component
public class MailReceiver {
private static final Logger LOGGER = LoggerFactory.getLogger(MailReceiver.class);
@Autowired
private JavaMailSender javaMailSender;
@Autowired
private MailProperties mailProperties;
@Autowired
private TemplateEngine templateEngine;
@RabbitListener(queuesToDeclare = {@Queue("mq.email")})//获取队列名称
public void handler(TUser user){
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage);
try {
//发件人
helper.setFrom(mailProperties.getUsername());
//收件人
helper.setTo(user.getMailbox());
//主题
helper.setSubject("入职欢迎邮件");
//发送日期
helper.setSentDate(new Date());
//邮件内容
Context context = new Context();
context.setVariable("username", "码农用户");
context.setVariable("url", "https://www.aliyun.com/?utm_content=se_1000301881");
String mail = templateEngine.process("email", context);//跟模板名称要一样
helper.setText(mail,true);
//发送邮件
javaMailSender.send(mimeMessage);
} catch (MessagingException e) {
LOGGER.error("邮件发送失败========>{}",e.getMessage());
}
}
}
3.4.配置HTML模板
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3 th:text="|尊敬的${username} :|"></h3><br />
<img src="http://gtms02.alicdn.com/tps/i2/T1YoblFq4cXXa94Hfd-32-32.png" /> 您有代金券即将到期,逾期失效,请尽早使用。<a th:href = "${url}" >点此查看</a>
<br />
</body>
</html>
3.5.配置Controller
package com.example.demo3.controller;
import com.example.demo3.entity.RespBean;
import com.example.demo3.entity.TUser;
import com.example.demo3.service.TUserService;
import com.example.demo3.utils.MailUtil;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.thymeleaf.TemplateEngine;
import javax.annotation.Resource;
import java.util.Date;
/**
* (TUser)表控制层
*/
@RestController
@RequestMapping("/tUser")
public class TUserController {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostMapping("/mails")
public RespBean doMail(@RequestBody TUser user){
System.out.println("数据: " + user);
if (user != null){
rabbitTemplate.convertAndSend("mq.email",user);
return RespBean.success("查询成功",user);
}
return RespBean.error("发送失败!");
}
}
3.6.测试
测试完成!!!!