8 Replies Latest reply: Apr 11, 2012 12:54 PM by bshannon RSS

    Fetching email with attachments in Tomcat

    928796
      I'm trying to process emails with attachments using following code and it works fine in standalone java application, but when I run this code on Tomcat it treates all messages as not multipart. Class of all contents got from messages is SharedByteArrayInputStream.
      I'm using jdk1.6.0_27 and javamail1_4_5
      I put mail.jar in WEB-INF/lib of my war.

      Can anyone help my how to deal with this? What's wrong?



      package test;
      import java.util.Arrays;
      import java.util.List;
      import java.util.Properties;
      import javax.mail.Folder;
      import javax.mail.Message;
      import javax.mail.MessagingException;
      import javax.mail.Multipart;
      import javax.mail.Session;
      import javax.mail.Store;
      public class Main {
      private static Store store;
      private static Folder folder;
      /**
      * @param args
      * @throws Exception
      */
      public static void main(String[] args) throws Exception {
      try {
      List<Message> messages = getMessages("...", "...", "...");
      for (Message mess : messages) {
      System.out.println(mess.getSentDate());
      Object content = mess.getContent();
      if (content instanceof Multipart) {
      System.out.println("miltipart");
      } else {
      System.out.println("plain");
      }
      }
      } finally {
      close();
      }
      }
      public static List<Message> getMessages(String host, String userName, String password) throws Exception {
      if (store != null || folder != null) {
      throw new IllegalStateException("There are open and closed messages exist");
      }
      // create empty properties
      Properties props = new Properties();
      // get session
      Session session = Session.getDefaultInstance(props, null);
      try {
      // get the store
      store = session.getStore("pop3");
      store.connect(host, userName, password);
      // get folder
      folder = store.getFolder("INBOX");
      folder.open(Folder.READ_ONLY);
      // get directory
      return Arrays.asList(folder.getMessages());
      } catch (MessagingException e) {
      throw new Exception("Exception while mail receiving ", e);
      }
      }
      public static void close() throws MessagingException {
      // close connection
      if (folder != null) {
      folder.close(false);
      }
      if (store != null) {
      store.close();
      }
      folder = null;
      store = null;
      }
      }
        • 1. Re: Fetching email with attachments in Tomcat
          bshannon
          Most likely Tomcat is not setting the thread's context class loader correctly,
          causing the JAF implementation in JDK 6 to be unable to find the mailcap
          configuration file in the mail.jar file. There are two workarounds:

          1. Put the mail.jar file in Tomcat's lib directory instead of in the application.
          2. Re: Error running SendMail when launch application from JNI
          • 2. Re: Fetching email with attachments in Tomcat
            928796
            The first variant didn't work for me.
            When I put such string you mentioned in second variant in my servlet listener which initializes the application it didn't work, but when I put it to my class which deals with emails it work.

            Thank you!
            • 3. Re: Fetching email with attachments in Tomcat
              928796
              But I found another interesting issue.
              When I run my application everything works fine on first iteration. According to my code I get default instance of Session, get Store, get Folder and at last getMessages. After processing messages I close folder and store.
              But if I don't restart my application and try to get messages again all of the SAME messages became plain (SharedByteArrayInputStream) again (as it was earlier).
              If I restart my application first iteration works fine and others fails.
              In both iterations used the same instance of class where I put Thread.currentThread().setContextClassLoader(BaseEmailService.class.getClassLoader());

              What I must reinitialize to make it works on each iteration?
              • 4. Re: Fetching email with attachments in Tomcat
                bshannon
                If you print out the class loader, is it the same value on both cases? If so, I have no idea what's wrong.
                If not, check to make sure the workaround code is being executed in both cases.
                • 5. Re: Fetching email with attachments in Tomcat
                  928796
                  Output of the classloader is overriden and doesn't answer on question if there are the same. But System.identityHashCode returns the same value in these two cases and when I try to save the instance of the first class loader and then compare to second using == it returns true. So I realized that classloaders are the same.
                  But problem is still exists ((
                  • 6. Re: Fetching email with attachments in Tomcat
                    bshannon
                    I don't understand why it would work once and not again.
                    • 7. Re: Fetching email with attachments in Tomcat
                      928796
                      First request to tomcat is being processed by thread which works correctly. If second request is being processed by the same thread it also works correctly. But if it is being handled by another thread the issue as I mentioned above appears.
                      If I put workaround line in the first line of MY! code wich thread executes everithing works fine. But If I put this line in the first line of method of the second class involved in processing (but knows nothing about emails) it doesn't work.
                      My class which deals with email is fifth in processing queue and of cource it doesn't work either (I mean works only on first iteration).
                      • 8. Re: Fetching email with attachments in Tomcat
                        bshannon
                        You're setting the context class loader for the thread, so you need to be sure to put it in
                        a place where it will be done for every thread.