复杂邮件发送问题

转载请标明出处!https://www.cnblogs.com/dream-saddle/p/10978113.html

关于 JavaMail 如何发送邮件这里就不赘述了,网上有很多例子。其中最复杂的邮件发送莫过于 html邮件包含内嵌图片以及附件,最近项目中的这项功能我在发送邮件时就出现了一系列问题。

我在使用 JavaMail 发送了邮件之后,会再次通过 JavaMail 将其获取回来进行解析,由于发送操作不当,导致了解析就不是那么回事了。

接下来先看看正常的解析过程吧。关于邮件的解析,网上依然有很多例子。

private static void multipartMailParser(Multipart mail) throws Exception {
int count = mail.getCount();
System.out.println("part count: " + count);
for (int i = 0; i < count; i++) {
BodyPart bodyPart = mail.getBodyPart(i); //cid 解析
//cid 示例: <4a85b9c9$1$16af704cfc3$Coremail$user_taohan$163.com>
String[] cids = bodyPart.getHeader("Content-Id");
System.out.println("=========> cids: " + (cids == null ? "NULL" : cids.length));
String content = "", cid = "";
if (cids != null && cids.length > 0) {
content = cids[0];
if (content.startsWith("<") && content.endsWith(">")) {
cid = "cid:" + content.substring(1, content.length() - 1);
} else {
cid = "cid:" + content;
}
}
System.out.println(content+"---"+cid); System.out.println(bodyPart.getContentType());
if (bodyPart.isMimeType("text/plain")) {
System.out.println("纯文本邮件: " + bodyPart.getContent());
} else if (bodyPart.isMimeType("text/html")) {
System.out.println("html邮件: " + bodyPart.getContent());
} else if (bodyPart.isMimeType("multipart/*")) {
Multipart part = (Multipart)bodyPart.getContent();
multipartMailParser(part);
} else if (bodyPart.isMimeType("application/octet-stream")) {
String disposition = bodyPart.getDisposition();
System.out.println("任意的二进制数据: " + disposition);
//这里就是对附件进行解析
if (disposition.equalsIgnoreCase(BodyPart.ATTACHMENT)) {
String fileName = bodyPart.getFileName();
System.out.println("------------------------保存附件 " + fileName);
InputStream is = bodyPart.getInputStream();
File file = new File("C:\\Users\\AB\\Desktop\\mail\\"+fileName);
copy(is, new FileOutputStream(file));
}
} else if (bodyPart.isMimeType("image/*") && !("".equals(cid))) {
//内嵌图片处理
DataHandler dataHandler = bodyPart.getDataHandler();
String name = dataHandler.getName();
System.out.println("内嵌图片 NAME: " + name);
InputStream is = dataHandler.getInputStream();
File file = new File("C:\\Users\\AB\\Desktop\\mail\\"+name);
copy(is, new FileOutputStream(file));
}
}
} private static void copy(InputStream is, OutputStream os) throws IOException {
byte[] bytes = new byte[1024];
int len = 0;
while ((len=is.read(bytes)) != -1 ) {
os.write(bytes, 0, len);
}
if (os != null)
os.close();
if (is != null)
is.close();
}

使用以上方法对邮件进行解析是没有问题的,内嵌图片、附件都是可以分开解析的。但在我解析通过 JavaMail 发送的邮件时就出现了问题。

先看看最初是怎么发送的吧。这里就不贴完整代码了,我就是按照文章开始链接对应的文章进行了修改。

//这里只给出附件节点创建方法吧
//给出参数accessory(附件信息)格式为: zxd.jpg-C:/Users/AB/Desktop/zxd.jpg,lyf.jpg-C:/Users/AB/Desktop/lyf.jpg,htmlFile-C:/Users/AB/Desktop/file.html,golang-C:/Users/AB/Desktop/Demo.go
private List<MimeBodyPart> mailAttachmentParts(String accessory) throws MessagingException, UnsupportedEncodingException {
//附件节点集合
List<MimeBodyPart> attachments = new ArrayList<>();
MimeBodyPart attachment;
DataHandler dh;
String[] accs = accessory.split(",");
for (final String acc : accs) {
String[] ac = acc.split("-");
//按照网上文章的例子,这里只需要进行如下设置即可
attachment = new MimeBodyPart();
dh = new DataHandler(new FileDataSource(ac[1]));
attachment.setDataHandler(dh);
attachments.add(attachment);
} return attachments;
}

