com.github.zj.dreamly.mail.util.EmailParsing Maven / Gradle / Ivy
package com.github.zj.dreamly.mail.util;
import com.alibaba.fastjson.JSON;
import com.github.zj.dreamly.mail.entity.MailItem;
import com.github.zj.dreamly.mail.entity.UniversalAttachment;
import com.github.zj.dreamly.mail.entity.UniversalMail;
import com.github.zj.dreamly.mail.entity.UniversalRecipient;
import com.github.zj.dreamly.mail.exception.MailCustomException;
import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPMessage;
import com.sun.mail.pop3.POP3Folder;
import com.sun.mail.pop3.POP3Message;
import com.vdurmont.emoji.EmojiParser;
import microsoft.exchange.webservices.data.core.PropertySet;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
import microsoft.exchange.webservices.data.core.service.folder.Folder;
import microsoft.exchange.webservices.data.core.service.item.EmailMessage;
import microsoft.exchange.webservices.data.core.service.item.Item;
import microsoft.exchange.webservices.data.core.service.schema.EmailMessageSchema;
import microsoft.exchange.webservices.data.core.service.schema.ItemSchema;
import microsoft.exchange.webservices.data.property.complex.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.mail.util.MimeMessageParser;
import javax.activation.DataSource;
import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
/**
* EmailParsing
*
* @author: 苍海之南
* @since: 2019-09-04 17:04
**/
@SuppressWarnings("all")
public class EmailParsing {
/**
* 导入方式
*/
private static final String IMPORT_FOLDER = "手动导入";
/**
* eml文件后缀
*/
private static final String EML_SUFFIX = ".eml";
/**
* 解析通用邮件内容
*
* @param mailItem mailItem
* @param targetDir 本地保存路径
* @throws MailCustomException 自定义邮件异常
*/
public static UniversalMail parseMail(MailItem mailItem, String targetDir) throws MailCustomException {
UniversalMail universalMail = null;
if (mailItem.getPop3Message() != null) {
POP3Message pop3Message = mailItem.getPop3Message();
universalMail = parseMimeMessage(pop3Message, targetDir);
if (universalMail.getHasAttachment()) {
List universalAttachments = parseAttachment(pop3Message,
targetDir + "/" + universalMail.getUid());
universalMail.setAttachments(universalAttachments);
}
String emlPath = saveMimiMessageAsLocalEml(pop3Message,
targetDir + "/" + universalMail.getUid());
universalMail.setEmlPath(emlPath);
} else if (mailItem.getImapMessage() != null) {
IMAPMessage imapMessage = mailItem.getImapMessage();
universalMail = parseMimeMessage(imapMessage, targetDir);
if (universalMail.getHasAttachment()) {
List universalAttachments = parseAttachment(imapMessage,
targetDir + "/" + universalMail.getUid());
universalMail.setAttachments(universalAttachments);
}
String emlPath = saveMimiMessageAsLocalEml(imapMessage,
targetDir + "/" + universalMail.getUid());
universalMail.setEmlPath(emlPath);
} else if (mailItem.getExchangeMessage() != null) {
universalMail = parseExchangeMail(mailItem.getExchangeMessage());
//解析附件
if (universalMail.getHasAttachment()) {
try {
EmailMessage exchangeMessage = mailItem.getExchangeMessage();
exchangeMessage.load(new PropertySet(EmailMessageSchema.MimeContent,
EmailMessageSchema.AllowedResponseActions, EmailMessageSchema.Attachments));
List attachments = parseAttachment(exchangeMessage.getAttachments(),
targetDir + "/" + universalMail.getUid());
universalMail.setAttachments(attachments);
} catch (Exception e) {
e.printStackTrace();
throw new MailCustomException(e.getMessage());
}
}
//保存到本地
String emlPath = saveExchangeMailAsLocalEml(mailItem.getExchangeMessage(),
targetDir + "/" + universalMail.getUid());
universalMail.setEmlPath(emlPath);
}
return universalMail;
}
/**
* 保存邮件到本地的eml中
*
* @param mimeMessage 消息体
* @param targetDir 本地保存路径
* @throws MailCustomException 自定义邮件异常
*/
public static String saveMimiMessageAsLocalEml(MimeMessage mimeMessage, String targetDir) throws MailCustomException {
try {
String subject = mimeMessage.getSubject();
subject = StringUtils.isEmpty(subject) ? "无主题" + System.currentTimeMillis() : subject;
File file = new File(targetDir.concat("/")
.concat(mimeMessage.getSession() == null ? RandomStringUtils.random(40, true, true) : DigestUtils.md5Hex(subject))
.concat(EML_SUFFIX));
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {
file.createNewFile();
mimeMessage.writeTo(new FileOutputStream(file));
}
return file.getAbsolutePath();
} catch (MessagingException | IOException e) {
e.printStackTrace();
throw new MailCustomException(e.getMessage());
}
}
/**
* 解析邮件附件
*
* @param mimeMessage 消息体
* @param targetDir 本地保存路径
* @throws MailCustomException 自定义邮件异常
*/
public static List parseAttachment(MimeMessage mimeMessage, String targetDir) throws MailCustomException {
try {
MimeMessageParser parser = new MimeMessageParser(mimeMessage).parse();
List list = new ArrayList<>();
File dir = new File(targetDir);
if (!dir.exists()) {
dir.mkdirs();
}
List attachmentList = parser.getAttachmentList();
Collection contentIds = parser.getContentIds();
Set cidFile = new HashSet<>();
for (String cid : contentIds) {
DataSource attachmentByCid = parser.findAttachmentByCid(cid);
File file = new File(targetDir + "/" + attachmentByCid.getName());
if (!file.exists()) {
file.createNewFile();
FileUtils.copyInputStreamToFile(attachmentByCid.getInputStream(), file);
}
UniversalAttachment universalAttachment = UniversalAttachment.builder()
.cid(cid)
.path(file.getAbsolutePath())
.name(attachmentByCid.getName())
.contentType(attachmentByCid.getContentType())
.build();
list.add(universalAttachment);
cidFile.add(attachmentByCid.getName());
}
for (DataSource dataSource :
attachmentList) {
if (cidFile.contains(dataSource.getName())) {
continue;
}
File file = new File(targetDir + "/" + dataSource.getName());
if (!file.exists()) {
file.createNewFile();
FileUtils.copyInputStreamToFile(dataSource.getInputStream(), file);
}
UniversalAttachment universalAttachment = UniversalAttachment.builder()
.cid(null)
.path(file.getAbsolutePath())
.name(dataSource.getName())
.contentType(dataSource.getContentType())
.build();
list.add(universalAttachment);
}
return list;
} catch (Exception e) {
e.printStackTrace();
throw new MailCustomException(e.getMessage());
}
}
/**
* 解析mime邮件
*
* @param mimeMessage 消息体
* @param targetDir 本地保存路径
* @throws MailCustomException 自定义邮件异常
*/
public static UniversalMail parseMimeMessage(MimeMessage mimeMessage, String targetDir) throws MailCustomException {
try {
MimeMessageParser parser = new MimeMessageParser(mimeMessage).parse();
javax.mail.Folder folder = mimeMessage.getFolder();
String uid;
//组装uid
if (mimeMessage instanceof IMAPMessage) {
uid = folder.getName() + ((IMAPFolder) folder).getUID(mimeMessage);
} else if (mimeMessage instanceof POP3Message) {
uid = ((POP3Folder) folder).getUID(mimeMessage);
} else {
uid = UUID.randomUUID().toString();
}
if (StringUtils.isEmpty(uid)) {
throw new MailCustomException("【MIME邮件解析】解析uid失败");
}
String subject = parser.getSubject();
String body = parser.hasHtmlContent() ? parser.getHtmlContent() : parser.getPlainContent();
UniversalMail universalMail = UniversalMail.builder()
.content(StringUtils.isEmpty(body) ? "" : EmojiParser.parseToAliases(body))
.uid(uid)
.receiver(getMimeMessageAddressJson(parser.getTo()))
.title(StringUtils.isEmpty(subject) ? "<无主题>" : EmojiParser.parseToAliases(subject))
.sendDate(mimeMessage.getSentDate())
.hasRead(mimeMessage.getFlags().equals(Flags.Flag.SEEN))
.hasAttachment(parser.hasAttachments())
.fromer(parser.getFrom())
.folder(folder != null ? folder.getName() : IMPORT_FOLDER)
.cc(getMimeMessageAddressJson(parser.getCc()))
.bcc(getMimeMessageAddressJson(parser.getBcc()))
.build();
return universalMail;
} catch (Exception e) {
e.printStackTrace();
throw new MailCustomException(e.getMessage());
}
}
/**
* 获取JSON格式的邮件地址
*
* @param address 地址
*/
public static String getMimeMessageAddressJson(List address) {
List recipients = new ArrayList<>();
for (Address value : address) {
InternetAddress internetAddress = (InternetAddress) value;
UniversalRecipient build = UniversalRecipient.builder()
.name(StringUtils.isNotEmpty(internetAddress.getPersonal()) ? EmojiParser.parseToAliases(internetAddress.getPersonal()) : internetAddress.getAddress())
.email(internetAddress.getAddress())
.build();
recipients.add(build);
}
return JSON.toJSONString(recipients);
}
/**
* 保存到本地,必须在解析完邮件之后再保存,不然会报错,加载的头不一样了
*
* @param exchangeMessage 消息体
* @param targetDir 路径
* @throws MailCustomException 自定义邮件异常
*/
public static String saveExchangeMailAsLocalEml(EmailMessage exchangeMessage, String targetDir) throws MailCustomException {
try {
File dir = new File(targetDir);
if (dir.exists()) {
dir.mkdirs();
}
exchangeMessage.load();
String subject = exchangeMessage.getSubject();
subject = StringUtils.isEmpty(subject) ? "<无主题>" + System.currentTimeMillis() : subject;
File eml = new File(targetDir.concat("/").concat(DigestUtils.md5Hex(subject).concat(EML_SUFFIX)));
exchangeMessage.load(
new PropertySet(
EmailMessageSchema.MimeContent
, EmailMessageSchema.AllowedResponseActions
)
);
if (!eml.exists()) {
File parentFile = eml.getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
eml.createNewFile();
byte[] content = exchangeMessage.getMimeContent().getContent();
FileUtils.writeByteArrayToFile(eml, content);
}
return eml.getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
throw new MailCustomException(e.getMessage());
}
}
/**
* 解析Exchange附件
*
* @param attachments 附件
* @param targetDir 保存路径
*/
public static List parseAttachment(AttachmentCollection attachments, String targetDir) {
List universalAttachments = new ArrayList<>();
List items = attachments.getItems();
File dir = new File(targetDir);
if (!dir.exists()) {
dir.mkdirs();
}
for (Attachment attachment :
items) {
try {
String path = targetDir + "/" + attachment.getName();
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
if (attachment instanceof FileAttachment) {
((FileAttachment) attachment).load(file.getAbsolutePath());
} else if (attachment instanceof ItemAttachment) {
ItemAttachment itemAttachment = (ItemAttachment) attachment;
itemAttachment.load(ItemSchema.MimeContent);
Item item = itemAttachment.getItem();
FileUtils.writeByteArrayToFile(file, item.getMimeContent().getContent());
}
}
universalAttachments.add(
UniversalAttachment.builder()
.cid(attachment.getContentId())
.contentType(attachment.getContentType())
.name(attachment.getName())
.path(path)
.build()
);
} catch (Exception e) {
e.printStackTrace();
}
}
return universalAttachments;
}
/**
* 解析exchange邮件
*
* @param message 消息
* @throws MailCustomException 自定义邮件异常
*/
public static UniversalMail parseExchangeMail(EmailMessage message) throws MailCustomException {
try {
message.load();
String subject = message.getSubject();
EmailAddress from = message.getFrom();
String body = message.getBody().toString();
Date dateTimeSent = null;
try {
dateTimeSent = message.getDateTimeSent();
} catch (ServiceLocalException e) {
e.printStackTrace();
}
UniversalMail.UniversalMailBuilder builder = UniversalMail.builder()
.bcc(getExchangeAddressJson(message.getBccRecipients()))
.cc(getExchangeAddressJson(message.getCcRecipients()))
.folder(Folder.bind(message.getService(), message.getParentFolderId()).getDisplayName())
.fromer(from == null ? "<无发件人>" : from.getAddress())
.hasAttachment(message.getHasAttachments())
.hasRead(message.getIsRead())
.sendDate(dateTimeSent)
//处理emoji
.title(StringUtils.isAnyEmpty(message.getSubject()) ? "<无主题>" : EmojiParser.parseToAliases(subject))
.receiver(getExchangeAddressJson(message.getToRecipients())).uid(message.getId().getUniqueId())
.content(StringUtils.isEmpty(body) ? "" : EmojiParser.parseToAliases(body));
UniversalMail universalMail = builder.build();
return universalMail;
} catch (Exception e) {
e.printStackTrace();
throw new MailCustomException(e.getMessage());
}
}
/**
* 解析exchange地址为键值对并转换成JSON字符串
*
* @param recipients exchange地址
*/
public static String getExchangeAddressJson(EmailAddressCollection recipients) {
List items = recipients.getItems();
List list = new ArrayList<>();
for (EmailAddress emailAddress :
items) {
list.add(
UniversalRecipient.builder()
.email(emailAddress.getAddress())
.name(StringUtils.isNotEmpty(emailAddress.getName()) ?
EmojiParser.parseToAliases(emailAddress.getName()) : emailAddress.getAddress())
.build()
);
}
return JSON.toJSONString(list);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy