ews-managed-api icon indicating copy to clipboard operation
ews-managed-api copied to clipboard

SearchFilter.IsGreaterThan returns same items for DateTimeReceived with Milliseconds DateTimePrecision

Open Misiu opened this issue 7 years ago • 6 comments

Hi there, I'm trying to create mechanism that will read all unread mails from certain mailbox. In each cycle I'm getting 10 emails from that mailbox.

ItemView view = new ItemView(10)
{
    PropertySet = new PropertySet(ItemSchema.Id, EmailMessageSchema.DateTimeReceived)
};

view.OrderBy.Add(EmailMessageSchema.DateTimeReceived, SortDirection.Ascending);

SearchFilter receivedAfterFilter = new SearchFilter.IsGreaterThan(EmailMessageSchema.DateTimeReceived, lastSyncDate ?? DateTime.Now.AddYears(-1));
SearchFilter notReadFilter = new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false);
var sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And)
{
    receivedAfterFilter,
    notReadFilter
};

I've set DateTimePrecision = DateTimePrecision.Milliseconds so DateTimeReceived contains milliseconds.

If last email in my results has DateTimeReceived= 2017-11-27 11:41:14.704 and I set that in my filter I get same email over and over.

My workaround is adding one millisecond like this: receivedAfterFilter = new SearchFilter.IsGreaterThan(EmailMessageSchema.DateTimeReceived, lastMailTime.Value.AddMilliseconds(1));

Below is fully working example showing my issue. I'm not native English speaker, so code will speak for itself.

public IEnumerable<EmailMessage> GetEmails(FolderId root, SearchFilter itemsFilter, ItemView view)
{
    foreach (Item item in _exchangeService.FindItems(root, itemsFilter, view))
    {
        if (item is EmailMessage mail)
        {
            Debug.WriteLine(mail.Id.UniqueId + " - " + mail.DateTimeReceived.ToString("yyyy-MM-dd HH:mm:ss.fff") + " - " + mail.Subject);
            yield return mail;
        }
    }
}

private void button3_Click(object sender, EventArgs e)
{
    var service = new ExchangeService(ExchangeVersion.Exchange2010_SP2)
    {
        Credentials = CredentialCache.DefaultNetworkCredentials,
        TraceEnabled = true,
        TraceFlags = TraceFlags.None, //All
        TraceEnablePrettyPrinting = true,
        Url = new Uri("https://mail.example.com/ews/exchange.asmx"),
        Timeout = Int32.MaxValue,
        DateTimePrecision = DateTimePrecision.Milliseconds
    };

    ItemView view = new ItemView(10)
    {
        PropertySet = new PropertySet(ItemSchema.Id, EmailMessageSchema.DateTimeReceived)
    };

    view.OrderBy.Add(EmailMessageSchema.DateTimeReceived, SortDirection.Ascending);

    SearchFilter receivedAfterFilter = new SearchFilter.IsGreaterThanOrEqualTo(EmailMessageSchema.DateTimeReceived, DateTime.Now.Date);
    SearchFilter notReadFilter = new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false);
    var sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And)
    {
        receivedAfterFilter,
        notReadFilter
    };

    var mailbox = new Mailbox("[email protected]");
    var folderId = new FolderId(WellKnownFolderName.Inbox, mailbox);

    DateTime? lastMailTime = null;

    bool more = true;

    while (more)
    {
        var emails = GetEmails(folderId, sf, view);
        int i = 0;
        foreach (var item in emails)
        {
            lastMailTime = item.DateTimeReceived;
            i++;
        }

        if (i == 0)
        {
            more = false;
        }
        else
        {
            //receivedAfterFilter = new SearchFilter.IsGreaterThan(EmailMessageSchema.DateTimeReceived, lastMailTime.Value);// this cause infinite loop
            receivedAfterFilter = new SearchFilter.IsGreaterThan(EmailMessageSchema.DateTimeReceived, lastMailTime.Value.AddMilliseconds(1));
            sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And)
            {
                receivedAfterFilter,
                notReadFilter
            };
        }
        Debug.WriteLine("END");
    }
}

I think this is a bug, because IsGreaterThan should return items except exact match (like in my case)

Misiu avatar Nov 27 '17 11:11 Misiu

That is interesting. I am curious though - what are you trying to accomplish here? It seems like you are trying to do some dateTime based paging or something. There might be a better way to accomplish this.

davster avatar Dec 30 '17 19:12 davster

I experienced the same issue, and also solved it with the +1 millisecond trick.

What I am doing is making a tool that iterates through emails in an inbox. I process 100 at a time, and I need to know which email to start with next time I run the tool. To do this I store the received date on the last email i retrieved, and then I search for all emails newer than this. If there is a better way to do this, please feel free to comment.

snarum avatar Apr 23 '18 13:04 snarum

@snarum my final workaround was to move processed emails into folder (called Imported for example). This way I don't care about that time and I'm sure I don't miss anything.

Misiu avatar Apr 23 '18 13:04 Misiu

More than 7 month but still not labeled and no assignee.

HamletHakobyan avatar Jul 10 '18 08:07 HamletHakobyan

I'm also seeing the same issue. Moving to a 'Processed' folder is good but I'm not in a position to that.

Has anyone had any other solutions?

murphypaj avatar Jul 26 '18 17:07 murphypaj

I understand, that this is not an issue of EWS Managed API, but how we can push this to EWS side to fix it?

HamletHakobyan avatar Jul 26 '18 18:07 HamletHakobyan