发送后,查看去邮件服务器中查看,邮件是正常的。但是我再通过 JavaMail 获取就出现问题了。输出如下:(//…​为我给出的注释)

part count: 5
=========> cids: NULL
---
multipart/related;
boundary="----=_Part_2_1562389956.1559641692502"
part count: 2
=========> cids: NULL
---
text/html; charset=UTF-8
//邮件内容正常获取
html邮件: <html><body><h1>这是邮件发送测试十二</h1><b>这依然是刘亦菲</b><br><br><br><img src='cid:liuyifei' /></body></html> //内嵌图片也正常获取
=========> cids: 1
liuyifei---cid:liuyifei
image/jpeg; name=lyf2.jpg
内嵌图片 NAME: lyf2.jpg
=========> cids: NULL
---
image/jpeg; name=zxd.jpg //附件图片获取失败, 可以看见前面为 image/jpeg,也就是说 JavaMail 并没有将其作为附件进行处理
=========> cids: NULL
---
image/jpeg; name=lyf.jpg //附件图片获取失败
=========> cids: NULL
---
//最可笑的是居然将我的 file.html 文件当做了 text/html 来进行了处理, 没有将 html 文件保存到本地,而是直接输出了其中的内容
//我在手机邮件app中查看这封邮件的时候, 我的邮件内容并不是上面打印的内容, 而是这个 html 文件中的内容
text/html; charset=us-ascii; name=file.html
html邮件: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>file upload</title>
</head>
<body>
<div>
<form action="http://localhost:8080/api/mail/record/accessory/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Submit">
</form>
</div>
</body>
</html> //但奇怪的是 Demo.go 这个文件又被正常的当做了附件处理
//到这里就大概知道其中的原因了
//上面的 图片和html 文件都是比较特殊的, 但是 Demo.go 就不一样了
=========> cids: NULL
---
application/octet-stream; name=Demo.go
任意的二进制数据: attachment
------------------------保存附件 Demo.go

于是,我将需要发送的邮件保存至本地, message.writeTo(new FileOutputStream("D/mail.eml")) 即可;

打开查看其中的内容发现

附件都有如下内容:

Content-Type: image/jpeg; name=lyf.jpg
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=lyf.jpg
—————————————————————
Content-Type: application/octet-stream; name=Demo.go
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=Demo.go

而对比上面获取邮件的输出内容,只有 Demo.go 这一个文件输出了 application/octet-stream 字样, 所以问题就已经变得很明显了。

只需要在创建附件节点时,为附件节点设置以下几样东西即可

attachment.setFileName(MimeUtility.encodeText(dh.getName())); //附件名称
attachment.setDisposition(BodyPart.ATTACHMENT); //设置 disposition 为 attachment (附件标识)
attachment.setHeader("content-disposition", "attachment; filename="+dh.getName()); //设置以下两个 header
attachment.setHeader("content-type", "application/octet-stream; name="+dh.getName());

再看获取邮件输出:

part count: 5
=========> cids: NULL
---
multipart/related;
boundary="----=_Part_2_1714832523.1559700934372"
part count: 2
=========> cids: NULL
---
text/html; charset=UTF-8
html邮件: <html><body><h1>这是邮件发送测试十四</h1><b>这依然是刘亦菲</b><br><br><br><img src='cid:liuyifei' /></body></html> =========> cids: 1
liuyifei---cid:liuyifei
image/jpeg; name=lyf2.jpg
内嵌图片 NAME: lyf2.jpg
=========> cids: NULL
---
application/octet-stream; name=zxd.jpg
任意的二进制数据: attachment
------------------------保存附件 zxd.jpg
=========> cids: NULL
---
application/octet-stream; name=lyf.jpg
任意的二进制数据: attachment
------------------------保存附件 lyf.jpg
=========> cids: NULL
---
application/octet-stream; name=file.html
任意的二进制数据: attachment
------------------------保存附件 file.html
=========> cids: NULL
---
application/octet-stream; name=Demo.go
任意的二进制数据: attachment
------------------------保存附件 Demo.go

这下就正常了,其实解决办法就是添加上面几样配置即可。

附件中文乱码解决

经过以上处理本以为正常了,但是附件又出现了中文乱码问题,在网上找了很多办法都不行,最终解决办法如下:

中文乱码问题:

网上的办法都是 bodyPart.setFileName(MimeUtility.encodeText(文件名)); 我也试过这种办法,但是未能奏效,最后通过下面的办法解决

//自己模拟一个 MimeUtility.encodeText() 返回的字符串
BASE64Encoder encoder = new BASE64Encoder();
String fileName="=?UTF-8?B?"+encoder.encode(dh.getName().getBytes("UTF-8"))+"?=";
bodyPart.setFileName(fileName);
attachment.setDisposition(BodyPart.ATTACHMENT); //设置 disposition 为 attachment (附件标识)
attachment.setHeader("content-disposition", "attachment; filename="+fileName); //设置以下两个 header, 这里也需要设置 base64 编码的文件名, JavaMail 默认就是使用的Base64编码文件名
attachment.setHeader("content-type", "application/octet-stream; name="+fileName);

获取的时候任然要使用 MimeUtility.decodeText(bodyPart.getFileName()) 对文件名进行解码

中文乱码过长问题:

这个的解决办法和网上方法一样,如下:

static {
  System.setProperty("mail.mime.splitlongparameters","false");
}

具体原因自行百度了,多得很。

JavaMail发送邮件后再通过JavaMail接收格式问题的更多相关文章

  1. 使用JavaMail发送邮件-从FTP读取图片并添加到邮件正文发送

    业务分析: 最近工作需要,需要从FTP读取图片内容,添加到邮件正文发送.发送邮件正文,添加附件采用Spring的MimeMessageHelper对象来完成,添加图片也将采用MimeMessageHe ...

  2. JavaMail发送邮件(超详细)

    一:邮件发送的基本概念 本文我将阐述使用JavaMail方式发送和接收Email的详细说明,本博客本着以后遇到类似的邮件发送需求可以直接把代码粘过去直接使用,快捷方便省时间,对于刚接触的JavaMai ...

  3. javamail发送邮件(转)

    今天学习了一下JavaMail,javamail发送邮件确实是一个比较麻烦的问题.为了以后使用方便,自己写了段代码,打成jar包,以方便以后使用.呵呵 以下三段代码是我的全部代码,朋友们如果想用,直接 ...

  4. Java Web(十二) JavaMail发送邮件

    发送邮件的原理 概叙 邮件服务器: 要在 Internet 上提供电子邮件功能,必须有专门的电子邮件服务器.例如现在 Internet 很多 提供邮件服务的厂商:sina.sohu.163 等等他们都 ...

  5. 使用JavaMail发送邮件-no object DCH for MIME type multipart/mixed报错解决

    最近需要实现一个使用Spring schedule按一定时间间隔自动触发条件发送邮件的功能,在开发的过程中,是按照先测试能发出text/html文本邮件,然后测试添加附件发送邮件,我碰到的问题是,文本 ...

  6. 实用代码|javaMail发送邮件(文末重磅资源!)

    每天进步一点点,距离大腿又近一步!阅读本文大概需要5分钟 JavaMail发送邮件,简单实用,了解一下呗~ 1.开启邮箱MAP/SMTP服务,获取第三方授权码 以QQ邮箱为例 2.主要代码 maven ...

  7. JavaMail发送邮件

    发送邮件包含的内容有: from字段  --用于指明发件人 to字段      --用于指明收件人 subject字段  --用于说明邮件主题 cc字段     -- 抄送,将邮件发送给收件人的同时抄 ...

  8. JavaMail发送邮件第一版

    首先,我们先来了解一个基本的知识点,用什么工具来发邮件? 简单的说一下,目前用的比较多的客户端:OutLook,Foxmail等 顺便了解一下POP3.SMTP协议的区别: POP3,全名为" ...

  9. web应用中使用JavaMail发送邮件

    现在很多的网站都提供有用户注册功能, 通常我们注册成功之后就会收到一封来自注册网站的邮件.邮件里面的内容可能包含了我们的注册的用户名和密码以及一个激活账户的超链接等信息.今天我们也来实现一个这样的功能 ...

随机推荐

  1. 题解报告:hdu 2588 GCD(欧拉函数)

    Description The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written ...

  2. Node“getTextContent() is undefined for the type Node”处理办法

    最近一个项目在MyEclipse导入后总是报getTextContent() is undefined for the type Node错误. 经过查找原来是因为Node类为JDK中自带的(org. ...

  3. 网站开发综合技术 一 JavaScript简介 二JavaScript语法

    第1部分 JavaScript简介 1.JavaScript它是个什么东西? 它是个脚本语言,需要有宿主文件,他的宿主文件是html文件. 2.它与Java有什么关系? 没有什么直接联系,java是S ...

  4. LN : leetcode 283 Move Zeroes

    lc 283 Move Zeroes 283 Move Zeroes Given an array nums, write a function to move all 0's to the end ...

  5. Paxos,Raft,Zab一致性协议-Raft篇

    Raft是一个一致性算法,旨在易于理解.它提供了Paxos的容错和性能.不同之处在于它被分解为相对独立的子问题,它清楚地解决了实际系统所需的所有主要部分.我们希望Raft能够为更广泛的受众提供共识,并 ...

  6. CF817B Makes And The Product

    思路: 模拟,数学. 实现: #include <iostream> #include <cstdio> #include <algorithm> using na ...

  7. 2057. [ZLXOI2015]殉国

    ★☆   输入文件:BlackHawk.in   输出文件:BlackHawk.out   评测插件 时间限制:0.05 s   内存限制:256 MB [题目描述] 正义的萌军瞄准了位于南极洲的心灵 ...

  8. Modbus测试工具ModbusPoll与Modbus Slave使用方法

    感谢https://blog.csdn.net/byxdaz/article/details/77979114原创,由于CSDN经常调整,故再编辑收藏,并修改了部分BUG. 一.介绍 Modbus P ...

  9. MFC_2.2 编辑框和文本控件

    编辑框和文本控件 1.拖控件 2.绑定变量.用户名密码编辑框控件类型.取名字.用户协议用值类型,默认CString. 设置属性.用户类型.选择mustiline TRUE. AOTO HScroll ...

  10. Spring框架系列(四)--IOC控制反转和DI依赖注入

    背景: 如果对象的引用或者依赖关系的管理由具体对象完成,代码的耦合性就会很高,代码测试也变得困难.而IOC可以很好的解决这个问题,把这 些依赖关系交给框架或者IOC容器进行管理,简化了开发. IOC是 ...