打开邮箱时同步Javamail,读取现有邮件并启动MessageCountListener

时间:2015-05-05 16:01:29

标签: java synchronization javamail

在我看来,没有防弹方法可以使用Javamail打开IMAP邮箱,读取现有的未读邮件并添加MessageChangedListener事件监听器以读取后续新到货。

我写的应用程序必须只处理一次消息,并且绝不应该遗漏任何电子邮件。

这是听众:

public class EmailListener implements MessageCountListener {

    private final IncomingEmailProcessor processor;

    @Override
    public void messagesAdded(final MessageCountEvent event) {
        for (Message email : event.getMessages()) {
                processor.process(email);
        }
    }
}

如果我先添加侦听器,然后抓住所有未读消息:

Session session = javax.mail.Session.getInstance(imapProperties);
store = (IMAPStore) session.getStore(imapProtocol);
store.connect(imapHost, imapUser, imapPassword);
inbox = (IMAPFolder) store.getFolder("INBOX");
inbox.open(Folder.READ_WRITE);
inbox.addMessageCountListener(emailListener);
Message messages[] = inbox.search(
    new FlagTerm(new Flags(Flags.Flag.SEEN), false));
for (Message message : messages) {
    processor.process(message);
}
while (inbox.isOpen()) {
    inbox.idle();
}

然后有可能在启动监听器和获取未读消息之间到达新的电子邮件,并且它将被读取两次。

如果我在搜索后获取未读消息后更改它并添加侦听器,那么在获取未读消息之后但是在添加侦听器之前,新电子邮件可能会到达,因此会错过!

这个问题有解决方法吗?

2 个答案:

答案 0 :(得分:1)

打开文件夹,处理文件夹中的所有邮件,并检查新邮件是否已到达(邮件计数已增加)。如果是这样,循环。如果没有,添加监听器,然后等待新消息(例如,通过调用idle方法)。

了解其工作原理的关键部分是了解何时允许服务器通知客户端新消息,以及JavaMail何时会看到这些通知。在获取消息数量和添加侦听器之间,JavaMail将不会看到任何新消息通知。当您执行允许JavaMail查看通知的操作时,侦听器将就位。

JavaMail FAQ包含code example

答案 1 :(得分:1)

我有一个类似的问题。这是我根据比尔的答案(对于那些正在寻找完整示例的人)得出的结论:

 public static void loadUnreadEmails() throws MessagingException, IOException, SQLException {

    Store store = null;
    Properties props = new Properties();
    props.setProperty("mail.store.protocol", "imaps");
    try {

        Session session = Session.getInstance(props, null);
        store = session.getStore();
        store.connect("imap.gmail.com", EMAIL_ID,
                EMAIL_PASSWORD);
        Folder inbox = store.getFolder("INBOX");
        inbox.open(Folder.READ_WRITE);
        int msgCount;
        do {//go through all the unread emails in the inbox at least once
            msgCount = inbox.getMessageCount();//set how many messages are in the inbox when the array is created
            // Fetch unseen messages from inbox folder
            javax.mail.Message[] messages = inbox.search(
                    new FlagTerm(new Flags(Flags.Flag.SEEN), false));
            for (javax.mail.Message msg : messages) {
                //process emails here
                processEmail(msg);
            }
            //if a new message came in while reading the messages start the loop over and get all unread messages    
        } while (inbox.getMessageCount() != msgCount);
        //add listener
        inbox.addMessageCountListener(new MessageCountAdapter() {
            @Override
            public void messagesAdded(MessageCountEvent ev) {
                javax.mail.Message[] messages = ev.getMessages();
                for (javax.mail.Message msg : messages) {
                    //process emails here
                    processEmail(msg);
                }
            }
        });
        // wait for new messages
        while (inbox.isOpen()) {                
            //every 25 minutes poke the server with a inbox.getMessageCount() to keep the connection active/open
            ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
            final Runnable pokeInbox = () -> {
                try {
                    inbox.getMessageCount();
                } catch (MessagingException ex) {
                    //nothing doin'
                }
            };
            scheduler.schedule(pokeInbox, 25, TimeUnit.MINUTES);
            ((IMAPFolder) inbox).idle();
        }
    } catch (FolderClosedException e) {
        e.printStackTrace();
        System.out.println("error connection was dropped");
        if (store != null) {
            store.close();
        }
        loadUnreadEmails();//restarts listening for email if the connection times out
    } finally {
        if (store != null) {
            store.close();
        }
    }
}