用javamail接收没有经过编码(转码)的中文附件时,出现javamail javax.mail.internet.ParseException异常

Fandian 2013-06-23 11:12:45
我们查看一封邮件的“原始信息”时(在FOXMAIL,OUTLOOK,或者WEB免费信箱中,都可以查看邮件原始信息,其实就是一个eml格式的文本文件),

在邮件原始信息中,除了可以看到很多有用邮件头信息(From,To,Subject,Content-Type,Message-Id,,,,等等),也可以看到经过编码的邮件内容(包括正文与附件或内嵌资源)

比如带中文名附件的邮件原始信息中的附件应该是以下这样子的,这是一个WORD格式的附件:
Content-Type: application/msword; 
name="=?gb2312?B?azNtbGhxZ3DI57rOvPK7r8rkyOvW2Li00NTUtLXEzsTX1m1lYTk5ZGYuZG9j?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="=?gb2312?B?azNtbGhxZ3DI57rOvPK7r8rkyOvW2Li00NTUtLXEzsTX1m1lYTk5ZGYuZG9j?="


即一个附件包括三个信息:
1,Content-Type
2,Content-Transfer-Encoding
3,Content-Disposition

其中Content-Type有个name属性,Content-Disposition有个filename属性,这其实就是附件的文件名。
它们的值是由三个部分组成的,每个部分用"?"分割:
第一部分:?gb2312?,表示附件文件名是用中文的gb2312字集,即表示有带中文。
第二部分:?B?,表示文件名采用 base64编码。
第三部分:?azNtbGhxZ3DI57rOvPK7r8rkyOvW2Li00NTUtLXEzsTX1m1lYTk5ZGYuZG9j?,这表示经过 base64编码的文件名。


以上说的都是正常情况,此情况下用javamail 接收邮件,完全正常,不会发生任何异常。

但是如果邮件原始信息是以下这样子呢,会发生什么呢?

Content-Type: application/msword;
name=如何lz有效调整薪酬.doc
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename=如何lz有效调整薪酬.doc


上面的邮件,使用javamail的BodyPart.getDisposition(),或BodyPart.getFileName()时,就会发生javamail javax.mail.internet.ParseException:Expected parameter value got "????"异常。

当然,以上两个方法我们在做javamail接收邮件时,必须用到,它们是用于判断邮件是否带附件,以及取得附件的文件名的必须用到的方法。


#####################侵害线######################


以上是异常事件的描述,各位,问题来了。
1,为什么会发生中文名的附件没有转码情况?
2,有什么办法解析此类邮件,能正常取得附件?






...全文
2592 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
iaiti 2013-06-25
  • 打赏
  • 举报
回复
引用 14 楼 Fandian 的回复:
[quote=引用 12 楼 iaiti 的回复:] [quote=引用 10 楼 Fandian 的回复:] [quote=引用 8 楼 iaiti 的回复:] [quote=引用 7 楼 Fandian 的回复:] 有人处理过类似的问题吗?
lz,filename为什么异常,乱码了嘛,你自己能不能把乱码转成正常的,那就正常了。[/quote] 取不出来,不是取出来后乱码。[/quote] 不好意思,是我看错了。楼主,看一下,http://bbs.csdn.net/topics/20060460和你同样问题的。 [/quote] 1,这文章看过,我分析一下。
attachment="d:\网络地址.txt";
mbp2.setFileName(attachment);如果是这样就不能在信箱里正确显示!
如果有人这样发邮件,这肯定是不行的,文件名必须encode才可以;当然我们没办法控制别人发邮件的代码,其实用客户端发是不会这样的,此种情况经常发生在用JAVAMAIL发邮件的,比如注册激活邮件之类的邮件中。 2,这文章里的二楼方法不行,就是我上面说的问题,BodyPart.getFilename()都发生异常了,就不用去谈对它的结果进行处理了,没结果,呵。 [/quote] 那帮不了你了,我不懂。。
Fandian 2013-06-24
  • 打赏
  • 举报
回复
引用 12 楼 iaiti 的回复:
[quote=引用 10 楼 Fandian 的回复:] [quote=引用 8 楼 iaiti 的回复:] [quote=引用 7 楼 Fandian 的回复:] 有人处理过类似的问题吗?
lz,filename为什么异常,乱码了嘛,你自己能不能把乱码转成正常的,那就正常了。[/quote] 取不出来,不是取出来后乱码。[/quote] 不好意思,是我看错了。楼主,看一下,http://bbs.csdn.net/topics/20060460和你同样问题的。 [/quote] 1,这文章看过,我分析一下。
attachment="d:\网络地址.txt";
mbp2.setFileName(attachment);如果是这样就不能在信箱里正确显示!
如果有人这样发邮件,这肯定是不行的,文件名必须encode才可以;当然我们没办法控制别人发邮件的代码,其实用客户端发是不会这样的,此种情况经常发生在用JAVAMAIL发邮件的,比如注册激活邮件之类的邮件中。 2,这文章里的二楼方法不行,就是我上面说的问题,BodyPart.getFilename()都发生异常了,就不用去谈对它的结果进行处理了,没结果,呵。
Fandian 2013-06-24
  • 打赏
  • 举报
回复
有人处理过类似的问题吗?
iaiti 2013-06-24
  • 打赏
  • 举报
回复
异常还是看一下别人的代码吧,那个地方写错了,因为别人只是乱码问题。我刚开始也看错了。
iaiti 2013-06-24
  • 打赏
  • 举报
回复
引用 10 楼 Fandian 的回复:
[quote=引用 8 楼 iaiti 的回复:] [quote=引用 7 楼 Fandian 的回复:] 有人处理过类似的问题吗?
lz,filename为什么异常,乱码了嘛,你自己能不能把乱码转成正常的,那就正常了。[/quote] 取不出来,不是取出来后乱码。[/quote] 不好意思,是我看错了。楼主,看一下,http://bbs.csdn.net/topics/20060460和你同样问题的。
Fandian 2013-06-24
  • 打赏
  • 举报
回复
引用 9 楼 iaiti 的回复:
就像你平时做错东西一样,有时候错了就是错了,要怎么改才最重要!
其实有两种办法,但比较别扭: 1,改写javamail API中的相关类,让它可以取得没有转码的中文文件名。 2,出现异常时,做一下异常处理,然后用另外的方法(不是javamail的)来提取附件。
Fandian 2013-06-24
  • 打赏
  • 举报
回复
引用 8 楼 iaiti 的回复:
[quote=引用 7 楼 Fandian 的回复:] 有人处理过类似的问题吗?
lz,filename为什么异常,乱码了嘛,你自己能不能把乱码转成正常的,那就正常了。[/quote] 取不出来,不是取出来后乱码。
iaiti 2013-06-24
  • 打赏
  • 举报
回复
就像你平时做错东西一样,有时候错了就是错了,要怎么改才最重要!
iaiti 2013-06-24
  • 打赏
  • 举报
回复
引用 7 楼 Fandian 的回复:
有人处理过类似的问题吗?
lz,filename为什么异常,乱码了嘛,你自己能不能把乱码转成正常的,那就正常了。
Fandian 2013-06-23
  • 打赏
  • 举报
回复
引用 5 楼 iaiti 的回复:
自己完善商城的时候遇到过这种问题,附件名其实是文件名,文件名本身读取的时候已经出现乱码,这跟数据库存储出现乱码一样,filename.getBytes("ISO-8859-1"),"gb2312"),先转为正常的字符,本身整个协议本身的转码没错。
呵,首先你要先得到文件名(你上面的filename),才可能去做filename.getBytes("ISO-8859-1"),"gb2312") 但是getFileName()就出异常了,如何得到文件名?!
iaiti 2013-06-23
  • 打赏
  • 举报
回复
自己完善商城的时候遇到过这种问题,附件名其实是文件名,文件名本身读取的时候已经出现乱码,这跟数据库存储出现乱码一样,filename.getBytes("ISO-8859-1"),"gb2312"),先转为正常的字符,本身整个协议本身的转码没错。
caofeng891102 2013-06-23
  • 打赏
  • 举报
回复
学习。
Fandian 2013-06-23
  • 打赏
  • 举报
回复
有人来讨论讨论吗 是否可以通过改写javamail的getFileName(),getDisposition()方法来解决?
Fandian 2013-06-23
  • 打赏
  • 举报
回复
再补充:
从上面截图可以看出,getFileName()其实不会返回"如何lz有效调整薪酬.doc",而是很长很长的乱码。因为去getFileName()的时间,看到的,不是"如何lz有效调整薪酬.doc"中文名,而是乱码。
如下图:


Fandian 2013-06-23
  • 打赏
  • 举报
回复
补充一张异常截图。
JavaMail.jsp代码: <%@ page import="javax.mail.*"%> <%@ page import="javax.activation.*"%> <%@ page import="javax.mail.internet.*"%> <%@ page import="java.util.*,java.io.*"%> <%@ page contentType="text/html;charset=utf8"%> <%@page import="java.net.URL"%> <%@page import="org.apache.commons.httpclient.methods.GetMethod"%> <%@page import="org.apache.commons.httpclient.HttpClient"%> <%@page import="vdo.ws.GetSource"%> CH17 - <em><em>Java</em><em>Mail</em></em>2.jsp

利用JavaMail来发送电子邮件 - HTML格式

<% InternetAddress[] address = null; //request.setCharacterEncoding("utf8"); String mailserver = "smtp.163.com";//发出邮箱的服务器 String From = request.getParameter("From");//发出的邮箱 String to = request.getParameter("To");//发到的邮箱 String Subject = request.getParameter("Subject");//标题 String type = request.getParameter("Type");//发送邮件格式为html String messageText = request.getParameter("Message");// 发送内容 boolean sessionDebug = false; try { // 设定所要用的Mail 服务器和所使用的传输协议 java.util.Properties props = System.getProperties(); props.put("mail.host", mailserver); props.put("mail.transport.protocol", "smtp"); props.put("mail.smtp.auth", "true");//指定是否需要SMTP验证 // 产生新的Session 服务 javax.mail.Session mailSession = javax.mail.Session.getDefaultInstance(props, null); mailSession.setDebug(sessionDebug); Message msg = new MimeMessage(mailSession); // 设定发邮件的人 msg.setFrom(new InternetAddress(From)); // 设定收信人的信箱 address = InternetAddress.parse(to, false); msg.setRecipients(Message.RecipientType.TO, address); // 设定信中的主题 msg.setSubject(Subject); // 设定送信的间 msg.setSentDate(new Date()); Multipart mp = new MimeMultipart(); MimeBodyPart mbp = new MimeBodyPart(); // 设定邮件内容的类型为 text/plain 或 text/html mbp.setContent(messageText, type + ";charset=utf8"); mp.addBodyPart(mbp); msg.setContent(mp); Transport transport = mailSession.getTransport("smtp"); ////请填入你的邮箱用户名和密码,千万别用我的^_^ transport.connect(mailserver, "zhang-xinjie", "******");//设发出邮箱的用户名、密码 transport.sendMessage(msg, msg.getAllRecipients()); transport.close(); //Transport.send(msg); out.println("邮件已顺利发送"); } catch (MessagingException mex) { mex.printStackTrace(); out.println(mex); } try{ response.sendRedirect("../indexSelf.jsp");//转向某页 }catch (Exception e){ e.printStackTrace(); } %>
package com.lccert.crm.chemistry.util; import java.util.Date; import java.util.Properties; import javax.mail.Message; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; public class SendMail { private static SendMail instance = null; private SendMail() { } public static SendMail getInstance() { if (instance == null) { instance = new SendMail(); } return instance; } public void send() { try { String to[]={"tiwsonchen@163.com","tiwson@163.com"}; Properties p = new Properties(); //Properties p = System.getProperties(); p.put("mail.smtp.auth", "true"); p.put("mail.transport.protocol", "smtp"); p.put("mail.smtp.host", "smtp.163.com"); p.put("mail.smtp.port", "25"); //建立会话 Session session = Session.getInstance(p); Message msg = new MimeMessage(session); //建立信息 msg.setFrom(new InternetAddress("tiwson@163.com")); //发件人 String toList = getMailList(to); InternetAddress[] iaToList = new InternetAddress().parse(toList); msg.setRecipients(Message.RecipientType.TO,iaToList); //收件人 msg.setSentDate(new Date()); // 发送日期 msg.setSubject("javamail测试邮件"); // 主题 msg.setText("注意,这是测试程序发的,请不要回复!"); //内容 // 邮件服务器进行验证 Transport tran = session.getTransport("smtp"); tran.connect("smtp.163.com", "tiwson", "9041160"); // bluebit_cn是用户名,xiaohao是密码 tran.sendMessage(msg, msg.getAllRecipients()); // 发送 System.out.println("邮件发送成功"); } catch (Exception e) { e.printStackTrace(); } } private String getMailList(String[] mailArray){ StringBuffer toList = new StringBuffer(); int length = mailArray.length; if(mailArray!=null && length <2){ toList.append(mailArray[0]); }else{ for(int i=0;imailArray[i]); if(i!=(length-1)){ toList.append(","); } } } return toList.toString(); } }
适用人群通用各大网易系,腾讯QQ系,新浪系,阿里系等主流邮箱;同也适用于企业开发的企业邮箱,进行收件和发件。课程概述通用各大网易系,腾讯QQ系,新浪系,阿里系等主流邮箱;同也适用于企业开发的企业邮箱,进行收件和发件。POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。它是因特网电子邮件的第一个离线协议标准,POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同删除保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的SMTP 的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件找到下一个目的地。SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器。   SMTP 认证,简单地说就是要求必须在提供了账户名和密码之后才可以登录 SMTP 服务器,这就使得那些垃圾邮件的散播者无可乘之机。。【开发者如何进行快速开发邮件发送系统???本课程系统进行快速研发,项目实战】 部分截图如下:完整版请查看课件或者视频

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