Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EWS get count of unread emails from all folders

I'm trying to get number of unread emails from Exchange for specific user.

I'm able to get number of emails from Inbox like so:

SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
ItemView view = new ItemView(int.MaxValue);
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, sf, view);
int unreadCount = 0;
foreach (EmailMessage i in findResults)
    {
        unreadCount++;
    }
label1.Text = unreadCount.ToString();

This works great.
I'm also able to get all subfolders is Inbox:

FindFoldersResults findResults1 = service.FindFolders(
    WellKnownFolderName.Inbox,
    new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep });

foreach (Folder folder in findResults1.Folders)
{
    Console.WriteLine(folder.DisplayName);
}

Problem is that I'm not able to combine these two together.
I know that I can do nested foreach loop, but I would like to avoid that.

I found these question: Exchange Web Services (EWS) FindItems within All Folders, but it requires to at least use Outlook 2010 in order to create AllItems folder.

I know that I can create SearchFilterCollection, but how to add rules to it so that it will search for unread emails in Inbox and all subfolders?

EDIT:

This what I have tried to do so far:

private int getEmailCount()
{
    int unreadCount = 0;

    FolderView viewFolders = new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep, PropertySet = new PropertySet(BasePropertySet.IdOnly) };
    ItemView viewEmails = new ItemView(int.MaxValue) { PropertySet = new PropertySet(BasePropertySet.IdOnly) };
    SearchFilter unreadFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));

    FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, unreadFilter, viewEmails);
    unreadCount += findResults.Count();

    FindFoldersResults inboxFolders = service.FindFolders(WellKnownFolderName.Inbox, viewFolders);

    foreach (Folder folder in inboxFolders.Folders)
    {
        findResults = service.FindItems(folder.Id, unreadFilter, viewEmails);
        unreadCount += findResults.Count();
    }

    return unreadCount;
    }

Basically this works, but when I have created multiple subfolders it started to work very slow.
Instead of multiple queries can I do one to get same results?

like image 521
Misiu Avatar asked Oct 02 '12 09:10

Misiu


People also ask

How do I show the number of unread items including subfolders?

Click the Criteria button to open the Search Folder Criteria dialog box, next go to the More Choices tab, check the Only items that are option, select unread from right drop down list, and click the OK button.

How do you show the unread count of a folder including its subfolders in Outlook?

Start by creating a Search Folder. Then select the last option , "Create a custom search folder". Name it and click the Criteria button. In the "More Choices" tab, select the checkbox for "Only items that are" and select "unread" in the droplist.

How do I show unread emails in subfolders?

Right click your created Search Folder and choose “Show in Favorites” to more easily keep an eye on the Unread count. Select from which parent folder the Search Folder should count.


3 Answers

I've searched a bit and created this function:

    public void getEmailCount(Action<int> callback)
    {
        int unreadCount = 0;

        FolderView viewFolders = new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep, PropertySet = new PropertySet(BasePropertySet.IdOnly) };
        ItemView viewEmails = new ItemView(int.MaxValue) { PropertySet = new PropertySet(BasePropertySet.IdOnly) };
        SearchFilter unreadFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
        SearchFilter folderFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "AllItems"));

        FindFoldersResults inboxFolders = service.FindFolders(WellKnownFolderName.Root, folderFilter, viewFolders);

        if (inboxFolders.Count() == 0)//if we don't have AllItems folder
        {
            //search all items in Inbox and subfolders
            FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, unreadFilter, viewEmails);
            unreadCount += findResults.Count();

            inboxFolders = service.FindFolders(WellKnownFolderName.Inbox, viewFolders);
            foreach (Folder folder in inboxFolders.Folders)
            {
                findResults = service.FindItems(folder.Id, unreadFilter, viewEmails);
                unreadCount += findResults.Count();
            }
        }
        else //AllItems is avilable
        {
            foreach (Folder folder in inboxFolders.Folders)
            {
                FindItemsResults<Item> findResults = service.FindItems(folder.Id, unreadFilter, viewEmails);
                unreadCount += findResults.Count();
            }
        }

        callback(unreadCount);
    }

Basically it checks if we have AllItems folder avilable.
If YES then we do one, simple query that returns all unread messages.
If NO then we loop all folders inside Inbox. This is slower and depends on how many folders and levels we have.

Any fixes and improvements are welcome :)

like image 178
Misiu Avatar answered Oct 03 '22 15:10

Misiu


Not sure it's what you were looking for, but... Getting unread emails counts (inbox / draft etc.):

int x = Folder.Bind(yourService, WellKnownFolderName.Inbox).UnreadCount;
int y = Folder.Bind(yourService, WellKnownFolderName.Drafts).UnreadCount;
return x + y;

In this case, the service is called two times, but the calls are issued sequentially - not good enough.

Though, you can issue both requests at the same time and increase the response time of your app.

See this or any tutorial that explains how to instantiate two TPL tasks, send them to the task scheduler, wait for both (WaitAll()) to complete and, in the end, retrieve their results :)

And, if you want to get the email counts after applying some custom filters (not the trivial 'unread' filter), then make sure that your ItemView object is ItemView(1), not ItemView(int.MaxValue). Then, get the total count:

int n = findItemsResults.TotalCount;

See the docs for TotalCount property.

This way, the service response is quite small - it contains only one item, but it (the response) also carries the total count... That's what you want, right?

like image 29
turdus-merula Avatar answered Oct 03 '22 17:10

turdus-merula


Here is the code for fetching the total unread count of a mailbox.

  1. Find all folders with deep traversal
  2. Limit the set of properties for each folder to id, unreadcount, displayname (forinformational purpose)
  3. Some of the folders like calendars, contacts don't have this property so handle that case

Limitations with this code snippet:

  1. If the mailbox contains more than 1000 folders under Top of information store, then you will not get the complete total unread count
  2. To handle that case do finditems in a loop until there are no more items with same logic

This makes only one findfolders call and work on the results.

public static int GetTotalUnreadCount(ExchangeService ewsConnector)
{
    int pagedView = 1000;
    FolderView fv = new FolderView(pagedView) { Traversal = Microsoft.Exchange.WebServices.Data.FolderTraversal.Deep };
    fv.PropertySet = new PropertySet(BasePropertySet.IdOnly, FolderSchema.UnreadCount, FolderSchema.DisplayName);

    FindFoldersResults findResults = ewsConnector.FindFolders(WellKnownFolderName.MsgFolderRoot, fv);

    int totalUnreadCount = 0;
    foreach (Folder f in findResults.Folders)
    {
        try
        {
            totalUnreadCount += f.UnreadCount;
            Console.WriteLine("Folder [" + f.DisplayName + "] has [" + f.UnreadCount.ToString() + "] unread items.");
        }
        catch(Exception ex)
        {
            Console.WriteLine("Folder [" + f.DisplayName + "] does not have the unread property.");
        }
    }

    Console.WriteLine("Mailbox has [" + totalUnreadCount.ToString() + "] unread items.");

    return totalUnreadCount;
}
like image 43
Sesha Krishnan Avatar answered Oct 03 '22 16:10

Sesha Krishnan