IMAP请求之间的结果不同

2022-07-13 00:00:00 imap gmail email-client java jakarta-mail

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

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

  • 当";开始日期&SearchTermComparisonTerm.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条件,Yahoo会返回适当数量的电子邮件。
  • Javamail的请求可能过于含糊。
  • @Gmail:考虑到某些请求中的一堆条件...为什么您刚刚决定退还整个文件夹?
  • 为什么同一请求会有不同的响应?
  • 谁正确退回了邮件?
  • 协议的设计难道不是为了使事情标准化,而不是让事情变得更糟吗?

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


解决方案

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

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

几点注意事项...

  • 是否确实要使用Java Mail 1.5.5?您显示的搜索命令反映了1.5.3之前版本的JavaMail bug。
  • 您应该change Session.getDefaultInstance to Session.getInstance。
  • 您don't need the socket factory properties;只需将"mail.imap.ssl"设置为"true"即可。

相关文章