前言
嘿嘿,北京又下雨了,莫名的开心啊!
效果图
以表情为例演示下载cid内嵌资源到本地并替换html 中的img src:为本地路径,同时存储到数据库,下载进来则不用再进行下载,你看到cid内嵌资源,列表也识别为附件,因为这属于内嵌的附件了,其实我觉得这个标识可以去掉了,等产品提了再说吧,嘿嘿!
什么是cid?
一封邮件由邮件头(Headers)和邮件体组成的,邮件头中包括了各种属性,其中就有cid,即Content-Id,下图是Java邮件开发详解中对Content-id的解释(张孝祥版PDF)
这个cid跟这封邮件的内嵌资源一一对应,这个cid主要用来替换你下载到本地的资源文件比如gif表情,然后将src中的路径换成本地路径才能正常显示,这个没有附件容易理解,其实可以这样理解,他也是附件,就是你要先下载到本地,替换完之后才能正常的展示到用户面前,多了个下载的过程,而附件可以直接展示,点击某个附件再调用下载的过程.
解析cid并存储到本地数据库
解析相信大家都会,邮件解析也就递归进行吧,获取part中的content-id就行,注意content-id的大小写,代码如下
/**
* 获取附件
*/
private void saveAttachMent(Part part) throws Exception {
String fileName;
if (part.isMimeType("multipart/*")) {
Multipart mp = (Multipart) part.getContent();
for (int i = 0; i < mp.getCount(); i++) {
BodyPart mPart = mp.getBodyPart(i);
String disposition = mPart.getDisposition();
if ((disposition != null) && ((disposition.equals(Part.ATTACHMENT)) || (disposition.equals(Part.INLINE)))) {
fileName = mPart.getFileName();
if (fileName != null) {
fileName = MimeUtility.decodeText(fileName);
attachments.add(fileName);
attachmentsInputStreams.add(mPart.getInputStream());
attachSizeList.add(Long.valueOf(mPart.getSize()));
}
} else if (mPart.isMimeType("multipart/*")) {
saveAttachMent(mPart);
} else {
fileName = mPart.getFileName();
if ((fileName != null)) {
fileName = MimeUtility.decodeText(fileName);
attachments.add(fileName);
attachmentsInputStreams.add(mPart.getInputStream());
attachSizeList.add(Long.valueOf(mPart.getSize()));
String cid = getCid(mPart);
if (!android.text.TextUtils.isEmpty(cid)) {
cidList.add(cid);
}
Logger.e("getCid 内嵌= ", cid);
}
}
}
} else if (part.isMimeType("message/rfc822")) {
saveAttachMent((Part) part.getContent());
}
}
获取cid方法
public static String getCid(Part p) throws MessagingException {
String content, cid;
String[] headers = p.getHeader("Content-Id");
if (headers != null && headers.length > 0) {
content = headers[0];
} else {
return null;
}
if (content.startsWith("<") && content.endsWith(">")) {
cid = "cid:" + content.substring(1, content.length() - 1);
} else {
cid = "cid:" + content;
}
return cid;
}
看下log输出,因为我用FoxMail发送的表情测试的,可以看到cid后面有foxmail的标识,可能是cid的生成规则吧
可以看到这个cid是一样的,应该就是一个内嵌资源,或者是一个表情,然后将这封邮件对应的cid存储到数据库表中(我们是附件表).
之后当用户点击列表进入详情时,根据InputStream流来下载这个资源,并根据cid替换src中的路径为本地路径,之后就能正常显示,替换代码我这样写的,其实可以写个JS的函数,我这边简单化了,回头我可以考虑优化下
public boolean isCidImgAndReplace(String text) {
if (TextUtils.isEmpty(text)) {
return false;
}
return text.contains("<img src=\"cid:");
}
public String replaceLocalPathByImgCid(String content,String fileName,String filePath) {
return content.replace("<img src=" + "\"" + fileName + "\"","<img src=\"file://" + filePath+"\"").toString();
}
第一个方法我是判断这个是否是内嵌的资源,如果是的话, 下面会执行下载,最后用第二个方法替换路径,动态传入cid,和本地路径进行替换,所以,有表情重复的话,也能全部的替换,因为cid是一样的,大家可以试下.
结尾
到这里基本就结束了,这个过程就可以了,上面的gif图就可以看到这个过程了,主要还是要理解邮件的解析过程和cid的意思,当时搜索不到资料,因为这个Java Mail比较早了,现在用这个做移动端开发邮件的也比较少,我权当记录下吧,大家有不会的可以在下面评论,共勉!