【问题标题】:Different results between IMAP requestIMAP 请求之间的不同结果
【发布时间】:2016-08-10 09:51:28
【问题描述】:

我和我的团队编写了一个邮件组件,供其他团队在我们的应用程序中使用。该组件旨在允许他们使用自定义搜索条件下载电子邮件。目前使用的是使用IMAP protocol 在 Gmail 帐户的一系列日期之间进行邮件搜索。直到 2016 年 4 月 4 日上午 6:00 GMT+1,它一直正常工作,只下载范围内的电子邮件。但是,从格林威治标准时间+1 上午 8:00 开始,服务器的响应突然发生了变化,它开始返回整个 INBOX 文件夹!

重复最初的测试,我们发现我们收到的是整个 INBOX 文件夹,而不是范围内的那些。在对 IMAP 请求进行了一些研究之后,Gmail 似乎在某些条件下改变了返回的电子邮件数量:

  • 当“开始日期”SearchTerm 有一个 ComparisonTerm.GT 术语时,
  • 当“结束日期”SearchTerm 有一个 ComparisonTerm.LE 术语时

在这两种情况下,Gmail 的 IMAP 服务器都会返回文件夹中的所有电子邮件。相反,作为一个例子,雅虎的 IMAP 服务器只返回那些符合给定条件的电子邮件。

我们向他们开了一张票,询问他们的反应是否有任何变化,但他们回答说他们没有改变任何东西。当然,没有办法证明(我们还没有时间机器)。

由于我们对这种意外行为产生了巨大影响,因此我们决定进一步调查,并创建了一个简单的邮件客户端,以使用来自不同 IMAP 服务器的不同条件组合下载邮件。

this link's 程序开始,我们添加了与其他程序检查的功能,但更改了库以满足我们的 javax.mail 版本 1.5.5。因此,我们避免了不同的实现行为。

代码附在下面:

package gmail;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.search.AndTerm;
import javax.mail.search.ComparisonTerm;
import javax.mail.search.ReceivedDateTerm;
import javax.mail.search.SearchTerm;

public class JavaMailTest {
    
    public static void main(String[] args) {
        
        JavaMailTest testClient=new JavaMailTest();
        
        //Yahoo
        //SEARCH SINCE 3-Apr-2016 BEFORE 7-Apr-2016 ALL
        testClient.performTest(testClient.getYahooImapProps(),ComparisonTerm.GE,ComparisonTerm.LT);
        //Gmail
        //SEARCH SINCE 3-Apr-2016 BEFORE 7-Apr-2016 ALL
        testClient.performTest(testClient.getGmailImapProps(),ComparisonTerm.GE,ComparisonTerm.LT);
        //Yahoo
        //SEARCH SINCE 3-Apr-2016 OR BEFORE 7-Apr-2016 ON 7-Apr-2016 ALL
        testClient.performTest(testClient.getYahooImapProps(),ComparisonTerm.GE,ComparisonTerm.LE);
        //Gmail
        //SEARCH SINCE 3-Apr-2016 OR BEFORE 7-Apr-2016 ON 7-Apr-2016 ALL
        testClient.performTest(testClient.getGmailImapProps(),ComparisonTerm.GE,ComparisonTerm.LE);
        //Yahoo
        //SEARCH NOT ON 3-Apr-2016 SINCE 3-Apr-2016 BEFORE 7-Apr-2016 ALL
        testClient.performTest(testClient.getYahooImapProps(),ComparisonTerm.GT,ComparisonTerm.LT);
        //Gmail
        //SEARCH NOT ON 3-Apr-2016 SINCE 3-Apr-2016 BEFORE 7-Apr-2016 ALL
        testClient.performTest(testClient.getGmailImapProps(),ComparisonTerm.GT,ComparisonTerm.LT);
        //Yahoo
        //SEARCH NOT ON 3-Apr-2016 SINCE 3-Apr-2016 OR BEFORE 7-Apr-2016 ON 7-Apr-2016 ALL
        testClient.performTest(testClient.getYahooImapProps(),ComparisonTerm.GT,ComparisonTerm.LE);
        //Gmail
        //SEARCH NOT ON 3-Apr-2016 SINCE 3-Apr-2016 OR BEFORE 7-Apr-2016 ON 7-Apr-2016 ALL
        testClient.performTest(testClient.getGmailImapProps(),ComparisonTerm.GT,ComparisonTerm.LE);

    }

    public int performTest(Properties props, int startTermCondition, int endTermCondition)
    {
        try {
            Session session = Session.getDefaultInstance(props, null);
            Message[] totalMessages = null;

            Store store = session.getStore(props.getProperty("protocol"));
            store.connect(props.getProperty("mail.imap.host"), props.getProperty("account"), props.getProperty("pass"));
            Folder inbox = store.getFolder("inbox");
            inbox.open(Folder.READ_ONLY);


            SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd"); 
            Date startDate = ft.parse("2016-04-03");
            Date endDate = ft.parse("2016-04-07");

            System.out.println("Testing email account: <"+props.getProperty("account")+"> with startDate: <" + startDate + "> (ComparisonTerm."+
                    getConditionText(startTermCondition)+") and endDate: <" + endDate+"> (ComparisonTerm."+getConditionText(endTermCondition)+")");

            Message[] messages = inbox.getMessages();

            if (messages != null && messages.length > 0) {
                SearchTerm startDateTearm = 
                        new ReceivedDateTerm(startTermCondition, startDate);

                SearchTerm endDateTerm = 
                        new ReceivedDateTerm(endTermCondition, endDate);

                SearchTerm andTerm = new AndTerm(startDateTearm, endDateTerm); 

                totalMessages = inbox.search(andTerm);
                if(totalMessages.length > 0){
                    System.out.println("Found "+totalMessages.length+" matching messages (Total messages in folder: "+messages.length+")");
                }

                /*for (int i = 0; i < totalMessages.length; i++) {
                    System.out.println(totalMessages[i].getReceivedDate() + " --> Mail Subject:- " + totalMessages[i].getSubject());

                }*/
                //First message
                int currentMessage=0;
                System.out.println("First Message: "+totalMessages[currentMessage].getReceivedDate() + " --> Mail Subject: " + totalMessages[currentMessage].getSubject().substring(0, 5));
                //Last message
                currentMessage=totalMessages.length-1;
                System.out.println("Last Message:  "+totalMessages[currentMessage].getReceivedDate() + " --> Mail Subject: " + totalMessages[currentMessage].getSubject().substring(0, 5));
            }


            inbox.close(true);
            store.close();
            return totalMessages.length;

        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }

    }
    
    public static String getConditionText(int condition)
    {
        String returnValue="";
        switch (condition) {
        case ComparisonTerm.EQ:
            returnValue="EQ";
            break;
        case ComparisonTerm.GE:
            returnValue="GE";
            break;
        case ComparisonTerm.GT:
            returnValue="GT";
            break;
        case ComparisonTerm.LE:
            returnValue="LE";
            break;
        case ComparisonTerm.LT:
            returnValue="LT";
            break;
        case ComparisonTerm.NE:
            returnValue="NE";
            break;
        default:
            returnValue="Error";
            break;
        }
        return returnValue;
    }
    
    public Properties getYahooImapProps()
    {
        Properties props = new Properties();
        //Yahoo
        String imapServer="imap.mail.yahoo.com";
        String imapPort="993";
        String account="********@yahoo.es";
        String pass="*********";
        
        props.setProperty("mail.imap.host", imapServer);
        props.setProperty("mail.imap.port", imapPort);
        props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.setProperty("mail.imap.auth", "true");
        props.setProperty("account", account);
        props.setProperty("pass", pass);
        props.setProperty("protocol", "imaps");
        
        return props;
        
    }

    public Properties getGmailImapProps()
    {
        Properties props = new Properties();
        //Gmail
        String imapServer="imap.gmail.com";
        String imapPort="143";
        String account="******@gmail.com";
        String pass="********";
        
        props.setProperty("mail.imap.host", imapServer);
        props.setProperty("mail.imap.port", imapPort);
        /*props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.setProperty("mail.imap.auth", "true");*/
        props.setProperty("account", account);
        props.setProperty("pass", pass);
        props.setProperty("protocol", "imap");
        
        return props;
    }

}

