java.lang.ArrayIndexOutOfBoundsException at com.sun.mail.imap.MessageCache.getMessage(MessageCache.java:123)

I am reading emails from emailServer and saving them in database.I am using following code to read messages from folder("INBOX") on email server and retrieve messages corresponding to them but I am getting

"java.lang.ArrayIndexOutOfBoundsException: message number (621) out of bounds (620)
at com.sun.mail.imap.MessageCache.getMessage(MessageCache.java:123)
at com.sun.mail.imap.MessageCache.getMessageBySeqnum(MessageCache.java:153)
at com.sun.mail.imap.IMAPFolder.getMessageBySeqNumber(IMAPFolder.java:2795)
at com.sun.mail.imap.IMAPFolder.getMessagesByUID(IMAPFolder.java:1924)"

I am using javax.mail.1.4.4 , this issue is coming mainly when inbox is getting flooded .

Code used:

folder = store.getFolder("INBOX");

folder.open(Folder.READ_WRITE);
// messageUID is uid of last message I saved in DB

 Message messages[] = ((UIDFolder) folder).getMessagesByUID(messageUID + 1, UIDFolder.LASTUID);

I have done some research and found that messagecache is set for a folder as soon as it opens, lets assume it is set as 520( size of the folder). Whereas if any message arrives after message cache is set , then in last message sequence num exceeds total size of message cache and it throws an exception.

Can anybody let me know how to get absolute value of UId of the Last message in a folder or how to acquire a folder lock so that after cache is set , folder does not update the size of the folder.


Solution 1:

Interesting problem!

First, I think that this is a bug in javax mail. There should probably be a call to checkRange() in getMessageBySeqNumber(), or just a Math.min() with the vector size.

In any case, the issue is that the the code goes to the server to get the latest message count, but never updates the local messageCache. This means that the messageCache has out of date data compared to the method, yet the method still assumes that it is up to date… as you have seen hilarity ensures.

Now, how to avoid it until it is fixed?

Unfortunately, I think that you are stuck with the somewhat horrid workaround of doing something like:

folder = store.getFolder("INBOX");

folder.open(Folder.READ_WRITE);
// messageUID is uid of last message I saved in DB

/* I apologize for all of the kittens that this code is about to kill */
boolean getMessagesWorked = false;
do {
  try {
    Message messages[] = ((UIDFolder) folder).getMessagesByUID(messageUID + 1, UIDFolder.LASTUID);
    getMessagesWorked = true;
   } catch (ArrayIndexOutOfBoundsException e) {
     /* Doing this should force the internal messagesCache to get updated
      * Unfortunately, this is also somewhat racy, depending on just how
      * hard the mail folder is being hit */
      try {
       folder.getMessage(folder.getMessageCount());
      } catch (ArrayIndexOutOfBoundsException e) {
        /* There really isn't much you can do here, except try again.
         * the good news is that this should hardly ever happen!!
         * Good in this case is a relative term! */
      }
   }
} while (! getMessagesWorked);