Wednesday, September 12, 2012

Websphere and OSGi woes with Java mail/Commons email attachments

Ever faced below issues sending emails in web/enterprise applications with OSGI framework deployed in Websphere?  Such an easy and straight forward logic which works everywhere else in all other application servers like Tomcat, Jboss and Weblogic but only fails in Websphere. Spent some time figuring out this and thought of sharing the solution I found to help others.


  • Not able to send emails with attachments and facing error like no object DCH for MIME type */*
  • Not able to send attachments but only email
  • Error like : javax.mail.messagingexception java.net.sockettimeoutexception read timed out
Luckily we have solutions for these issues. In my case, I had a custom OSGi bundle which makes use of mail-activation-wrapper-1.0 and commons-email-1.2 bundles in same OSGi container to send emails with attachments. When the ear containing this deployed in Websphere it started failing with mime type not finding error. Also found other two errors given above in the fixing process. Finally could able to fix this following simple steps given below.

To start with, it is required to temporarily change class loader to point to the Session class loader of javax.mail as shown below. Also, make sure to reset it back using finally block.


public void sendMail(){

ClassLoader tcl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(javax.mail.Session.class.getClassLoader());
// Call java mail or commons email API...

} finally {
Thread.currentThread().setContextClassLoader(tcl);
}
}


Next step is to manually add mime types to MailCommandCap object. Here, the OSGi bundle which calls Java mail API,  which in turn makes use of javax.activation, fails to locate META-INF/mailcap resources bundled as part of mail bundle resulting in UnsupportedDataTypeException.


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("multipart/mixed;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
CommandMap.setDefaultCommandMap(mc);

Endorsed Approach

The other easiest but not so clean approach is to add "endorsed" folder in websphere/appserver/java/jre/lib and place the activation and mail jars there. This would be better in case if java class modification is not possible or required.

Hope this helps!