为了让程序输出更清晰,我在第一个方法输出之前添加了请求:

  //SEARCH SINCE 3-Apr-2016 BEFORE 7-Apr-2016 ALL
  Testing email account: <*********@yahoo.es> with startDate: <Sun Apr 03 00:00:00 CEST 2016> (ComparisonTerm.GE) and endDate: <Thu Apr 07 00:00:00 CEST 2016> (ComparisonTerm.LT)
  Found 5 matching messages (Total messages in folder: 78)
  First Message: Mon Apr 04 23:14:22 CEST 2016 --> Mail Subject: Aviso
  Last Message:  Tue Apr 05 00:48:00 CEST 2016 --> Mail Subject: Alter
  //SEARCH SINCE 3-Apr-2016 BEFORE 7-Apr-2016 ALL
  Testing email account: <*********@gmail.com> with startDate: <Sun Apr 03 00:00:00 CEST 2016> (ComparisonTerm.GE) and endDate: <Thu Apr 07 00:00:00 CEST 2016> (ComparisonTerm.LT)
  Found 92 matching messages (Total messages in folder: 20138)
  First Message: Sun Apr 03 04:08:47 CEST 2016 --> Mail Subject: Tu es
  Last Message:  Wed Apr 06 22:12:45 CEST 2016 --> Mail Subject: ¿Quie
  //SEARCH SINCE 3-Apr-2016 OR BEFORE 7-Apr-2016 ON 7-Apr-2016 ALL
  Testing email account: <*********@yahoo.es> with startDate: <Sun Apr 03 00:00:00 CEST 2016> (ComparisonTerm.GE) and endDate: <Thu Apr 07 00:00:00 CEST 2016> (ComparisonTerm.LE)
  Found 5 matching messages (Total messages in folder: 78)
  First Message: Mon Apr 04 23:14:22 CEST 2016 --> Mail Subject: Aviso
  Last Message:  Tue Apr 05 00:48:00 CEST 2016 --> Mail Subject: Alter
  //SEARCH SINCE 3-Apr-2016 OR BEFORE 7-Apr-2016 ON 7-Apr-2016 ALL
  Testing email account: <*********@gmail.com> with startDate: <Sun Apr 03 00:00:00 CEST 2016> (ComparisonTerm.GE) and endDate: <Thu Apr 07 00:00:00 CEST 2016> (ComparisonTerm.LE)
  Found 20138 matching messages (Total messages in folder: 20138)
  First Message: Sat Sep 04 13:23:35 CEST 2004 --> Mail Subject: Gmail
  Last Message:  Tue Apr 19 10:09:06 CEST 2016 --> Mail Subject: El re
  //SEARCH NOT ON 3-Apr-2016 SINCE 3-Apr-2016 BEFORE 7-Apr-2016 ALL
  Testing email account: <*********@yahoo.es> with startDate: <Sun Apr 03 00:00:00 CEST 2016> (ComparisonTerm.GT) and endDate: <Thu Apr 07 00:00:00 CEST 2016> (ComparisonTerm.LT)
  Found 5 matching messages (Total messages in folder: 78)
  First Message: Mon Apr 04 23:14:22 CEST 2016 --> Mail Subject: Aviso
  Last Message:  Tue Apr 05 00:48:00 CEST 2016 --> Mail Subject: Alter
  //SEARCH NOT ON 3-Apr-2016 SINCE 3-Apr-2016 BEFORE 7-Apr-2016 ALL
  Testing email account: <*********@gmail.com> with startDate: <Sun Apr 03 00:00:00 CEST 2016> (ComparisonTerm.GT) and endDate: <Thu Apr 07 00:00:00 CEST 2016> (ComparisonTerm.LT)
  Found 20138 matching messages (Total messages in folder: 20138)
  First Message: Sat Sep 04 13:23:35 CEST 2004 --> Mail Subject: Gmail
  Last Message:  Tue Apr 19 10:09:06 CEST 2016 --> Mail Subject: El re
  //SEARCH NOT ON 3-Apr-2016 SINCE 3-Apr-2016 OR BEFORE 7-Apr-2016 ON 7-Apr-2016 ALL
  Testing email account: <*********@yahoo.es> with startDate: <Sun Apr 03 00:00:00 CEST 2016> (ComparisonTerm.GT) and endDate: <Thu Apr 07 00:00:00 CEST 2016> (ComparisonTerm.LE)
  Found 5 matching messages (Total messages in folder: 78)
  First Message: Mon Apr 04 23:14:22 CEST 2016 --> Mail Subject: Aviso
  Last Message:  Tue Apr 05 00:48:00 CEST 2016 --> Mail Subject: Alter
  //SEARCH NOT ON 3-Apr-2016 SINCE 3-Apr-2016 OR BEFORE 7-Apr-2016 ON 7-Apr-2016 ALL
  Testing email account: <*********@gmail.com> with startDate: <Sun Apr 03 00:00:00 CEST 2016> (ComparisonTerm.GT) and endDate: <Thu Apr 07 00:00:00 CEST 2016> (ComparisonTerm.LE)
  Found 20138 matching messages (Total messages in folder: 20138)
  First Message: Sat Sep 04 13:23:35 CEST 2004 --> Mail Subject: Gmail
  Last Message:  Tue Apr 19 10:09:06 CEST 2016 --> Mail Subject: El re

从这个结果我们可以说:

  • 雅虎会根据给定的 Java 条件返回适当数量的电子邮件。
  • Javamail 的请求可能太模棱两可了。
  • @Gmail:考虑到一些请求中的一堆条件......为什么你决定返回整个文件夹?
  • 为什么同一个请求会有不同的响应?
  • 谁在退回邮件?
  • 协议不是旨在使事物标准化而不是使事情变得更糟吗?

我们也尝试使用 Outlook 帐户,结果与 Gmail 相同。

【问题讨论】:

  • 协议通常旨在标准化,但这不一定是唯一的目标,有时也不是首要任务。有时它与实现的简单性相冲突,并且失败了。在日期搜索的情况下,IMAP 明确不指定时区处理,因此如果 SINCE 限制在服务器之间相差几个小时,这是允许的。当然,这不是您所看到的:我只提供评论,而不是答案。

标签: java gmail jakarta-mail imap email-client


【解决方案1】:

在我看来,这确实像是 Gmail 中的一个错误。我能够自己复制它。如果 Outlook.com 有同样的错误,我真的很惊讶。

为什么您认为请求不明确? IMAP 规范非常明确。

一些笔记...

【讨论】:

  • 我记得注意到 javamail OR 并想知道您正在解决什么错误。现在我发现这是一个错误,而不是解决方法;)
  • 我在 Google 的联系人已确认这是一个 Gmail 错误,很快就会修复。
【解决方案2】:

@比尔香农

我认为@popilla20k 认为请求模棱两可,因为当他使用“GT”AND“LE”searchTerm(andTerm)发出请求时,它被分解为,例如:

//自 2016 年 4 月 3 日起搜索 或之前 2016 年 4 月 7 日至 2016 年 4 月 7 日全部

我必须说,我在 4 月 6 日看到 Google 的行为发生了变化。几天前,我检索了所有满足“GT”和“LE”searchTerm 条件的邮件。 4 月 6 日之后,我看到 @popilla20k 显示的相同行为(使用 javamail 1.5.5)

即便如此,我认为子句 OR BEFORE 使第一个无效。它应该是 AND 子句,不是吗?无论如何,在 4 月 6 日之前的几天,同样的请求得到的答复与现在不同。

谢谢。

【讨论】:

  • 您误解了 IMAP SEARCH 语法。 OR 是前缀运算符,适用于其后的两个搜索词 - BEFORE 词和 ON 词。 OR 词与 SINCE 词结合使用多个搜索词的默认 AND 操作。
  • 你是对的。所以,我很清楚我们正在处理 Google 的 IMAP 错误。谢谢比尔。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多