使用 Apache James Mime4J
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j-dom</artifactId>
</dependency>
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j-storage</artifactId>
</dependency>
public class EmailPreviewVo {
private Long id;
private String from;
private String cc;
private String to;
private String subject;
private String sentDate;
private String content;
private List<FileVo> attachments;
private String partnerId = null;
}
public static EmailPreviewVo parseToPreview(File file) throws MimeException, IOException {
EmailPreviewVo vo = new EmailPreviewVo();
String messageFileName = file.getAbsolutePath();
CustomContentHandler contentHandler = new CustomContentHandler();
parseEmail(messageFileName, contentHandler);
Email emailSrc = ((CustomContentHandler) contentHandler).getEmail();
EmailFacade email = new EmailFacade(emailSrc);
String html = email.getHtmlBody();
Document doc = Jsoup.parse(html);
List<FileVo> attachList = new ArrayList<>();
for(int i=0; i < email.getAttacheNames().size(); i++) {
Map<String, Object> map = new HashMap<String, Object>();
InputStream ins = email.getAttachementList().get(i).getIs();
String attachName = email.getAttacheNames().get(i);
File attachementFile = null;
if (Utils.existSuffix(attachName)) {
String suffix = Utils.getSuffix(attachName);
attachementFile = Utils.createTmpFile(suffix);
} else {
attachementFile = Utils.createTmpFileWithName(attachName);
}
org.apache.commons.io.FileUtils.copyInputStreamToFile(ins, attachementFile);
if (attachementFile != null) {
FileVo fileVo = new FileVo();
fileVo.setFileName(attachName);
fileVo.setFileLength(attachementFile.length());
fileVo.setFilePath(attachementFile.getAbsolutePath());
attachList.add(fileVo);
}
}
vo.setAttachments(attachList);
Elements imgList = doc.select("img");
if (imgList.size() > 0) {
imgList.forEach(new Consumer<Element>() {
@Override
public void accept(Element element) {
String src = element.attr("src");
if (src.indexOf("cid:") < 0) {
return;
}
String imgAttach = src.substring(4);
FileVo fileVo = null;
for (FileVo tmp : attachList) {
if (tmp.getFileName().equals(imgAttach)) {
fileVo = tmp;
break;
}
}
if (fileVo == null) {
return;
}
File attach = new File(fileVo.getFilePath());
String base64 = null;
InputStream in = null;
try {
in = new FileInputStream(attach);
byte[] bytes=new byte[(int)attach.length()];
in.read(bytes);
base64 = Base64.getEncoder().encodeToString(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (StringUtils.isNotBlank(base64)) {
String srcBase64 = "data:image/png;base64," + base64;
element.attr("src", srcBase64);
attachList.remove(fileVo);
}
}
});
}
Elements bodyList = doc.select("body");
if (bodyList.size() > 0) {
Element bodyEle = bodyList.first();
if (bodyEle.html().length() > 0) {
vo.setContent(bodyEle.html());
}
}
org.apache.james.mime4j.dom.Header header = emailSrc.getHeader();
List<Field> fields = header.getFields();
for (Field field : fields) {
if ("Date".equals(field.getName())) {
vo.setSentDate(decode(field.getBody()));
} else if ("From".equals(field.getName())) {
vo.setFrom(decode(field.getBody()));
} else if ("To".equals(field.getName())) {
vo.setTo(decode(field.getBody()));
} else if ("Cc".equals(field.getName())) {
vo.setCc(decode(field.getBody()));
} else if ("Subject".equals(field.getName())) {
vo.setSubject(decode(field.getBody()));
}
}
return vo;
}
private static void parseEmail(String messageFileName,
ContentHandler contentHandler) throws FileNotFoundException,
MimeException, IOException {
MimeConfig mime4jParserConfig = MimeConfig.DEFAULT;
BodyDescriptorBuilder bodyDescriptorBuilder = new DefaultBodyDescriptorBuilder();
MimeStreamParser mime4jParser = new MimeStreamParser(
mime4jParserConfig, DecodeMonitor.SILENT, bodyDescriptorBuilder);
mime4jParser.setContentDecoding(true);
mime4jParser.setContentHandler(contentHandler);
InputStream mailIn = new FileInputStream(new File(messageFileName));
mime4jParser.parse(mailIn);
}
public static String decode(String rawvalue) {
if (rawvalue == null || "".equals(rawvalue.trim())) {
return "無標題";
}
try {
if (!rawvalue.contains("=?")) {
return toChinese(rawvalue);
}
if (rawvalue.contains("gb2312")) {
rawvalue = rawvalue.replace("gb2312", "GBK");
} else if (rawvalue.contains("GB2312")) {
rawvalue = rawvalue.replace("GB2312", "GBK");
}
StringBuilder sb = new StringBuilder();
while (true) {
int codingStartIdx = rawvalue.indexOf("=?");
if (codingStartIdx == -1) {
sb.append(rawvalue);
break;
}
if (codingStartIdx != 0) {
sb.append(rawvalue.substring(0, codingStartIdx));
}
int codingEndIdx = rawvalue.indexOf("?", codingStartIdx + 2);
String coding = rawvalue.substring(codingStartIdx + 2, codingEndIdx);
String codingType = rawvalue.substring(codingEndIdx + 1, codingEndIdx + 2);
String code = "=?" + coding + "?" + codingType + "?";
int innerCodingIdx = rawvalue.indexOf(code, codingEndIdx + 2);
while (innerCodingIdx != -1) {
int lastCodingEndInx = rawvalue.indexOf("?=");
if (lastCodingEndInx < innerCodingIdx) {
String connection = rawvalue.substring(lastCodingEndInx, innerCodingIdx);
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(connection);
rawvalue = rawvalue.replace(connection, m.replaceAll(""));
}
if (!rawvalue.contains("=?=" + code)) {
rawvalue = rawvalue.replace("?=" + code, "");
}
innerCodingIdx = rawvalue.indexOf(code, innerCodingIdx + 2);
}
int segEnd = rawvalue.indexOf("?=", codingEndIdx + 3);
if ("q".equals(codingType.toLowerCase())) {
String codeSeg = rawvalue.substring(codingEndIdx + 3, segEnd);
sb.append(parseQ(coding, codeSeg));
} else {
sb.append(MimeUtility.decodeText(code + rawvalue.substring(
codingEndIdx + 3, segEnd) + "?="));
}
if (rawvalue.length() == segEnd + 2) {
break;
}
rawvalue = rawvalue.substring(segEnd + 2);
}
return Utils.trimilSpace(sb.toString());
} catch (Exception e) {
logger.warn("cannot decode subject." + rawvalue, e);
}
return rawvalue;
}