使用JavaMail读取电子邮件内容时的编码问题
我正在使用JavaMail 1.4.1(我已升级到1.4.5版本,但有相同的问题)阅读来自电子邮件帐户的邮件,但内容的编码有问题:使用JavaMail读取电子邮件内容时的编码问题,java,email,encoding,utf-8,jakarta-mail,Java,Email,Encoding,Utf 8,Jakarta Mail,我正在使用JavaMail 1.4.1(我已升级到1.4.5版本,但有相同的问题)阅读来自电子邮件帐户的邮件,但内容的编码有问题: POP3Message pop3message; ... Object contentObject = pop3message.getContent(); ... String contentType = pop3message.getContentType(); String content = contentObject.toString(); 某些消
POP3Message pop3message;
...
Object contentObject = pop3message.getContent();
...
String contentType = pop3message.getContentType();
String content = contentObject.toString();
某些消息被正确读取,但其他消息由于编码不合适而具有奇怪的字符。我意识到它不适用于特定的内容类型
如果contentType是以下任意一种类型,则效果良好:
- 文本/纯文本;字符集=ISO-8859-1
- 文本/纯文本
charset=“iso-8859-1” - 文本/纯文本
charset=“ISO-8859-1”
format=“flowed” - 文本/纯文本;字符集=windows-1252
- 文本/纯文本
charset=“utf-8”
更新 这是我添加的一段代码,用于尝试jlordo提供的函数getUTF8Content()
POP3Message pop3message = (POP3Message) message;
String uid = pop3folder.getUID(message);
//START JUST FOR TESTING PURPOSES
if(uid.trim().equals("1401")){
Object utfContent = pop3message.getContent();
System.out.println(utfContent.getClass().getName()); // it is of type String
//System.out.println(utfContent); // if not commmented it prints the content of one of the emails I'm having problems with.
System.out.println(pop3message.getEncoding()); //prints: quoted-printable
System.out.println(pop3message.getContentType()); //prints: text/plain; charset="utf-8"
String utfContentString = getUTF8Content(utfContent); // throws java.lang.ClassCastException: java.lang.String cannot be cast to javax.mail.util.SharedByteArrayInputStream
System.out.println(utfContentString);
}
//END TEST CODE
您是如何检测到这些消息具有“奇怪的字符”的?您是否在某处显示数据?无论您使用什么方法来显示数据,都可能无法正确处理Unicode字符
第一步是确定问题是您输入了错误的字符,还是正确的字符显示不正确。您可以检查数据中每个字符(例如,从getContent方法返回的字符串)的Unicode值,以确保每个字符具有正确的Unicode值。如果是,则问题在于您用于显示字符的方法。请尝试此方法,并告诉我它是否有效:
if ( *check if utf 8 here* ) {
content = getUTF8Content(contentObject);
}
// TODO take care of UnsupportedEncodingException,
// IOException and ClassCastException
public static String getUTF8Content(Object contentObject) {
// possible ClassCastException
SharedByteArrayInputStream sbais = (SharedByteArrayInputStream) contentObject;
// possible UnsupportedEncodingException
InputStreamReader isr = new InputStreamReader(sbais, Charset.forName("UTF-8"));
int charsRead = 0;
StringBuilder content = new StringBuilder();
int bufferSize = 1024;
char[] buffer = new char[bufferSize];
// possible IOException
while ((charsRead = isr.read(buffer)) != -1) {
content.append(Arrays.copyOf(buffer, charsRead));
}
return content.toString();
}
顺便问一下,JavaMail 1.4.1是一项要求吗?最新版本是1.4.5。对我有用的是,我调用了
getContentType()
,并检查字符串中是否包含“utf”(定义用作utf之一的字符集)
如果是,在这种情况下,我会以不同的方式对待内容
private String encodeCorrectly(InputStream is) {
java.util.Scanner s = new java.util.Scanner(is, StandardCharsets.UTF_8.toString()).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
(IS-to-String转换器的一种修改,来自)
这里重要的部分是使用正确的字符集。这为我解决了这个问题。首先,您必须按照UTF-8编码方式添加标题,如下所示:
...
MimeMessage msg = new MimeMessage(session);
msg.setHeader("Content-Type", "text/html; charset=UTF-8");
msg.setHeader("Content-Transfer-Encoding", "8bit");
msg.setFrom(new InternetAddress(doConversion(from)));
msg.setRecipients(javax.mail.Message.RecipientType.TO, address);
msg.setSubject(asunto, "UTF-8");
MimeBodyPart mbp1 = new MimeBodyPart();
mbp1.setContent(text, "text/html; charset=UTF-8");
Multipart mp = new MimeMultipart();
mp.addBodyPart(mbp1);
...
但对于“from”标题,我使用以下方法转换字符:
public String doConversion(String original) {
if(original == null) return null;
String converted = original.replaceAll("á", "\u00c3\u00a1");
converted = converted.replaceAll("Á", "\u00c3\u0081");
converted = converted.replaceAll("é", "\u00c3\u00a9");
converted = converted.replaceAll("É", "\u00c3\u0089");
converted = converted.replaceAll("í", "\u00c3\u00ad");
converted = converted.replaceAll("Í", "\u00c3\u008d");
converted = converted.replaceAll("ó", "\u00c3\u00b3");
converted = converted.replaceAll("Ó", "\u00c3\u0093");
converted = converted.replaceAll("ú", "\u00c3\u00ba");
converted = converted.replaceAll("Ú", "\u00c3\u009a");
converted = converted.replaceAll("ñ", "\u00c3\u00b1");
converted = converted.replaceAll("Ñ", "\u00c3\u0091");
converted = converted.replaceAll("€", "\u00c2\u0080");
converted = converted.replaceAll("¿", "\u00c2\u00bf");
converted = converted.replaceAll("ª", "\u00c2\u00aa");
converted = converted.replaceAll("º", "\u00c2\u00b0");
return converted;
}
如果需要包含一些其他字符,您可以在UTF中看到相应的UTF-8十六进制编码。您在哪里看到
Ubicaci³n(而不是Ubicación)
?安慰变量检查器?我怀疑一切正常,但调试器无法显示utf-8字符。@jlordo在Eclipse的调试器中,通过观察内容变量中的内容,我看到了这一点。同样在数据库postgresql中,如果我做了一个select,我会得到这个结果。你是从数据库中读取它,还是将它写入数据库,然后再次读取?数据库设置是否正确?@jlordo如果我在数据持久化之前就检测到问题,这怎么可能是数据库的问题?@jlordo在持久化数据之前,我在调试器中观察数据,将其保存到日志中,甚至在控制台中打印数据,所有这些都以相同的方式显示(而对于ISO-8859-1和windows-1252,则正确显示)。在将其持久化到数据库中之后,我可以使用PostgreSQL的管理员看到完全相同的结果。您真的认为Eclipse、控制台、日志以及后来的PostgreSQL管理员无法正确打印它吗?我想这一定是关于Javamail的问题。我在Eclipse的调试器中看到了它,但在postgresql数据库中也可以看到它。我不认为这是eclipse和PgAdminIII的问题。事实上,当我从该表中读取时,我再次发现该字段中存在编码问题。再次,按照我的建议确定问题的引入位置。上面是JavaMail在内部使用消息中的字符集返回任何部分的字符串时所做的有效操作。你是说这对你不起作用吗?我没看消息来源就想到了。这将从基础字节数组中读取字节。如果它们在数组中是错误的,那么它们是错误的,你需要检查它们是如何进入数组的。我是说JavaMail已经做了同样的事情,所以没有必要在应用程序中这样做。是的,正如你所说,如果消息中有错误的字节,那么就会有其他错误。例如,创建消息的程序可能将iso-8859-1字节放入消息中,但将标头中的字符集设置为“utf-8”。垃圾邮件程序经常是这样被破坏的。在你的帖子中,你会写“所以邮件看起来没问题”。如果消息包含错误的字节,如何才能正确显示?我已经为我遇到问题的一封电子邮件尝试了这段代码,对于它,对象contentObject的类型是java.lang.String。当我尝试调用getUTF8Content()时,它会在第一行抛出一个ClassCastException:java.lang.ClassCastException:java.lang.String不能转换为javax.mail.util.SharedByteArrayInputStream