Java mail with attachment: ClassCastException on javax.mail.Multipart
I use the following code to download the attachment from the mail but it gives the ClassCastException
on the Multipart declaration:
Exception in thread "main" java.lang.ClassCastException: com.sun.mail.imap.IMAPInputStream cannot be cast to javax.mail.Multipart at ReadAttachment.main(ReadAttachment.java:52)
How do I handle IMAPInputStream?
Message messages[] = inbox.getMessages();
for (int j = 0; j < messages.length; j++) {
String mailType = messages[j].getContentType()开发者_如何学编程;
System.out.println("-- Message " + (j + 1) + " --");
System.out.println("SentDate : " + messages[j].getSentDate());
System.out.println("From : " + messages[j].getFrom()[0]);
System.out.println("Subject : " + messages[j].getSubject());
System.out.println("Type :" + messages[j].getContentType());
System.out.println("Attachment :" + messages[j].getFileName());
Multipart mp = (Multipart) messages[j].getContent();
..
System.out.println();
}
I had the same problem with the JavaMail 1.5.1 and OSGi. Using msg.getContent() always returned an InputStream when called from an OSGi bundle while it works perfectly when called from a simple Java test program.
Setting the default CommandMap didn't work for me, but I found a solution here:
https://www.java.net/node/705585
ClassLoader tcl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(javax.mail.Session.class.getClassLoader());
// now call JavaMail API
// ...
} finally {
Thread.currentThread().setContextClassLoader(tcl);
}
The getContent method returns the content as a Java object and its type is of course dependent on the content itself.
The object returned for "text/plain" content is usually a String object.
The object returned for a "multipart" content is always a Multipart subclass.
For content-types that are unknown to the DataHandler system, an input stream is returned as the content.
Seen on the Java Apache Cocoon source code *:
Object objRef = msg.getContent();
if (!(objRef instanceof Multipart)) {
String message = "This Message is not a multipart message!";
getLogger().warn(message);
return;
}
Multipart multipart = (Multipart) objRef;
* I don't take the responsability for the possible misuse of instanceof
I have fixed this error by adding following lines of code. There is something wrong with MailCap, javamail can not find a handler for the multipart/mixed part, so this bit needs to be added. This resolved my problem. Hope it helps someone out there.
MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
CommandMap.setDefaultCommandMap(mc);
Cheers!
OK. I think the real problem here is that although you should be checking for the object type you're getting back....it still might be IMAPInputStream when it should not be.
I have been hammering on this for over two days.
The underlying problem is often that the Java Mail API does something very dumb, it tries to read in a file called mailcap which isn't always available if the class loader has been switched. This is particularly tricky in my case because I'm dealing with OSGi bundles and don't seem to have direct control over which loader I'm using....but I digress.
I found 'a fix'...perhaps THE FIX after sifting through the source code of the Java Mail API as a last resort.
// Set up our Mailcap entries. This will allow the JAF
// to locate our viewers.
File capfile = new File("/path/to/mailcap");
if (!capfile.isFile()) {
System.out.println(
"Cannot locate the \"simple.mailcap\" file.");
System.exit(1);
}
CommandMap.setDefaultCommandMap( new MailcapCommandMap(
new FileInputStream(capfile)));
I've been Googling for days and found dozens of people with the same problem and various classpath, thread, classloader suggestions. But this is the only thing that worked for me and it's relatively simple. Hence posting this to what seems to be the closest related issue with some momentum. PHEW.
Yes, because you're assuming that getContent()
returns something that implements Multipart
, and in this case it does not (IMAPInputStream
extends InputStream
).
Your code needs to account for this possibility.
The object returned by getContent
depends on the message type. It will only be Multipart if the message type is multipart. You could do an if check to look at the MIME type...
if(messages[j].getContentType().equals("multipart")) {
//Do your cast and stuff
} else {
//This message isn't a multipart message, maybe just skip it.
}
Of course that involves the use of magic strings. A more sophisticated solution would be to look into the DataHandler API and use the getDataHandler()
method on the message. Unfortunately I don't know much about that API.
精彩评论