在我看来,没有防弹方法用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();
}
然后有可能在启动收听者和获取未读消息之间到达新的电子邮件,并且它将被读取两次。
如果我在从搜索中获取未读消息后更改它并添加侦听器,则有可能在获取未读消息之后但在添加侦听器之前新电子邮件将到达,因此它将被遗漏!
有这个问题的解决方案吗?
打开文件夹,处理文件夹中的所有消息,并检查新消息是否已到达(消息计数已增加)。如果是这样,循环。如果不是,则添加侦听器,然后等待新消息(例如,通过调用idle方法)。
了解其工作原理的关键部分是了解何时允许服务器通知客户端新消息,以及何时JavaMail将看到这些通知。在获取消息数量和添加侦听器之间,JavaMail将不会看到任何新消息通知。当您执行允许JavaMail查看通知的操作时,侦听器将就位。
JavaMail FAQ包括code example。
我有一个类似的问题。这是我根据比尔的答案制定的(对于那些正在寻找完整例子的人):
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();
}
}
}