申请邮箱服务开通POP3/SMTP(以qq邮箱为例)
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
yml:
QQ邮箱:
spring:
mail:
host: smtp.qq.com #发送邮件服务器
username: xx@qq.com #QQ邮箱
password: xxxxxxxxxxx #客户端授权码
protocol: smtp #发送邮件协议
properties.mail.smtp.auth: true
properties.mail.smtp.port: 465 #端口号465或587
properties.mail.display.sendmail: Javen #可以任意
properties.mail.display.sendname: Spring Boot Guide Email #可以任意
properties.mail.smtp.starttls.enable: true
properties.mail.smtp.starttls.required: true
properties.mail.smtp.ssl.enable: true
default-encoding: utf-8
from: xx@qq.com #与上面的username保持一致,这个是发送邮件方
网易邮箱:
spring:
mail:
host: smtp.126.com
username: xx@126.com
password: xxxxxxxx
protocol: smtp
properties.mail.smtp.auth: true
properties.mail.smtp.port: 994 #465或者994
properties.mail.display.sendmail: Javen
properties.mail.display.sendname: Spring Boot Guide Email
properties.mail.smtp.starttls.enable: true
properties.mail.smtp.starttls.required: true
properties.mail.smtp.ssl.enable: true
default-encoding: utf-8
from: xx@126.com
service:
package com.inesa.email.service;
import javax.mail.MessagingException;
public interface IMailService {
/**
* 发送文本邮件
* @param to
* @param subject
* @param content
*/
public void sendSimpleMail(String to, String subject, String content);
public void sendSimpleMail(String to, String subject, String content, String... cc);
/**
* 发送HTML邮件
* @param to
* @param subject
* @param content
* @throws MessagingException
*/
public void sendHtmlMail(String to, String subject, String content) throws MessagingException;
public void sendHtmlMail(String to, String subject, String content, String... cc);
/**
* 发送带附件的邮件
* @param to
* @param subject
* @param content
* @param filePath
* @throws MessagingException
*/
public void sendAttachmentsMail(String to, String subject, String content, String filePath) throws MessagingException;
public void sendAttachmentsMail(String to, String subject, String content, String filePath, String... cc);
/**
* 发送正文中有静态资源的邮件
* @param to
* @param subject
* @param content
* @param rscPath
* @param rscId
* @throws MessagingException
*/
public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId) throws MessagingException;
public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId, String... cc);
}
impl:
package com.inesa.email.service.impl;
import com.inesa.email.service.IMailService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.UnsupportedEncodingException;
@Component
public class IMailServiceImpl implements IMailService {
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.from}")
private String from;
/**
* 发送文本邮件
*
* @param to
* @param subject
* @param content
*/
@SneakyThrows
@Override
public void sendSimpleMail(String to, String subject, String content) {
//设置自定义发件人昵称
//String nick = "";
String nick = javax.mail.internet.MimeUtility.encodeText("xxx");
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(nick + " <" + from + ">");
message.setTo(to);
message.setSubject(subject);
message.setText(content);
mailSender.send(message);
}
@Override
public void sendSimpleMail(String to, String subject, String content, String... cc) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(to);
message.setCc(cc);
message.setSubject(subject);
message.setText(content);
mailSender.send(message);
}
/**
* 发送HTML邮件
*
* @param to
* @param subject
* @param content
*/
@Override
public void sendHtmlMail(String to, String subject, String content) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
mailSender.send(message);
}
@Override
public void sendHtmlMail(String to, String subject, String content, String... cc) {
}
/**
* 发送带附件的邮件
*
* @param to
* @param subject
* @param content
* @param filePath
*/
public void sendAttachmentsMail(String to, String subject, String content, String filePath) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName, file);
mailSender.send(message);
}
@Override
public void sendAttachmentsMail(String to, String subject, String content, String filePath, String... cc) {
}
/**
* 发送正文中有静态资源的邮件
*
* @param to
* @param subject
* @param content
* @param rscPath
* @param rscId
*/
public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource res = new FileSystemResource(new File(rscPath));
helper.addInline(rscId, res);
mailSender.send(message);
}
@Override
public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId, String... cc) {
}
}
测试:
package com.inesa.email;
import com.inesa.email.service.IMailService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class TestEmail {
@Autowired
private IMailService iMailService;
// 文本
@Test
public void test01() {
iMailService.sendSimpleMail("XXXX@qq.com", "XXXX", "XXXX测试发送");
}
// html
@Test
@SneakyThrows
public void test02() {
String code = "1234";
String text = "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Title</title>\n" +
"</head>\n" +
"<body>\n" +
"<h2>" + "XXX欢迎你" + "</h2>\n" +
"<h3>您的验证码为:<span style='color: red'" + ">" +
code +
"</span> " + ",请在 5 分钟内进行验证</h3>\n" +
"</body>\n" +
"</html>";
iMailService.sendHtmlMail("XXXX@qq.com", "XXXX", text);
}
}
在下面案例中可自行修改为异步发送邮件(案例不是发邮件实例,可自行修改):
@EnableAsync在启动项添加注解
package com.inesa.multith.reading.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
public class AsyncConfiguration {
@Bean("doSomethingExecutor")
public Executor doSomethingExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数:线程池创建时候初始化的线程数
executor.setCorePoolSize(10);
// 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(20);
// 缓冲队列:用来缓冲执行任务的队列
executor.setQueueCapacity(500);
// 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
// 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
//executor.setThreadNamePrefix("do-something-"); Thread
executor.setThreadNamePrefix("Thread-");
// 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程)
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
executor.initialize();
return executor;
}
}
package com.inesa.multith.reading.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Slf4j
@Service
public class AsyncService {
// 指定使用beanname为doSomethingExecutor的线程池
@Async("doSomethingExecutor")
public String doSomething(String message) {
log.info("do something, message={}", message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error("do something error: ", e);
}
return message;
}
@Async("doSomethingExecutor")
public CompletableFuture<String> doSomething1(String message) throws InterruptedException {
log.info("do something1: {}", message);
Thread.sleep(100);
return CompletableFuture.completedFuture("do something1: " + message);
}
@Async("doSomethingExecutor")
public CompletableFuture<String> doSomething2(String message) throws InterruptedException {
log.info("do something2: {}", message);
Thread.sleep(1000);
return CompletableFuture.completedFuture("; do something2: " + message);
}
@Async("doSomethingExecutor")
public CompletableFuture<String> doSomething3(String message) throws InterruptedException {
log.info("do something3: {}", message);
Thread.sleep(1000);
return CompletableFuture.completedFuture("; do something3: " + message);
}
}
package com.inesa.multith.reading.controller;
import com.inesa.multith.reading.service.AsyncService;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.logging.SimpleFormatter;
@RestController
@RequestMapping(value="/async")
public class AsyncController {
@Autowired
private AsyncService asyncService;
@SneakyThrows
@GetMapping("/open/something")
@ApiOperation("异步无返回值")
public String something() {
int count = 100;
for (int i = 0; i < count; i++) {
asyncService.doSomething("index = " + i);
}
return "success";
}
@SneakyThrows
@ApiOperation("异步 有返回值")
@GetMapping("/open/somethings")
public String somethings() {
CompletableFuture<String> createOrder = null;
for (int i = 0; i < 100; i++) {
Thread.sleep(100);
createOrder = asyncService.doSomething1("create order"+i);
}
CompletableFuture<String> reduceAccount = asyncService.doSomething2("reduce account");
CompletableFuture<String> saveLog = asyncService.doSomething3("save log");
// 等待所有任务都执行完
CompletableFuture.allOf(createOrder, reduceAccount, saveLog).join();
// 获取每个任务的返回结果
String result = createOrder.get() + reduceAccount.get() + saveLog.get();
return result;
}
}