SpingBoot使用JavaMail实现邮件的接收、发送
前言
最近项目需要集成mail,经过很长时间的摸索,也算是基本达成了项目中的要求了。
项目中主要是用到了 邮件发送,邮件接收
相关概念
IMAP
IMAP全称是Internet Mail Access Protocol(交互式邮件存取协议),与POP3一样都是一种邮件获取协议。它的主要作用是邮件客户端(例如iPhone、Foxmail)可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等。IMAP的功能是各处同步,即在网页、客户端、手持设备上对邮箱的操作,均多向同步。如果一封在网页中打开过的新邮件,在iPad上登录邮箱后,该邮件也是已读状态;一封邮件在iPhone上被彻底删除,在Foxmail登录邮箱后,将找不到该邮件。
SMTP
SMTP 的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器。
相关文档
https://javaee.github.io/javamail/docs/api/index.html
http://www.vue5.com/javamail_api/javamail_api_core_classes.html
导入依赖
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
</dependency>
邮件发送
public void sendMail(SendMailParam sendMailParam, List<MultipartFile> files, MailSetting mailSetting) throws Exception {
try {
System.setProperty("mail.mime.splitlongparameters", "false");
final JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setUsername(mailSetting.getUsername()); //用于发送邮件的邮箱账号
javaMailSender.setPassword(mailSetting.getPassword()); //用于发送邮件的邮箱密码
javaMailSender.setHost(mailSetting.getSendHost()); //发送邮件的主机
javaMailSender.setPort(mailSetting.getSendPort()); //发送邮件的端口
javaMailSender.setProtocol(mailSetting.getSendProtocol()); //发送邮件的协议,默认值是:smtp
javaMailSender.setDefaultEncoding(mailSetting.getSendProtocol()); //发送邮件的字符集,默认使用UTF-8
final Properties mailProperties = new Properties();
mailProperties.put("mail.smtp.auth", true);
mailProperties.put("mail.debug", true);
if (mailSetting.getSendEncryption().equals("STARTTLS")) {
mailProperties.put("mail.smtp.starttls.enable", true);
}
if (mailSetting.getSendEncryption().equals("SSL")) {
mailProperties.put("mail.smtp.ssl.enable", true);
}
javaMailSender.setJavaMailProperties(mailProperties);
final MimeMessage mimeMessage = getMimeMessage(sendMailParam, javaMailSender, files,mailSetting.getUsername());
javaMailSender.send(mimeMessage);
} catch (MessagingException e) {
System.out.println("メールの送信に失敗しました:"+e.getMessage());
}
}
private MimeMessage getMimeMessage(SendMailParam sendMailParam,
JavaMailSenderImpl javaMailSender, List<MultipartFile> files,String senderName) throws javax.mail.MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
mimeMessageHelper.setFrom(senderName);
mimeMessageHelper.setTo(sendMailParam.getTo());
mimeMessageHelper.setCc(sendMailParam.getCc());
mimeMessageHelper.setSubject(sendMailParam.getSubject());
mimeMessageHelper.setText(sendMailParam.getContent(), true);
try {
if(files != null){
for (MultipartFile file : files) {
String filename = file.getOriginalFilename();
mimeMessageHelper.addAttachment(filename, file);
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
return mimeMessage;
}
邮件接收
邮件接收 就是 获取收件夹(inbox)中的邮件
当然同样也可以 获取已发送的邮件
receiveMailParam
如果使用 @Data注解 需要导入 Lombok 包
MailSetting 主要就是 邮件配置的信息
@Data
public class ReceiveMailParam {
private String type;
private long mailUID;
private MailSetting mailSetting;
}
@Data
public class MailSetting extends NewBaseEntity {
private int msid;
private String username;
private String password;
private String sendHost;
private int sendPort;
private String sendProtocol;
private String receiveHost;
private int receivePort;
private String receiveProtocol;
private String receiveEncryption;
private String sendEncryption;
}
private Store imapConnection(ReceiveMailParam receiveMailParam) throws MessagingException {
Properties props = new Properties();
props.put("mail.imap.host", receiveMailParam.getMailSetting().getReceiveHost());
props.put("mail.imap.port", receiveMailParam.getMailSetting().getReceivePort());
props.put("mail.imap.auth", true);
if (receiveMailParam.getMailSetting().getReceiveEncryption().equals("STARTTLS")) {
props.put("mail.imap.starttls.enable", true);
}
if (receiveMailParam.getMailSetting().getReceiveEncryption().equals("SSL")) {
props.put("mail.imap.ssl.enable", true);
}
Session session = Session.getInstance(props);
HashMap IAM = new HashMap();
//带上IMAP ID信息,由key和value组成,例如name,version,vendor,support-email等。
IAM.put("name","myname");
IAM.put("version","1.0.0");
IAM.put("vendor","myclient");
IAM.put("support-email","testmail@test.com");
IMAPStore store = (IMAPStore) session.getStore("imap");
store.connect(receiveMailParam.getMailSetting().getUsername(), receiveMailParam.getMailSetting().getPassword());
store.id(IAM); //这个id信息也可以选择不要 这个主要是针对 网易邮箱的
return store;
}
public List<MailHistoryDto> receiveMail(ReceiveMailParam receiveMailParam) throws Exception {
Store store = imapConnection(receiveMailParam); //这一步就是 调用上面的方法 获取Store对象
String folderName = "";
if(receiveMailParam.getType().equals("inbox")){
folderName = "INBOX";
}else if (receiveMailParam.getType().equals("send")){
//获取 已发送邮件夹的名字
// 收件夹的名字是固定的 但是其他邮件夹名字是不同的 不同的邮箱 名字也会不同
Folder defaultFolder = store.getDefaultFolder();
List<Folder> allFolder = Arrays.asList(defaultFolder.list()); //获取所有的邮件夹
folderName = allFolder.get(2).getFullName();
}
IMAPFolder folder = (IMAPFolder) store.getFolder(folderName); //获取邮件夹
folder.open(Folder.READ_ONLY); //打开邮件夹 只读权限
Message[] messagess = folder.getMessages(); //获取邮件夹的所有邮件
//现在获取到是message 而邮件的内容是需要通过解析的
List<MailHistoryDto> mailHistoryDtoList = new ArrayList<>();
//解析所有的邮件
for (Message message : messagess) {
MailHistoryDto mailHistoryDto = new MailHistoryDto();
MimeMessage msg = (MimeMessage) message;
mailHistoryDto.setMailUID(folder.getUID(msg));
mailHistoryDto.setIsSeen(ParseMail.isSeen(msg));
mailHistoryDto.setFrom(ParseMail.getFrom(msg));
mailHistoryDto.setSubject(ParseMail.getSubject(msg));
mailHistoryDto.setFrom(ParseMail.getFrom(msg));
mailHistoryDto.setTo(ParseMail.getReceiveAddress(msg,Message.RecipientType.TO ));
mailHistoryDto.setCc(ParseMail.getReceiveAddress(msg,Message.RecipientType.CC ));
mailHistoryDto.setSendDate(ParseMail.getSentDate(msg,null));
mailHistoryDto.setContainAttachment(ParseMail.isContainAttachment(msg));
mailHistoryDto.setReplySign(ParseMail.isReplySign(msg));
mailHistoryDto.setPriority(ParseMail.getPriority(msg));
StringBuffer content = new StringBuffer(30);
ParseMail.getMailTextContent(msg,content);
mailHistoryDto.setContent(String.valueOf(content));
if(receiveMailParam.getType().equals("inbox")){
mailHistoryDto.setType("inbox");
}else if (receiveMailParam.getType().equals("send")){
mailHistoryDto.setType("send");
}
mailHistoryDtoList.add(mailHistoryDto);
}
if (folder != null){
folder.close(true);
}
if (store != null) {
store.close();
}
return mailHistoryDtoList;
解析邮件
ParseMail
package com.share.mailTemplate.service;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ParseMail {
/**
* 删除邮件
*
* @param messages 要解析的邮件列表
*/
public static void deleteMessage(Message... messages) throws MessagingException, IOException {
if (messages == null || messages.length < 1)
throw new MessagingException("未找到要解析的邮件!");
// 解析所有邮件
for (int i = 0, count = messages.length; i < count; i++) {
/**
* 邮件删除
*/
Message message = messages[i];
String subject = message.getSubject();
// set the DELETE flag to true
message.setFlag(Flags.Flag.DELETED, true);
System.out.println("Marked DELETE for message: " + subject);
}
}
/**
* 获得邮件主题
*
* @param msg 邮件内容
* @return 解码后的邮件主题
*/
public static String getSubject(MimeMessage msg) throws UnsupportedEncodingException, MessagingException {
return MimeUtility.decodeText(msg.getSubject());
}
/**
* 获得邮件发件人
*
* @param msg 邮件内容
* @return 姓名 <Email地址>
* @throws MessagingException
* @throws UnsupportedEncodingException
*/
public static String getFrom(MimeMessage msg) throws MessagingException, UnsupportedEncodingException {
String from = "";
Address[] froms = msg.getFrom();
if (froms.length < 1)
throw new MessagingException("没有发件人!");
InternetAddress address = (InternetAddress) froms[0];
String person = address.getPersonal();
if (person != null) {
person = MimeUtility.decodeText(person) + " ";
} else {
person = "";
}
from = person + "<" + address.getAddress() + ">";
return from;
}
/**
* 根据收件人类型,获取邮件收件人、抄送和密送地址。如果收件人类型为空,则获得所有的收件人
* <p>Message.RecipientType.TO 收件人</p>
* <p>Message.RecipientType.CC 抄送</p>
* <p>Message.RecipientType.BCC 密送</p>
*
* @param msg 邮件内容
* @param type 收件人类型
* @return 收件人1 <邮件地址1>, 收件人2 <邮件地址2>, ...
* @throws MessagingException
*/
public static String getReceiveAddress(MimeMessage msg, Message.RecipientType type) throws MessagingException {
StringBuffer receiveAddress = new StringBuffer();
Address[] addresss = null;
if (type == null) {
addresss = msg.getAllRecipients();
} else {
addresss = msg.getRecipients(type);
}
if (addresss == null || addresss.length < 1)
return null;
for (Address address : addresss) {
InternetAddress internetAddress = (InternetAddress) address;
receiveAddress.append(internetAddress.toUnicodeString()).append(",");
}
receiveAddress.deleteCharAt(receiveAddress.length() - 1); //删除最后一个逗号
return receiveAddress.toString();
}
/**
* 获得邮件发送时间
*
* @param msg 邮件内容
* @return yyyy年mm月dd日 星期X HH:mm
* @throws MessagingException
*/
public static String getSentDate(MimeMessage msg, String pattern) throws MessagingException {
Date receivedDate = msg.getSentDate();
if (receivedDate == null)
return "";
if (pattern == null || "".equals(pattern))
pattern = "yyyy/MM/dd HH:mm ";
return new SimpleDateFormat(pattern).format(receivedDate);
}
/**
* 判断邮件中是否包含附件
*
* @return 邮件中存在附件返回true,不存在返回false
* @throws MessagingException
* @throws IOException
*/
public static boolean isContainAttachment(Part part) throws MessagingException, IOException {
boolean flag = false;
if (part.isMimeType("multipart/*")) {
MimeMultipart multipart = (MimeMultipart) part.getContent();
int partCount = multipart.getCount();
for (int i = 0; i < partCount; i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
String disp = bodyPart.getDisposition();
if (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE))) {
flag = true;
} else if (bodyPart.isMimeType("multipart/*")) {
flag = isContainAttachment(bodyPart);
} else {
String contentType = bodyPart.getContentType();
if (contentType.indexOf("application") != -1) {
flag = true;
}
if (contentType.indexOf("name") != -1) {
flag = true;
}
}
if (flag) break;
}
} else if (part.isMimeType("message/rfc822")) {
flag = isContainAttachment((Part) part.getContent());
}
return flag;
}
/**
* 判断邮件是否已读
*
* @param msg 邮件内容
* @return 如果邮件已读返回true, 否则返回false
* @throws MessagingException
*/
public static boolean isSeen(MimeMessage msg) throws MessagingException {
return msg.getFlags().contains(Flags.Flag.SEEN);
}
/**
* 判断邮件是否需要阅读回执
*
* @param msg 邮件内容
* @return 需要回执返回true, 否则返回false
* @throws MessagingException
*/
public static boolean isReplySign(MimeMessage msg) throws MessagingException {
boolean replySign = false;
String[] headers = msg.getHeader("Disposition-Notification-To");
if (headers != null)
replySign = true;
return replySign;
}
/**
* 获得邮件的优先级
*
* @param msg 邮件内容
* @return 1(High):紧急 3:普通(Normal) 5:低(Low)
* @throws MessagingException
*/
public static String getPriority(MimeMessage msg) throws MessagingException {
String priority = "普通";
String[] headers = msg.getHeader("X-Priority");
if (headers != null) {
String headerPriority = headers[0];
if (headerPriority.indexOf("1") != -1 || headerPriority.indexOf("High") != -1)
priority = "紧急";
else if (headerPriority.indexOf("5") != -1 || headerPriority.indexOf("Low") != -1)
priority = "低";
else
priority = "普通";
}
return priority;
}
public static String getTextMultipart(Part part) throws Exception{
if(part.isMimeType("text/html")){
String content = (String) part.getContent();
return content;
}else if(part.isMimeType("text/plain")){
String content = (String) part.getContent();
return content;
}
return "";
}
/**
* 获得邮件文本内容
*
* @param part 邮件体
* @param content 存储邮件文本内容的字符串
* @throws MessagingException
* @throws IOException
*/
public static void getMailTextContent(Part part, StringBuffer content) throws MessagingException, IOException {
// 如果是文本类型的附件,通过getContent方法可以取到文本内容,但这不是我们需要的结果,所以在这里要做判断
boolean isContainTextAttach = part.getContentType().indexOf("name") > 0;
if (part.isMimeType("text/*") && !isContainTextAttach) {
content.append(part.getContent().toString());
} else if (part.isMimeType("message/rfc822")) {
getMailTextContent((Part) part.getContent(), content);
} else if (part.isMimeType("multipart/*")) {
Object mpart = part.getContent();
if (mpart instanceof Multipart) {
Multipart multipart = (Multipart) part.getContent();
int partCount = multipart.getCount();
for (int i = 0; i < partCount; i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
getMailTextContent(bodyPart, content);
}
}
}
}
}
结语
以上就是 javamail 发送 和 接收 的过程了 如有疑问也可评论留言