HowTo: Search in Outlook items programmatically
You can search in Outlook folders and sub folders in 3 different ways: by using the Items.Restrict method, Items.Find in liaison with Items.FindNext and Application.AdvancedSearch. The first two have essential limitations in use – they work only for one Items collection of MAPIFolder, are executed synchronously, and not all fields of Outlook items by a long shot can be used for searching.
The AdvancedSearch method is the most powerful and convenient way of search, it can search in Outlook sub folders as well, and it is this method that we are going to dwell on today.
Well, here goes. The description of the AdvancedSearch method in VB.NET is as follows (C# sample is available for download at the end of the post):
Function AdvancedSearch(ByVal Scope As String,_ Optional ByVal Filter As Object = Nothing,_ Optional ByVal SearchSubFolders As Object = Nothing,_ Optional ByVal Tag As Object = Nothing)_ As Microsoft.Office.Interop.Outlook.Search
Parameters:
- Scope. It is the range of search, usually a path to a folder.
- Filter. This is the most complicated parameter. It determines what we are searching for. Its syntax should correspond to the syntax of SQL Server queries (among others, we can use such a nice operator as LIKE), which is very comfortable indeed. However, it not that easy to specify how column names should look like, but the following MSDN article will definitely be of much help.
- SearchSubFolders. Determines whether to search in folder’s subfolders.
- Tag. This is a search identifier. You will need it when handling the AdvancedSearchComplete event.
In our VB.NET example, we use an instance of an Advanced Outlook Form to give the end-user the ability to start search:
Private Sub Button1_Click(_ ByVal sender As System.Object,_ ByVal e As System.EventArgs) Handles Button1.Click Dim CurrentFolder As Outlook.MAPIFolder Dim CurrentOutlookApp As Outlook.Application Dim sFilter, sScope As String Me.ListView1.Items.Clear() If RadioButton1.Checked Then sFilter = "urn:schemas:httpmail:subject LIKE '%"_ + TextBox1.Text.Trim + "%'" Else sFilter = "urn:schemas:httpmail:textdescription LIKE '%"_ + TextBox1.Text.Trim + "%'" End If If Me.OutlookAppObj IsNot Nothing Then CurrentOutlookApp = TryCast(Me.OutlookAppObj, Outlook.Application) If Me.FolderObj IsNot Nothing Then Try CurrentFolder = TryCast(Me.FolderObj, Outlook.MAPIFolder) sScope = "'" + CurrentFolder.FolderPath._ Replace("'", "''") + "'" oSearch = CurrentOutlookApp.AdvancedSearch(_ sScope, sFilter, True, "Search1") Catch ex As Exception System.Windows.Forms.MessageBox.Show(ex.Message) End Try End If End If End Sub
Handle the AdvancedSearchComplete event and fill in System.Windows.Forms.ListView with search results:
Public Sub adxOutlookEvents_AdvancedSearchComplete(_ ByVal sender As System.Object,_ ByVal hostObj As System.Object)_ Handles adxOutlookEvents.AdvancedSearchComplete Dim myForm As ADXOlForm1 = Nothing Dim CurrentResults As Outlook.Results = Nothing Dim CurrentSearch As Outlook.Search = Nothing Dim lvListItem As System.Windows.Forms.ListViewItem Dim OldCursor As System.Windows.Forms.Cursor Dim objItem As Object myForm = AdxOlFormsManager1.Items(0)._ GetCurrentForm(AddinExpress.OL.EmbeddedFormStates.Visible) If myForm IsNot Nothing Then OldCursor = myForm.Cursor Try myForm.Cursor = Windows.Forms.Cursors.WaitCursor CurrentSearch = CType(hostObj, Outlook.Search) If CurrentSearch IsNot Nothing Then If CurrentSearch.Tag = "Search1" Then CurrentResults = CurrentSearch.Results If CurrentResults.Count > 0 Then myForm.ListView1.BeginUpdate() For i As Integer = 1 To CurrentResults.Count objItem = CurrentResults.Item(i) lvListItem =_ New System.Windows.Forms.ListViewItem With lvListItem .Text = objItem.SenderName .SubItems.Add(objItem.Subject) .SubItems.Add(_ objItem.ReceivedTime.ToString()) .SubItems.Add(objItem.EntryID) End With myForm.ListView1.Items.Add(lvListItem) Next myForm.ListView1.Items(0).Selected = True myForm.ListView1.EndUpdate() Else System.Windows.Forms.MessageBox.Show(_ "0 items were found.") End If End If End If Catch ex As Exception System.Windows.Forms.MessageBox.Show(ex.Message) Finally If CurrentResults IsNot Nothing Then Marshal.ReleaseComObject(CurrentResults) End If myForm.Cursor = OldCursor End Try End If End Sub
The search process is VERY fast indeed. It normally takes just a few seconds from executing the AdvancedSearch method to raising the AdvancedSearchComplete event. Retrieving objects from the Results collection is much slower. But even here there is some room for improvement: you can use the SetColumns method of the Results collection to cache certain fields for fast access. That's all for today.
You may also be interested in:
Special features for Outlook plug-in development
How to write Outlook add-in: toolbars, buttons, ribbons, menus
Available downloads:
C# sample Outlook add-in for VS 2005
VB.NET sample Outlook add-in for VS 2005
10 Comments
Can this AdvancedSearch also search recursively (i.e. with subfolders) inside Public Folders and folders inside shared mailboxes? Just asking because the Advanced Find dialog in Outlook could not…
It can search recursively in Exchange Mailboxes, but cannot in Public Folders. Also, searching across multiple Stores simultaneously is not possible.
That’s great to hear (about the secondary mailboxes)! We recently had a request where this would definitely come in handy. I’ll have a look at this next week.
Phew looks very complicated. How about a normal search tool which is able to search both your contacts and your addresses and is pretty fast, too? I use lookeen and am pretty happy with it.
Thank you for the idea. We will try to create a how-to sample of such kind.
Thanks, very helpful article and exactly what I was looking for. I expected that it would have been easy to find info on searching outlook folder but all the others (many) that I looked at were demonstrating how to use the Find and Restrict methods on the Items collection. I tried both of the afore mentioned methods and found them to be very limited and pretty much useless.
Thanks again.
I have a small question here. I have shared mailbox apart from the main mailbox and am not able to search on shared mailbox. I just need the mails under inbox folder of the share mailbox. I am able todo restrict but why cannot i do advancedsearch.The application is just freezing when i do advanced search for shared mailbox in winforms.
Hi Prathima,
What value do you pass in the Scope parameter of the AdvancedSearch method?
Nice Article!
The solution which i have downloaded from here is giving Add in Express error. Do you have any idea about this?
Actually what i need to do is, i need to search mails which has “XYZ” word exists in subject line & then programatically add reminders to those mails. Let me know if you have any source code for the same.
Thank you!
Hi Nishant,
Thank you for your kind words!
>> The solution which i have downloaded from here is giving Add in Express error. Do you have any idea about this?
I have just re-tested the solution, it works for me without any errors. I may assume that you don’t have our Add-in Express for Office and .NET product installed and that is why the error occurs on your side.
>> Actually what i need to do is, i need to search mails which has “XYZ” word exists in subject line & then programatically add reminders to those mails. Let me know if you have any source code for the same.
Sorry, we don’t have a ready-made source code of such kind.