Yi EungJun 2014-11-06
Mailbox: Ignore duplicated email
If there is two emails with same id in mailbox, Yobi handles the first
one only. It occurs quite frequently because mail servers send an email
twice if the email has two addresses differ from each other: e.g.
yobi+my/proj@mail.com and yobi+your/proj@mail.com.

Warn if the older email was handled one hour or more ago. Because it is
quite long time so that possibly the ignored email is actually new one
which should be handled.

This feature is not necessary for some IMAP servers, like Gmail, which
drop duplicated emails.
@c96352a45975929b5199d02d141a244134d521fb
app/mailbox/EmailHandler.java
--- app/mailbox/EmailHandler.java
+++ app/mailbox/EmailHandler.java
@@ -23,7 +23,9 @@
 import com.sun.mail.imap.IMAPFolder;
 import com.sun.mail.imap.IMAPMessage;
 import info.schleichardt.play2.mailplugin.Mailer;
-import mailbox.exceptions.*;
+import mailbox.exceptions.IllegalDetailException;
+import mailbox.exceptions.MailHandlerException;
+import models.OriginalEmail;
 import models.Project;
 import models.Property;
 import models.User;
@@ -33,6 +35,7 @@
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.commons.mail.HtmlEmail;
+import org.joda.time.DateTime;
 import play.Logger;
 import play.api.i18n.Lang;
 import play.i18n.Messages;
@@ -166,7 +169,32 @@
                 return;
             }
         } catch (MessagingException e) {
-            play.Logger.warn("Failed to determine whether the email is auto-replied or not", e);
+            play.Logger.warn(
+                    "Failed to determine whether the email is auto-replied or not: " + msg, e);
+        }
+
+        try {
+            // Ignore the email if there is an email with the same id. It occurs
+            // quite frequently because mail servers send an email twice if the
+            // email has two addresses differ from each other: e.g.
+            // yobi+my/proj@mail.com and yobi+your/proj@mail.com.
+            OriginalEmail sameMessage =
+                    OriginalEmail.finder.where().eq("messageId", msg.getMessageID()).findUnique();
+            if (sameMessage != null) {
+                // Warn if the older email was handled one hour or more ago. Because it is
+                // quite long time so that possibly the ignored email is actually
+                // new one which should be handled.
+                if (sameMessage.getHandledDate().before(new DateTime().minusHours(1).toDate())) {
+                    String warn = String.format("This email '%s' is ignored because an email with" +
+                                    " the same id '%s' was already handled at '%s'",
+                            msg, sameMessage.messageId, sameMessage.getHandledDate());
+                    play.Logger.warn(warn);
+                }
+                return;
+            }
+        } catch (MessagingException e) {
+            play.Logger.warn(
+                    "Failed to determine whether the email is duplicated or not: " + msg, e);
         }
 
         InternetAddress[] senderAddresses;
app/models/OriginalEmail.java
--- app/models/OriginalEmail.java
+++ app/models/OriginalEmail.java
@@ -26,6 +26,7 @@
 import play.db.ebean.Model;
 
 import javax.persistence.*;
+import java.util.Date;
 
 @Entity
 @Table(uniqueConstraints = @UniqueConstraint(columnNames = {"resource_type", "resource_id"}))
@@ -49,6 +50,9 @@
     @Constraints.Required
     public String resourceId;
 
+    @Constraints.Required
+    private Date handledDate;
+
     public static OriginalEmail findBy(Resource resource) {
         return finder.where()
                 .eq("resourceType", resource.getType())
@@ -65,4 +69,14 @@
         this.resourceType = resource.getType();
         this.resourceId = resource.getId();
     }
+
+    @Override
+    public void save() {
+        handledDate = new Date();
+        super.save();
+    }
+
+    public Date getHandledDate() {
+        return handledDate;
+    }
 }
Add a comment
List