JavaJavaMail More Efficiently

JavaMail More Efficiently

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

This article follows an exchange of emails with reader Daniel Dekanski. Daniel had a simple question: “how to find new emails in a POP3 mailbox with JavaMail?” He had noticed that his regular email client was significantly faster than JavaMail.

After a brief exchange of ideas, Daniel Dekanski found the solution. This article will explain the background and the solution. Thanks to Daniel for allowing me to share the solution with you.

What is the problem?

JavaMail is a generic API for email clients. Sun modelled JavaMail around the IMAP4 protocol. Unfortunately most email servers are configured for the older and comparatively simpler POP3 protocol.

The most significant difference between the two protocols is the role of the server. With IMAP4, the mailbox resides on the server. IMAP4 manages server-based folders, flags, notifications, and more. It is popular on Intranets (the mailbox is easier to backup) and with mobile workers (the mailbox is accessible from different workstations).

In contrast POP3 is very limited and only offers to download emails from the server. It is popular with ISPs because it reduces the load on the server.

Since JavaMail was modelled around IMAP4, it is not very efficient with POP3 unless special care is taken. Specifically to search for new emails, a naive JavaMail client does this:

  • connect to the mail server;
  • download the first email headers;
  • test if the mail is new;
  • download the second email headers;
  • test if the mail is new;
  • download the third email headers;
  • test if the mail is new;
  • and so on.

And so on. Assuming a typical header is between 1 and 2K, that’s more than 1M to download for every 1000 emails in the mailbox. If only a handful of those emails are new, this is very inefficient. On a shared connection (or even worse, a dial-up connection), this method is unacceptably slow.

Turning to identifiers

POP3 offers a better solution through UID (unique identifier). Regular email clients exploit UIDs but JavaMail won’t, unless it is explicitly told to.

The server assigns a different UID to every email. By definition, a new email has a new UID. To find new emails, the client retrieves only those emails with a new UID. The trick is that UID are small (10 to 20 bytes) so download a thousand of them is instantaneous.

How does the client know if a UID is new? JavaMail cannot help, your client will need to keep a list of known UIDs. The scenario becomes:

  • connect to the mail server;
  • download the list of UID on the server;
  • compare with the local list;
  • download first new email;
  • download second new email;
  • and so on.

The major difference with the previous scenario is that the client downloads new emails only. With JavaMail, the scenario looks like Listing 1.

Listing 1. efficiently collecting new messages

File file = new File("uids.txt");
UIDStore uids = new UIDStore();
uids.load(file);
URLName url = new URLName("pop3",
                          parameters[0],
                          110,
                          "",
                          parameters[1],
                          parameters[2]);
Session session = Session.getDefaultInstance(System.getProperties(),null);
Store store = session.getStore(url);
store.connect();
POP3Folder inbox = (POP3Folder)store.getFolder("INBOX");
inbox.open(Folder.READ_WRITE);
FetchProfile profile = new FetchProfile();
profile.add(UIDFolder.FetchProfileItem.UID);
Message[] messages = inbox.getMessages();
inbox.fetch(messages,profile);
for(int i = 0;i < messages.length;i++)
{
   String uid = inbox.getUID(messages[i]);
   if(uids.isNew(uid))
   {
      System.out.print(i);
      System.out.print(". ");
      System.out.println(inbox.getMessage(i + 1).getSubject());
   }
}
System.out.println("Done.");
uids.store(file);

UIDStore in listing 1 is a small class that manages the local list of UID, it is available with the source code. The interesting aspect, as far as JavaMail is concerned, is the FetchProfile objects which requests an efficient download of UIDs (if you request any additional information, JavaMail downloads the headers).

The code compares local and remote UIDs to print the subject of new emails only. Printing the subject requires downloading full headers.

Be warned that this technique depends on Sun POP3Folder which may not be available in every implementation of JavaMail.

To test this technique for yourself, download the complete code.

Benoît Marchal is a Belgian writer and consultant. He is the author of XML by Example and other XML books.
He works mostly on e-commerce, XML and Java.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories