0 votes

I need to configure an windows service app to read a shared mailbox, at a periodicity, for ex: say every 1 hr. So I wanted to see if it is possible to read only the mails from the mailbox, that have arrived in the last 1 hr. And repeat the same every hour. Say, when the job runs at 2PM, it reads only the mails from 1PM to 2PM server time, and when it runs at 3PM, it reads those from 2PM to 3PM. I want to avoid having to read all mails each time, as the size of mails is likely to be huge and also it is not required to read all each time. Also, as this shared mailbox is used by a function team for their communication, I cannot delete or move mails from the inbox.

Pls let me know how this can be done.

by (210 points)

1 Answer

+1 vote

As the mailbox is used by other team members you can't relay on \SEEN flag (IMAP server tracks read/unread messages using this flag).

You'll need to use Unique IDs (UIDs) to track which message you have already processed and which are new.

UID in IMAP are assigned in incremental order - new messages always have higher UIDs than previous ones.

You only need to remember the newest (greatest) UID that was downloaded during a previous session. On the next session you need to search IMAP for UIDs that are greater than the one remembered.

You'll need to create a class that stores information about the last application run:

internal class LastRun
{
    public long UIDValidtiy { get; set; }
    public long LargestUID { get; set; }
}

...and two methods that store and load this class from storage:

private void SaveThisRun(LastRun run)
{
    // Your code that saves run data.
}

private LastRun LoadPreviousRun()
{
    // Your code that loads last run data (null on the first run).
}

Here's the the full code that processes new messages:

LastRun last = LoadPreviousRun();

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap.example.com"); 
    imap.UseBestLogin("user", "password");

    FolderStatus status = imap.SelectInbox();

    List<long> uids;
    if (last == null || last.UIDValidtiy != status.UIDValidity)
    {
        uids = imap.GetAll();
    }
    else
    {
        uids = imap.Search().Where(
            Expression.UID(Range.From(last.LargestUID)));
        uids.Remove(largestUID);
    }

    foreach (long uid in uids)
    {
        var eml = imap.GetMessageByUID(uid);
        IMail email = new MailBuilder()
            .CreateFromEml(eml);

        Console.WriteLine(email.Subject);
        Console.WriteLine(email.Text);

        LastRun current = new LastRun
        {
            UIDValidtiy = status.UIDValidity,
            LargestUID = uid
        };
        SaveThisRun(current);
    }
    imap.Close();
}

You can find more information here:
https://www.limilabs.com/blog/get-new-emails-using-imap

by (301k points)
...