I have a requirement as a part of which i want to read incoming emails from outlook and then do some processing.I am using JavaMail API along with IMAP protocol to implement this.I have written a java class which reads email on messagesAdded event.
Its perfectly working fine with below code in single server environment, but when i deploy it to production where we have 2 servers i end up processing each email twice since the same code is deployed on both the servers,both try to read email once its received in the mailbox.
Below is the code snippet i am using to connect to mailbox and read emails:
try {
Properties props = System.getProperties();
// Get a Session object
Session session = Session.getInstance(props, null);
// session.setDebug(true);
// Get a Store object
Store store = session.getStore("imap");
// Connect
store.connect(argv[0], argv[1], argv[2]);
// Open a Folder
Folder folder = store.getFolder(argv[3]);
if (folder == null || !folder.exists()) {
System.out.println("Invalid folder");
System.exit(1);
}
folder.open(Folder.READ_WRITE);
// Add messageCountListener to listen for new messages
folder.addMessageCountListener(new MessageCountAdapter() {
public void messagesAdded(MessageCountEvent ev) {
Message[] msgs = ev.getMessages();
System.out.println("Got " + msgs.length + " new messages");
// Process incoming mail.
} catch (Exception ex) {
ex.printStackTrace();
}
Any suggestions on how should i restrict an email to be processed only once in multi server environment ?
Perhaps the simplest way to solve it is with a distributed lock; there are good libraries for that. But if you want an answer within javamail, then there are two ways.
First, you can use a Flag and call message.isSet() to check whether the other server has set the flag and then message.setFlags() to lock. Unfortunately that races. The race can be fixed with some unpretty hackery involving either two more flags or or an IMAP extension called condstore that javamail apparently doesn't support — setFlags() would need a new
longargument to set the flag only if the flags haven't changed since the client last noticed.Second, you can use a progression of mailboxes and move the messages though it. You need four mailboxes, namely the inbox and three others called perhaps "processing-a", "processing-b" and "processed". Server A processes all messages in "processing-a" and moves each to "processed" afterwards, B takes care of "processing-b". When each server is done with its "processing-foo", it looks for new messages in the inbox and calls moveMessages() to move one or a few messages atomically to its own mailbox. moveMessages() uses an IMAP extension called move to move messages atomically, and is supported by most servers, but not quite all.