Eugene Astafiev

How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)

As you have probably guessed, this article will describe the Find and FindNext methods of the Outlook Items class. But before focusing on the functionality of these methods, I would like to draw an analogy with database programming in the .NET world. In ADO.NET there is the System.Data.SqlClient.SqlDataReader class which provides the Read method. It reads the db records line by line according to the query you specified in the System.Data.SqlClient.SqlCommand class. As you will see a bit later, the Find and FindNext methods in Outlook do the same. Outlook and its object model act like a big wrapper around the Messaging db ;-)

The Find method locates and returns an Outlook item that specifies the provided filter. It accepts a string value reflecting the criteria that a result item should meet. The format of the string depends on the field type that you are going to filter by. Please note that there are some item properties that you can’t use for the filter. You can read more about the properties not allowed in the filter string and string formats used for the search criterion on MSDN.

As soon as the first record is found we need to use the FindNext method of the Items class to continue receiving subsequent records from Outlook according to the filter we specified in the Find method. As you may see, this is the major difference between the ADO.NET and Outlook classes. The FindNext method doesn’t accept any parameters; it just does its job: finds and returns the next Outlook item. Null (Nothing in case of VB.NET) will be returned if there are no more items meeting the search criteria or if FindNext simply fails.

The following sample iterates over all unread e-mails listed in the specified folder (see the folder parameter of the FindAllUnreadEmails method). It just writes unread e-mails’ subjects to the debug window using the System.Diagnostics.Debug class. Please use the DebugView utility to intercept the debug output.

C# and Add-in Express:

using System.Text;
using System.Diagnostics;
// ...
private void FindAllUnreadEmails(Outlook.MAPIFolder folder)
{
    string searchCriteria = "[UnRead] = true";
    StringBuilder strBuilder = null;
    int counter = default(int);
    Outlook._MailItem mail = null;
    Outlook.Items folderItems = null;
    object resultItem = null;
    try
    {
        if (folder.UnReadItemCount > 0)
        {
            strBuilder = new StringBuilder();
            folderItems = folder.Items;
            resultItem = folderItems.Find(searchCriteria);
            while (resultItem != null)
            {
                if (resultItem is Outlook._MailItem)
                {
                    counter++;
                    mail = resultItem as Outlook._MailItem;
                    strBuilder.AppendLine("#" + counter.ToString() + 
                                          "\tSubject: " + mail.Subject);
                }
                Marshal.ReleaseComObject(resultItem);
                resultItem = folderItems.FindNext();
            }
            if (strBuilder != null)
                Debug.WriteLine(strBuilder.ToString());
        }
        else
            Debug.WriteLine("There is no match in the " 
                                 + folder.Name + " folder.");
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
    finally
    {
        if (folderItems != null) Marshal.ReleaseComObject(folderItems);
    }
}

VB.NET and Add-in Express:

Imports System.Text
Imports System.Diagnostics
' ...
Private Sub FindAllUnreadEmails(folder As Outlook.MAPIFolder)
    Dim searchCriteria As String = "[UnRead] = true"
    Dim strBuilder As StringBuilder = Nothing
    Dim counter As Integer = 0
    Dim mail As Outlook._MailItem = Nothing
    Dim folderItems As Outlook.Items = Nothing
    Dim resultItem As Object = Nothing
    Try
        If (folder.UnReadItemCount > 0) Then
            strBuilder = New StringBuilder()
            folderItems = folder.Items
            resultItem = folderItems.Find(searchCriteria)
            While Not IsNothing(resultItem)
                If (TypeOf (resultItem) Is Outlook._MailItem) Then
                    counter += 1
                    mail = resultItem
                    strBuilder.AppendLine("#" + counter.ToString() + _
                                          " - Subject: " + mail.Subject)
                End If
                Marshal.ReleaseComObject(resultItem)
                resultItem = folderItems.FindNext()
            End While
            If Not IsNothing(strBuilder) Then
                Debug.WriteLine(strBuilder.ToString())
            End If
        Else
            Debug.WriteLine("There is no match in the " + _
                                   folder.Name + " folder.")
        End If
    Catch ex As Exception
        System.Windows.Forms.MessageBox.Show(ex.Message)
    Finally
        If Not IsNothing(folderItems) Then
            Marshal.ReleaseComObject(folderItems)
        End If
    End Try
End Sub

C# and VSTO:

using System.Diagnostics;
using System.Runtime.InteropServices;
// ...
private void FindAllUnreadEmails(Outlook.MAPIFolder folder)
{
    string searchCriteria = "[UnRead] = true";
    StringBuilder strBuilder = null;
    int counter = default(int);
    Outlook._MailItem mail = null;
    Outlook.Items folderItems = null;
    object resultItem = null;
    try
    {
        if (folder.UnReadItemCount > 0)
        {
            strBuilder = new StringBuilder();
            folderItems = folder.Items;
            resultItem = folderItems.Find(searchCriteria);
            while (resultItem != null)
            {
                if (resultItem is Outlook._MailItem)
                {
                    counter++;
                    mail = resultItem as Outlook._MailItem;
                    strBuilder.AppendLine("#" + counter.ToString() + 
                                          "\tSubject: " + mail.Subject);
                }
                Marshal.ReleaseComObject(resultItem);
                resultItem = folderItems.FindNext();
            }
            if (strBuilder != null)
            Debug.WriteLine(strBuilder.ToString());
        }
        else
            Debug.WriteLine("There is no match in the " + 
                                   folder.Name + " folder.");
    }
    catch (Exception ex)
    {
       System.Windows.Forms.MessageBox.Show(ex.Message);
    }
    finally
    {
       if (folderItems != null) Marshal.ReleaseComObject(folderItems);
    }
}

VB.NET and VSTO:

Imports System.Diagnostics
Imports System.Runtime.InteropServices
' ...
Private Sub FindAllUnreadEmails(folder As Outlook.MAPIFolder)
    Dim searchCriteria As String = "[UnRead] = true"
    Dim strBuilder As StringBuilder = Nothing
    Dim counter As Integer = 0
    Dim mail As Outlook._MailItem = Nothing
    Dim folderItems As Outlook.Items = Nothing
    Dim resultItem As Object = Nothing
    Try
        If (folder.UnReadItemCount > 0) Then
            strBuilder = New StringBuilder()
            folderItems = folder.Items
            resultItem = folderItems.Find(searchCriteria)
            While Not IsNothing(resultItem)
                If (TypeOf (resultItem) Is Outlook._MailItem) Then
                    counter += 1
                    mail = resultItem
                    strBuilder.AppendLine("#" + counter.ToString() + _
                                          " - Subject: " + mail.Subject)
                End If
                Marshal.ReleaseComObject(resultItem)
                resultItem = folderItems.FindNext()
            End While
            If Not IsNothing(strBuilder) Then
                Debug.WriteLine(strBuilder.ToString())
            End If
        Else
            Debug.WriteLine("There is no match in the " + _
                                   folder.Name + " folder.")
        End If
    Catch ex As Exception
        System.Windows.Forms.MessageBox.Show(ex.Message)
    Finally
        If Not IsNothing(folderItems) Then
            Marshal.ReleaseComObject(folderItems)
        End If
    End Try
End Sub

See you on our forums and in the e-mail support!

3 Comments

  • uma says:

    nice.its help me to save my time.

  • brian says:

    I dont know if you still maintain this blog but I am trying to make a vb.net 2012 program that will check the outlook email every 2 minutes or so for new messages, go through the senders name, searching only for approved senders, parse those emails with very simple formats (A name, A number, A message), put the number and message into a textbox, delete the email, and then repeat as new approved messages come up. Another hurdle I foresee in this program: I have set it up as a SDI rather than MDI so there may need to be two of these programs running at the same time, will this cause a crash of some kind of both try to search through outlook at the same time? I am a beginner with vb.net and would like a thorough explanation of everything Im doing so I can actually understand what is going on. It seems somewhat simple, but I can not get my head around it quite yet.

  • Andrei Smolin (Add-in Express Team) says:

    Hello Brian,

    I would suggest tht you check this blog: Outlook NewMail unleashed: writing a working solution (C#), it describes finding out what emails have been received. The project discussed there is written in C#; you can use any online Csharp to VB.NET convertor. As to the other problem, I don’t think there whould be any problem of this kind but the best approach is to debug this scenario. I don’t think MDI or SDI may influence the issue in any way.

Post a comment

Have any questions? Ask us right now!