首先要获取邮箱对应的16位授权码,这是为了使用邮箱服务器,进入QQ邮箱,在设置 -> 账户里面找到下面的服务开关,打开任意一个,smtp表示发送
javax.mail
mail
1.4.5
import com.sun.mail.util.MailSSLSocketFactory;
import jodd.util.URLDecoder;
import org.springframework.web.multipart.MultipartFile;
import javax.activation.DataHandler;
import javax.mail.*;
import javax.mail.internet.*;
import javax.mail.util.ByteArrayDataSource;
import java.io.File;
import java.util.*;
/*
邮箱工具类
*/
public class MailUtils {
//邮箱服务器(可以理解为中转站),常见的如网网易的邮箱服务器 smtp.163.com ,QQ的是smtp.qq.com
//第一个值是协议,第二个值是哪个公司提供的邮箱
private static final String SERVER_URL[] = {
"smtp.qq.com"};
//协议类型,常用协议有三种 smtp imap pop3,其中imap pop3是表示接收,smtp是发送
private static final String PROTOCOL_TYPE[] = {
"smtp", "imap", "pop3"};
//是否开启授权
private static final String AUTHOEIZATION = "true";
//是否开启SSL加密
private static final String SSL = "true";
//发送邮件的邮箱账号,可修改
public static String MAIL_ACCOUNT = "[email protected]";
//邮箱账号对应的协议16位授权码,可修改,必须和发邮件的账户一致
public static String MAIL_AUTHOEIZATION_CODE = "aaaaaaa";
//邮件文本类容格式(text/html是由游览器自己解析,可以解析富文本,text/plain是表示直接就是纯文字,不需要解析)
private static final String[] TABLE = {
"TEXT/HTML;charset=UTF-8", "TEXT/PLAIN;charset=UTF-8"};
//全局主体引用
private static MimeMultipart mimeMultipart;
//消息体全局引用
private static MimeBodyPart mimeBodyPart;
public static void main(String[] args) {
List<String> strings=new ArrayList<>();
strings.add("a");
List list=strings;
list.forEach(data -> System.out.println(data));
//根据路径拿附件
String[] stringUrls = {
"D:\\a.txt", "D:\\b.xlsx"};
//根据文件流实体拿附件
File[] files = {
new File("D:\\c.jpg")};
//调用邮件发送方法
System.out.println(getMail(MAIL_ACCOUNT, "测试", "胖!", stringUrls, files));
}
/**
* 发送邮寄
*
* @param receiveMail 收件人邮箱账号
* @param title 邮件标题
* @param content 邮件内容,TEXT/HTML格式下可以是富文本
* @param objects 附件,数组类型参数,String[]数组表示路径传附件,File[]表示file实例传附件,MultipartFile[]表示multipartFile实例传附件
* @return
*/
public static synchronized boolean getMail(String receiveMail, String title, String content, Object[]... objects) {
try {
//1.创建一个配置文件并保存,设置协议服务器地址,协议类型,是否授权
Properties properties = new Properties();
properties.setProperty("mail.host", SERVER_URL[0]);
properties.setProperty("mail.transport.protocol", PROTOCOL_TYPE[0]);
properties.setProperty("mail.smtp.auth", AUTHOEIZATION);
//2.QQ存在一个特性设置SSL加密
MailSSLSocketFactory ssl = new MailSSLSocketFactory();
ssl.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", SSL);
properties.put("mail.smtp.ssl.socketFactory", ssl);
//3.创建一个邮箱的session对象,要放入发送邮件的邮箱账号和协议授权嘛
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(MAIL_ACCOUNT, MAIL_AUTHOEIZATION_CODE);
}
});
//4.开启debug模式,就是开启每一步的操作打印
session.setDebug(true);
//5.获取连接对象
Transport transport = session.getTransport();
//6.连接邮箱对应服务器,发送是 smtp 协议服务器
transport.connect(SERVER_URL[0], MAIL_ACCOUNT, MAIL_AUTHOEIZATION_CODE);
//7.创建邮件对象
MimeMessage mimeMessage = new MimeMessage(session);
//8.邮件发送人账号
mimeMessage.setFrom(new InternetAddress(MAIL_ACCOUNT));
//9.邮件接收人账号
mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(receiveMail));
//10.邮件标题
mimeMessage.setSubject(title);
//11.构建邮件主体
mimeMessage.setContent(addMimeMultipart(content, objects));
//12.发送邮件
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
//13.关闭连接
transport.close();
} catch (Exception e) {
System.out.println(e.getMessage());
return false;
}
return true;
}
/**
* 构建邮件主体(包括内容,附件(一切文件),富文本等)
*
* @param content 文本内容,在TEXT/HTML格式下可以是富文本
* @param objects 附件,富文本图片
* @return
* @throws MessagingException
*/
private static synchronized MimeMultipart addMimeMultipart(String content, Object[] objects) throws MessagingException {
//得到主体实例
mimeMultipart = new MimeMultipart();
//处理富文本图片标签等类容,根据img标签分组,然后循环处理
String[] contentImgs = content.split(");
StringBuilder stringBuilder = new StringBuilder("");
for (String img : contentImgs) {
//判断当前内容里面是否有img的src属性
if (img.indexOf(" src='") != -1) {
//把img拼接回去
img = " + img;
//判断是否有以下几种格式
int index = 0;
Map<String, Integer> map = new HashMap<>();
map.put("jpg", img.indexOf(".jpg'/>"));
map.put("png", img.indexOf(".png'/>"));
map.put("pdf", img.indexOf(".pdf'/>"));
map.put("jpeg", img.indexOf(".jpeg'/>"));
for (String s : map.keySet()) {
int size = map.get(s);
if (size != -1) {
index = s.equals("jpeg") ? size + 8 : size + 7;
}
}
//如果找到了对应的格式图片或者表情,则生成一个新的名称,替换掉原来的路径
if (index != 0) {
//新名称,这是用来给邮箱寻找图片的别名
String name = String.valueOf(new Date().getTime());
//原来的路径
String url = img.substring(10, index - 3);
//新名称替换原来的路径
img = img.substring(0, 10) + "cid:" + name + img.substring(index, img.length());
//生成富文本对应的图片或者表情的消息体
mimeMultipart.addBodyPart(addRichUrl(url, name));
}
}
stringBuilder.append(img);
}
//把最终的文本内容放入消息体返回结果给主体
mimeMultipart.addBodyPart(addContent(stringBuilder.toString()));
//判断是否带了附件路径,附件文件流实体,富文本这些东西
if (objects.length > 0) {
for (Object object : objects) {
//判断是否是附件路径数组,是则循环放入附件消息体
if (object instanceof String[]) {
String[] stringUrls = (String[]) object;
for (String s : stringUrls) {
mimeMultipart.addBodyPart(addAccessoryUrl(s));
}
}
//判断是否是附件文件流File数组,是则循环放入附件消息体
if (object instanceof File[]) {
File[] files = (File[]) object;
for (File file : files) {
mimeMultipart.addBodyPart(addAccessoryFile(file));
}
}
//判断是否带了附件文件流MultipartFile数组,是则循环放入附件消息体
if (object instanceof MultipartFile[]) {
MultipartFile[] multipartFiles = (MultipartFile[]) object;
for (MultipartFile multipartFile : multipartFiles) {
mimeMultipart.addBodyPart(addAccessoryMultipartFile(multipartFile));
}
}
}
}
return mimeMultipart;
}
/**
* 构建纯文本消息体
*
* @param content 文本内容
* @return
*/
private static synchronized MimeBodyPart addContent(String content) {
try {
if (StringUtils.getNotNull(content)) {
return null;
}
mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setContent(content, TABLE[0]);
return mimeBodyPart;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 利用附件路径构建附件消息体
*
* @param fileUrl 附件路径
* @return
*/
private static synchronized MimeBodyPart addAccessoryUrl(String fileUrl) {
try {
mimeBodyPart = new MimeBodyPart();
//使用io读取文件流
File file = new File(fileUrl);
//把文件流放入消息体
mimeBodyPart.attachFile(file);
//解决中文乱码问题,放入当前文件名
mimeBodyPart.setFileName(MimeUtility.encodeText(file.getName()));
return mimeBodyPart;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 利用附件文件流File实体构建附件消息体
*
* @param file 附件文件流实体
* @return
*/
private static synchronized MimeBodyPart addAccessoryFile(File file) {
try {
mimeBodyPart = new MimeBodyPart();
//把文件流放入消息体
mimeBodyPart.attachFile(file);
//解决中文乱码问题,放入当前文件名
mimeBodyPart.setFileName(MimeUtility.encodeText(file.getName()));
return mimeBodyPart;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 利用附件文件流MultipartFile实体构建附件消息体
*
* @param multipartFile 附件文件流实体
* @return
*/
private static synchronized MimeBodyPart addAccessoryMultipartFile(MultipartFile multipartFile) {
try {
if (multipartFile != null) {
mimeBodyPart = new MimeBodyPart();
//拿到文件流
ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource(multipartFile.getInputStream(), multipartFile.getContentType());
//拿到文件名
byteArrayDataSource.setName(multipartFile.getOriginalFilename());
//把文件流放入消息体
mimeBodyPart.setDataHandler(new DataHandler(byteArrayDataSource));
//这里文件源名称由客户端上传 一般都是经过url编码的 我们先解码 再转成邮箱的编码
mimeBodyPart.setFileName(MimeUtility.encodeText(URLDecoder.decode(multipartFile.getOriginalFilename(), "utf-8")));
return mimeBodyPart;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 利用富文本图片或表情的路径构建富文本消息体
*
* @param fileUrl 富文本图片或表情路径
* @param name 富文本图片或表情别名,对应 标签里面的src属性值
* @return
*/
private static synchronized MimeBodyPart addRichUrl(String fileUrl, String name) {
try {
mimeBodyPart = new MimeBodyPart();
//使用io读取文件流
File file = new File(fileUrl);
//把文件流放入消息体
mimeBodyPart.attachFile(file);
//指定这个文件为富文本图片或表情
mimeBodyPart.setDescription(MimeBodyPart.INLINE);
//对应 标签里面的src值
mimeBodyPart.setContentID("<" + name + ">");
//解决中文乱码问题,放入当前文件名
mimeBodyPart.setFileName(MimeUtility.encodeText(file.getName()));
return mimeBodyPart;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}