因为需要解析apache james的邮件内容 ,内容格式如下
Return-Path: <XXXX@163.com>
Delivered-To: ***@**
Received: from m13-61.163.com (EHLO m13-61.163.com) ([220.181.13.61])
by VM_0_5_centos (JAMES SMTP Server ) with ESMTP ID -1461210387
for <XXXX@lawback.net>;
Fri, 14 Dec 2018 15:35:46 +0800 (CST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com;
s=s110527; h=Date:From:Subject:MIME-Version:Message-ID; bh=LGN55
QdgU9XoPQCr+27/Z+IPGOdDWiYZ7swbWaIAMzM=; b=P3wXeY5gFeuR5YVOBMga4
OHrnfwD+rYOKLUpTuaupgr/d/JftXBkufTMp8tIloy1njIPwt4Vp7oiJHAGT1gSi
k48Fk7CP30e6E8pXk4+LUfVaOinunqbdGgVzkmtkZnZu4U4X/vhRIxNLICB8kTSu
khVfkoXrWroSS2Q6HHAwpQ=
Received: from XXXX$163.com ( [59.83.198.133] ) by
ajax-webmail-wmsvr61 (Coremail) ; Fri, 14 Dec 2018 15:35:45 +0800 (CST)
X-Originating-IP: [59.83.198.133]
Date: Fri, 14 Dec 2018 15:35:45 +0800 (CST)
From: 1 <hy1131468749@163.com>
To: "hanyu@lawback.net" <hanyu@lawback.net>
Subject: kjchjkch
X-Priority: 3
X-Mailer: Coremail Webmail Server Version SP_ntes V3.5 build
20160729(86883.8884) Copyright (c) 2002-2018 www.mailtech.cn 163com
X-CM-CTRLDATA: xShnzGZvb3Rlcl9odG09MTAwOjU2
Content-Type: multipart/mixed;
boundary="----=_Part_183728_654166346.1544772945612"
MIME-Version: 1.0
Message-ID: <4414f0b3.bd9f.167aba486cd.Coremail.hy1131468749@163.com>
X-Coremail-Locale: zh_CN
X-CM-TRANSID:PcGowACHOSlRXRNcmW4QAA--.464W
X-CM-SenderInfo: 1k1rijqruwmliuz6il2tof0z/1tbiDwUdOVUMJg-i4gACsc
X-Coremail-Antispam: 1U5529EdanIXcx71UUUUU7vcSsGvfC2KfnxnUU==
------=_Part_183728_654166346.1544772945612
Content-Type: multipart/alternative;
boundary="----=_Part_183730_484598546.1544772945613"
------=_Part_183730_484598546.1544772945613
Content-Type: text/plain; charset=GBK
Content-Transfer-Encoding: base64
c2tkaGFza2pkaDG72ODB1/fPsrPJuaYx
------=_Part_183730_484598546.1544772945613
Content-Type: text/html; charset=GBK
Content-Transfer-Encoding: base64
PGRpdiBzdHlsZT0ibGluZS1oZWlnaHQ6MS43O2NvbG9yOiMwMDAwMDA7Zm9udC1zaXplOjE0cHg7
Zm9udC1mYW1pbHk6QXJpYWwiPnNrZGhhc2tqZGgxu9jgwdf3z7KzybmmMTwvZGl2Pjxicj48YnI+
PHNwYW4gdGl0bGU9Im5ldGVhc2Vmb290ZXIiPjxwPiZuYnNwOzwvcD48L3NwYW4+
------=_Part_183730_484598546.1544772945613--
------=_Part_183728_654166346.1544772945612
Content-Type: text/plain; name="=?GBK?Q?=B2=E2=CA=D422.txt?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="=?GBK?Q?=B2=E2=CA=D422.txt?="
vM6088/Dv9W85Lu5yse087/Nu6e94r72DQo=
------=_Part_183728_654166346.1544772945612--
一个完成邮箱格式内容在apache jame里包括头信息和 内容信息
先从数据库取出这2个信息进行相加。
然后在pom文件需要加入以下jar:
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j-core</artifactId>
<version>${mime4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j-dom</artifactId>
<version>${mime4j.version}</version>
</dependency>
代码如下:
public class JamesUtil {
/**
* 获取邮件内容
* @param mailBoxId mailBoxId
* @param mailUid mailUid
* @return Map<String, Object>
*/
public static Map<String, Object> getMailContent(String mailBoxId,String mailUid){
if(StringUtils.isEmpty(mailBoxId) || StringUtils.isEmpty(mailUid)){
return null;
}
IJamesMailService jamesMailService = SpringContextUtils.getBean(IJamesMailService.class);
JamesMail jamesMail = jamesMailService.selectByBoxIdAndUid(mailBoxId, mailUid);
if(jamesMail == null){
return null;
}
Map<String,Object> resultMap = new HashMap<>();
ByteArrayInputStream inputStringStream = null;
try {
String head = new String(jamesMail.getHeaderBytes());
String content =new String(jamesMail.getMailBytes());
inputStringStream = new ByteArrayInputStream((head + content).getBytes());
//apache 提供的邮件mime格式解析
MimeTokenStream parser = new MimeTokenStream(MimeConfig.PERMISSIVE, new DefaultBodyDescriptorBuilder());
parser.parse(inputStringStream);
handle(parser, resultMap);
}catch (Exception e){
e.printStackTrace();
}finally {
if(inputStringStream != null) {
try {
inputStringStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return resultMap;
}
private static void handle(MimeTokenStream parser,Map<String,Object> resultMap) throws Exception {
for (EntityState state = parser.getState();
state != EntityState.T_END_OF_STREAM;
state = parser.next()) {
switch (state) {
//到了这个状态,会获取到之前的头信息,然后获取到流,根据之前的头信息对流进行处理
case T_BODY:
MaximalBodyDescriptor descriptor = (MaximalBodyDescriptor) parser.getBodyDescriptor();
LimitedInputStream line = (LimitedInputStream) parser.getInputStream();
StringBuilder sb = new StringBuilder();
byte[] buffer = new byte[1024 * 4];
int n ;
while ((n = line.read(buffer)) != -1) {
sb.append(new String(buffer, 0, n));
}
String fileName = descriptor.getContentDispositionFilename();
String transferEncoding = descriptor.getTransferEncoding();
//处理文件
if (!StringUtils.isEmpty(fileName)) {
//获取文件名称
String fileRealName = MimeUtility.decodeText(fileName);
System.out.println(fileRealName);
String path = "E:\\" + fileRealName;
FileOutputStream fileOutputStream = null;
try {
File file = new File(path);
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] bytes = base64Decoder.decodeBuffer(sb.toString());
fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(bytes);
fileOutputStream.flush();
resultMap.put("file",path);
}catch (Exception e){
e.printStackTrace();
}finally {
if(fileOutputStream != null) {
fileOutputStream.close();
}
}
} else {
//处理文本内容
String contentShow = sb.toString();
if (StringUtils.isNotEmpty(transferEncoding)) {
String charset = descriptor.getCharset();
if ("base64".equals(transferEncoding)) {
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] bytes = base64Decoder.decodeBuffer(sb.toString());
contentShow = new String(bytes, charset);
} else if ("quoted-printable".equals(transferEncoding)) {
contentShow = qpDecoding(sb.toString(), charset);
}
}
// System.out.println("内容:" + contentShow);
String subType = descriptor.getSubType();
if("html".equals(subType)){
resultMap.put("html",contentShow);
}else{
resultMap.put("text",contentShow);
}
}
break;
case T_FIELD:
break;
case T_END_MULTIPART:
break;
}
}
}
public static String qpEncodeing(String str,String charset) {
if(StringUtils.isEmpty(str)){
return "";
}
char[] encode = str.toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < encode.length; i++)
{
if ((encode[i] >= '!') && (encode[i] <= '~') && (encode[i] != '=')
&& (encode[i] != '\n'))
{
sb.append(encode[i]);
}
else if (encode[i] == '=')
{
sb.append("=3D");
}
else if (encode[i] == '\n')
{
sb.append("\n");
}
else
{
StringBuilder sbother = new StringBuilder();
sbother.append(encode[i]);
String ss = sbother.toString();
byte[] buf = null;
try
{
buf = ss.getBytes(charset);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
if(buf == null){
continue;
}
if (buf.length == 3)
{
for (int j = 0; j < 3; j++)
{
String s16 = String.valueOf(Integer.toHexString(buf[j]));
// 抽取中文字符16进制字节的后两位,也就是=E8等号后面的两位,
// 三个代表一个中文字符
char c16_6;
char c16_7;
if (s16.charAt(6) >= 97 && s16.charAt(6) <= 122)
{
c16_6 = (char) (s16.charAt(6) - 32);
}
else
{
c16_6 = s16.charAt(6);
}
if (s16.charAt(7) >= 97 && s16.charAt(7) <= 122)
{
c16_7 = (char) (s16.charAt(7) - 32);
}
else
{
c16_7 = s16.charAt(7);
}
sb.append("=" + c16_6 + c16_7);
}
}
}
}
return sb.toString();
}
public static String qpDecoding(String str,String charset)
{
if (str == null)
{
return "";
}
try
{
StringBuilder sb = new StringBuilder(str);
for (int i = 0; i < sb.length(); i++)
{
if (sb.charAt(i) == '\n' && sb.charAt(i - 1) == '=')
{
// 解码这个地方也要修改一下
// sb.deleteCharAt(i);
sb.deleteCharAt(i - 1);
}
}
str = sb.toString();
byte[] bytes = str.getBytes(StandardCharsets.US_ASCII);
if(bytes.length == 0){
return "";
}
for (int i = 0; i < bytes.length; i++)
{
byte b = bytes[i];
if (b != 95)
{
bytes[i] = b;
}
else
{
bytes[i] = 32;
}
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
for (int i = 0; i < bytes.length; i++)
{
int b = bytes[i];
if (b == '=')
{
try
{
int u = Character.digit((char) bytes[++i], 16);
int l = Character.digit((char) bytes[++i], 16);
if (u == -1 || l == -1)
{
continue;
}
buffer.write((char) ((u << 4) + l));
}
catch (ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
}
}
else
{
buffer.write(b);
}
}
return new String(buffer.toByteArray(), charset);
}
catch (Exception e)
{
e.printStackTrace();
return "";
}
}
}