Search code examples
c#imapgmail-imapimapx

C# ImapX 2 email check code seems very slow


I am using ImapX 2 for my C# program to check for emails in Gmail account, but the whole process seems to take too much time, I'll explain in the code:

public static string checkForSubject() {
    ImapX.ImapClient client = new ImapX.ImapClient();
    client.Port = 993;
    client.UseSsl = true;
    client.Host = "imap.gmail.com";
    if (client.Connect()) {
        client.Login(Constants.EMAIL_SENDER, Constants.EMAIL_SENDER_PASSWORD);
        var messages = client.Folders.Inbox.Search("ALL"); // THIS LINE takes like 5-10 seconds to complete
        foreach (var item in messages) {
            if (item.Subject.StartsWith("HELLO_")) {
                string s = item.Subject;
                return s;
            }
        }
    }
    return null;
}

Is there something wrong with my code, or that is normal for IMAP access?


Solution

  • Well, you are asking for the UIDs or indexes of ALL of the messages in the folder. If the folder has a lot of messages and the IMAP server does not support the ESEARCH extension (and/or ImapX doesn't take advantage of the ESEARCH extension), then the server will send back a massive wall of text that can take a long time to transmit.

    The wall of text I'm referring to would look something like this:

    * SEARCH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ... 9999 10000
    

    You'd get one number per message.

    With ESEARCH, you'd get:

    * ESEARCH 1:10000
    

    But that's kind of beside the point because it looks like ImapX will download all of the matching messages, which in your case is ALL of the messages in the folder.

    Your search is also extremely inefficient. If you just want messages that start with "HELLO_", you could do this instead:

    var messages = client.Folders.Inbox.Search("SUBJECT HELLO_");
    foreach (var item in messages) {
        if (item.Subject.StartsWith("HELLO_")) {
            string s = item.Subject;
            return s;
        }
    }
    

    You still have to retain the item.Subject.StartsWith() check since IMAP does not have the ability to check that a string starts with or ends with a string, it just does a "contains" type search.

    But this search query will return far fewer matches which means ImapX will download far fewer messages which means it should be a lot faster.

    Unfortunately, it's still very inefficient for what you are doing, because all you care about is the subject string and not the whole message.

    I'm not familiar enough with ImapX to make this more efficient, but if you were to use MailKit, for instance, you could do this:

    client.Inbox.Open (FolderAccess.ReadOnly);
    var uids = client.Inbox.Search (SearchQuery.SubjectContains ("HELLO_"));
    if (uids.Count > 0) {
        var summaries = client.Inbox.Fetch (uids, MessageSummaryItems.Envelope);
        foreach (var summary in summaries) {
            if (summary.Envelope.Subject.StartsWith ("HELLO_"))
                return summary.Envelope.Subject;
        }
    }
    

    Hope that helps.