我使用javamail使用IMAP协议从交换帐户中读取邮件。这些邮件为纯格式,其内容为XML。
几乎所有这些邮件的大小都很短(通常在100Kb以下)。但是,有时我必须处理大型邮件(大约10Mb-15Mb)。例如,昨天我收到了一封大小为13Mb的电子邮件。仅花费了50多分钟即可阅读。正常吗有没有办法提高其性能?代码是:
Session sesion = Session.getInstance(System.getProperties());
Store store = sesion.getStore("imap");
store.connect(host, user, passwd);
Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_WRITE);
Message[] messages = inbox.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false));
for (int i = 0 ; i< messages.length ; i++){
Object contents = messages[i].getContent(); // Here it takes 50 min on 13Mb mail
// ...
}
花费这么长时间的方法是messages[i].getContent()
。我究竟做错了什么?有什么提示吗?
非常感谢,抱歉我的英语! ;)
我终于解决了这个问题,并希望分享。
此解决方案,至少是对我有用的解决方案,已在以下站点找到:http://www.oracle.com/technetwork/java/faq-135477.html#imapserverbug
所以,我在第一篇文章中输入的原始代码变为:
Session sesion = Session.getInstance(System.getProperties());
Store store = sesion.getStore("imap");
store.connect(host, user, passwd);
Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_WRITE);
// Convert to MimeMessage after search
MimeMessage[] messages = (MimeMessage[]) carpetaInbox.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false));
for (int i = 0 ; i< messages.length ; i++){
// Create a new message using MimeMessage copy constructor
MimeMessage cmsg = new MimeMessage(messages[i]);
// Use this message to read its contents
Object obj = cmsg.getContent();
// ....
}
诀窍是,使用MimeMessage()复制构造函数,创建一个新的MimeMessage并读取其内容而不是原始消息。您应该注意,此类对象并未真正连接到服务器,因此您对它所做的任何更改(例如设置标志)都不会生效。邮件上的任何更改都必须在原始邮件上完成。
总结:此解决方案可以读取使用IMAP协议连接到Exchange Server的大型纯文本邮件(最高15Mb)。时间从读取13Mb邮件的51-55分钟降低到读取同一邮件的9秒。难以置信的。
希望这对某人有帮助,对于英语错误感到抱歉;)
总是消息[i] .getContent()会成为代码中最慢的部分。原因通常是IMAP服务器不会缓存这部分消息数据。不过,您可以尝试以下方法:
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(FetchProfileItem.FLAGS);
fp.add(FetchProfileItem.CONTENT_INFO);
fp.add("X-mailer");
and after you have specified the fetch profile then you do your search/fetch of messages.
[基本概念是,IMAP提供程序仅在必要时才从服务器获取消息的数据。 (使用javax.mail.FetchProfile对其进行优化)。头和主体结构信息一经获取,就始终缓存在Message对象中。但是,未缓存bodypart的内容。因此,每次客户端请求内容(使用getContent()或使用getInputStream())时,都会向服务器发出新的FETCH请求。这样做的原因是消息的内容可能很大,并且如果我们为大量消息缓存此内容,则由于垃圾收集器无法释放所引用的内容,因此系统可能很快就会耗尽内存对象。客户应意识到这一点,并且在需要时必须自己保留检索到的内容。
通过使用上述代码段,您可以“希望”提高速度,但是否可行,则完全取决于您的SMTP服务器。由于上段中提到的负载问题,所有大型SMTP服务器都不支持此行为,因此您可能无法获得任何速度。
使用Folder.fetch方法,您可以在一个操作中预取多封邮件的元数据。这将减少处理每条消息的时间,但是对于一条巨大的消息不会有太大帮助。
有效地处理大量消息部分,通常需要使用getInputStream方法来逐步处理数据,而不是使用getContent方法来读取其中的所有数据并使用所有数据创建一个巨大的String对象。
您还可以通过指定“ mail.imap.fetchsize”属性(默认值为16384)来调整抓取。如果您的大多数消息小于100K,并且您始终需要读取消息中的所有数据,可能会将fetchsize设置为100K。这将使小消息更快,大消息更有效。
我有一个类似的问题。通过IMAP提取邮件非常慢。此外,我在下载大型附件时遇到了另一个问题。在查看了JavaMail FAQ之后,我在this question中找到了针对下一个问题的解决方案,建议将mail.imap.partialfetch
(分别为mail.imaps.partialfetch
)设置为false
。这不仅解决了下载问题,而且还解决了消息阅读缓慢的问题。
在引用的JavaMail notes.txt中说。
由于Microsoft Exchange IMAP服务器中的问题,不足读取大消息时,可能会检索到字节数。那里有两种方法可以解决此Exchange错误:
(a)Exchange IMAP服务器提供了一个名为UI的“快速消息检索”。只需转到站点,服务器或收件人,单击“ IMAP4”选项卡,然后单击复选框之一是“启用快速消息检索”。关闭它和八位字节计数将是准确的。有关详细信息,请参见http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q191504
(b)将“ mail.imap.partialfetch”属性设置为false。你会有在您提供的Properties对象中设置此属性您的会话。
某些IMAP服务器未实现IMAP部分FETCH功能正常。此问题通常表现为损坏从IMAP下载大邮件时的电子邮件附件服务器。要解决此服务器错误,请设置“ mail.imap.partialfetch”属性为假。您必须在属性中设置此属性您提供给会话的对象。