java mail 實現郵件的推送
阿新 • • 發佈:2018-12-28
今天在做郵件的推送功能,即當郵件伺服器接收到新郵件時,客戶端這邊可以立即接收到。
思路:利用 Java Mail IMAP IDLE 去實現此功能
剛開始利用 folder.idle()去實現,程式碼如下,但出現一個問題,接收到新郵件之後,會自動斷開監聽。
IMAPFolder folder = (IMAPFolder)store.getFolder("INBOX"); folder.open(Folder.READ_WRITE); folder.addMessageCountListener(new MessageCountAdapter() { @Override public void messagesAdded(MessageCountEvent e) { super.messagesAdded(e); Message[] msgs = e.getMessages(); for(int i=0;i<msgs.length;i++){ try { Log.e("add 郵件","add 郵件主題"+msgs[i].getSubject()); } catch (MessagingException e1) { e1.printStackTrace(); } } } @Override public void messagesRemoved(MessageCountEvent e) { super.messagesRemoved(e); Message[] msgs = e.getMessages(); for(int i=0;i<msgs.length;i++){ try { Log.e("remove 郵件","remove 郵件主題"+msgs[i].getSubject()); } catch (MessagingException e1) { e1.printStackTrace(); } } } }); folder.idle(true);
檢視官方文件:
Google翻譯:與idle()類似,但如果一次為真,則在第一次通知後中止IDLE命令,以允許呼叫者同步處理任何通知。
然後我就用folder.idle()去替代folder.idle(true),但貌似還是沒起作用,下面是idle()方法的介紹
Google翻譯:如果伺服器支援,則使用IMAP IDLE命令(請參閱RFC 2177)進入空閒模式,以便伺服器可以傳送未經請求的新訊息到達等通知,而無需客戶端不斷輪詢伺服器。 使用適當的偵聽器來通知新訊息或其他事件。 當另一個執行緒(例如,偵聽器執行緒)需要為該資料夾發出IMAP命令時,將終止空閒模式並返回此方法。 通常,呼叫者將在迴圈中呼叫此方法。
mail.imap.minidletime屬性在從此方法返回之前強制執行最小延遲,以確保其他執行緒有機會在呼叫者再次呼叫此方法之前發出命令。 預設延遲為10毫秒。
最後如何解決的:
利用IdleManager迅速解決了此問題(查閱了官網文件)
ExecutorService es = Executors.newCachedThreadPool(); final IdleManager idleManager = new IdleManager(session, es); IMAPFolder folder = (IMAPFolder)store.getFolder("INBOX"); folder.open(Folder.READ_WRITE); folder.addMessageCountListener(new MessageCountAdapter() { @Override public void messagesAdded(MessageCountEvent e) { super.messagesAdded(e); Folder folder = (Folder)e.getSource(); Message[] msgs = e.getMessages(); for(int i=0;i<msgs.length;i++){ try { Log.e("add 郵件","add 郵件主題"+msgs[i].getSubject()); } catch (MessagingException e1) { e1.printStackTrace(); } } try { idleManager.watch(folder); } catch (MessagingException e1) { e1.printStackTrace(); } } @Override public void messagesRemoved(MessageCountEvent e) { super.messagesRemoved(e); Message[] msgs = e.getMessages(); for(int i=0;i<msgs.length;i++){ try { Log.e("remove 郵件","remove 郵件主題"+msgs[i].getSubject()); } catch (MessagingException e1) { e1.printStackTrace(); } } } }); idleManager.watch(folder);
目前此方法測試良好,但可能會出現斷線重連的狀況,IMAP指出30分鐘內無任何響應,會自動斷開連線,所以這個問題我們也得重視。