Ty Anderson

Outlook Address Book – complete guide for developers

I bet if we surveyed most users of Outlook (the non-developer kind of users) and asked them why Outlook exists, they’d respond by saying, “email”. They’d  be correct of course. But they wouldn’t be fully correct. Email is front and center but Outlook wouldn’t be anything without Contacts.

Almost everything you do in Outlook involves a contact. Email, appointments, address book all involve contacts (aka people… people you know). Tasks are  more of a personal thing but you can assign them to others so lay off! Tasks involve people too even if the only “people” is you.

Because contacts are important, knowing how to use them in your Outlook solutions is a key skill. Today, you and I will cover Outlook’s address book…  complete with VB.NET code samples and just enough explaining.

What is the Outlook Address Book

Out-of-the-box, Outlook’is address book is the default contacts folder that resides in a user’s Outlook folder structure. In a typical Outlook installation, there is a single contacts folder and feeds the TO, CC, BCC fields in the Outlook email form. In any form that supports assigning a contact  to it, the default address book feeds it as well.

When the user clicks an address field like the TO, the address book dialog form displays. Here you will see the contacts listed in your contacts folder. If  connected to Exchange or other directory providers, these address books will also display contacts available via the LDAP directory.

Today, we are not concerned with the LDAP directory. We are dealing only with the default Outlook address book. And according to the Outlook object model,  that directory is the contacts directory… as you will soon see in the code samples.

Address Book code samples

From here until I stop typing, we’ll take a brisk walk through code samples worth stealing for your own purposes. I’ll start at the beginning and see where  it goes.

How to access the Outlook Address Book

To gain a reference to the default address book, you need to reference the default contacts folder.

Private Function GetDefaultAddressBook() As Outlook.MAPIFolder
 
    Dim ns As Outlook._NameSpace = Me.OutlookApp.GetNamespace("MAPI")
    If ns IsNot Nothing Then
        Try
            Return ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts)
        Finally
            Marshal.ReleaseComObject(ns)
        End Try
    End If
    Return Nothing
 
End Function

This task is trivial as the GetDefaultAddressBook function shows. You don’t need to make a function like I did as you can always call the GetDefaultFolder function via the OutlookApp.Session object. I made this function so I can use it in subsequent code samples and make them pithy.

How to enumerate folders & new Outlook address book entries

It stands to reason you will want to enumerate objects within the default address book. The EnumerateAddressBookFolders procedure shows how. What it does is add a new contact to each folder as it does its enumerating.

Private Sub EnumerateAddressBookFolders()
 
    Dim ab As Outlook.MAPIFolder = GetDefaultAddressBook()
    Dim fldrs As Outlook.Folders = ab.Folders
 
    For i = 1 To fldrs.Count
        Dim folder As Outlook.MAPIFolder = fldrs(i)
        Dim folderItems As Outlook._Items = folder.Items
        Dim contact As Outlook.ContactItem = _
            folderItems.Add(Outlook.OlItemType.olContactItem)
 
        With contact
            .FirstName = "John"
            .LastName = "Doe"
            .Email1Address = "john.doe@interweb.com"
            .PrimaryTelephoneNumber = "+12125551212"
            .Save()
        End With
 
        Marshal.ReleaseComObject(contact)
        Marshal.ReleaseComObject(folderItems)
        Marshal.ReleaseComObject(folder)
    Next
 
    Marshal.ReleaseComObject(fldrs)
    Marshal.ReleaseComObject(ab)
 
End Sub

I know the sample is generic but it serves my purposes here to illustrate how to rummage around the folders and how to add a new contact. Just be sure to save that new contact or he (or she) will never really exist.

How to enumerate items & edit contact items

With a folder in-hand, you will run across scenarios that require you to look inside that folder’s items and edit those items.  The EnumerateABItems procedure edits each item in the default Outlook address book and adds a note to it.

Private Sub EnumerateABItems()
 
    Dim ab As Outlook.MAPIFolder = GetDefaultAddressBook()
    Dim abItems As Outlook._Items = ab.Items
 
    For i = 1 To abItems.Count
        Dim objItem As Object = abItems(i)
        Dim con As Outlook._ContactItem = TryCast(objItem, Outlook._ContactItem)
 
        If con IsNot Nothing Then
            con.Body = con.Body & vbCrLf & "Enumerated: " & Now.Date
            con.Save()
        End If
 
        Marshal.ReleaseComObject(objItem)
    Next
 
    Marshal.ReleaseComObject(abItems)
    Marshal.ReleaseComObject(ab)
 
End Sub

It’s nothing major but I hope you see the main points. When enumerating, don’t use a FOR… EACH loop as they are bad for business in Outlook development. Instead, FOR… NEXT along with the item count. Next, access each item and change properties as you see fit. Oh… be sure to save it too.

How to remove an address book item

Here is a simple strategy for deleting a contact in the Outlook address book. In this sample, the code loops through the default address book items in search a specific email address (John Doe). If found, the code deletes that contact.

Private Sub DeleteJohnDoe(email As String)
 
    Dim ab As Outlook.MAPIFolder = GetDefaultAddressBook()
    Dim abItems As Outlook._Items = ab.Items
 
    For i = abItems.Count To 1 Step -1
        Dim objItem As Object = abItems(i)
        Dim contact As Outlook._ContactItem = TryCast(objItem, Outlook._ContactItem)
 
        If contact IsNot Nothing Then
            If contact.Email1Address = email Then contact.Delete()
        End If
 
        Marshal.ReleaseComObject(objItem)
    Next
 
    Marshal.ReleaseComObject(abItems)
    Marshal.ReleaseComObject(ab)
 
End Sub

How to move a ContactItem to another folder

Sometimes, you might need to move a contact to different Outlook folder. This is easy.

Private Sub MoveContact(ByRef contact As Outlook._ContactItem, _
                        ByRef folder As Outlook.MAPIFolder)
 
    contact.Move(folder)
 
End Sub

The MoveContact procedure accepts a contact and a folder as parameters. Which is all you need. You need a contact so you call its Move function. When calling the Move function, you need to pass the target folder object and voila! Contact moved.

How to forward a business card

I think this method is underexposed and underappreciated. This sample code accepts an email address as a search string. If a contact exists with the email, the code creates a new email and inserts the contacts business card within it.

Private Sub ForwardContact(contactEmail As String)
 
    Dim contacts As Outlook.MAPIFolder = GetDefaultAddressBook()
    Dim contactsItems As Outlook._Items = contacts.Items
 
    Dim query As String = "[Email1Address]='" & contactEmail & "'"
    query = query & " OR [Email2Address]='" & contactEmail & "'"
    query = query & " OR [Email3Address]='" & contactEmail & "'"
 
    Dim person As Outlook._ContactItem = contactsItems.Find(query)
 
    If Not person Is Nothing Then
        person.ForwardAsBusinessCard()
        Marshal.ReleaseComObject(person)
    End If
 
    Marshal.ReleaseComObject(contactsItems)
    Marshal.ReleaseComObject(contacts)
 
End Sub

Display an address book entry (aka a Contact)

This sample is similar to the one just above. It takes the passed email string to build a search query. The Find method then uses the query to execute the search.

Private Sub FindAndDisplayContact(contactEmail As String)
 
    Dim contacts As Outlook.MAPIFolder = GetDefaultAddressBook()
    Dim contactsItems As Outlook._Items = contacts.Items
 
    Dim query As String = "[Email1Address]='" & contactEmail & "'"
    query = query & " OR [Email2Address]='" & contactEmail & "'"
    query = query & " OR [Email3Address]='" & contactEmail & "'"
 
    Dim person As Outlook._ContactItem = contactsItems.Find(query)
 
    If Not person Is Nothing Then
        person.Display()
        Marshal.ReleaseComObject(person)
    End If
 
    Marshal.ReleaseComObject(contactsItems)
    Marshal.ReleaseComObject(contacts)
 
End Sub

If a matching contact is found, the code displays it for user’s perusal.

Set a reminder to contact a Contact

Sometimes you want to remind yourself to call someone in your Outlook address book. This code does finds a contact and the sets a task reminder for that contact.

Private Sub MarkContactasTask(contactEmail As String)
 
    Dim contacts As Outlook.MAPIFolder = GetDefaultAddressBook()
    Dim contactsItems As Outlook._Items = contacts.Items
 
    Dim query As String = "[Email1Address]='" & contactEmail & "'"
    query = query & " OR [Email2Address]='" & contactEmail & "'"
    query = query & " OR [Email3Address]='" & contactEmail & "'"
 
    Dim person As Outlook._ContactItem = contactsItems.Find(query)
 
    If Not person Is Nothing Then
        person.MarkAsTask(Outlook.OlMarkInterval.olMarkThisWeek)
        person.Save()
        Marshal.ReleaseComObject(person)
    End If
 
    Marshal.ReleaseComObject(contactsItems)
    Marshal.ReleaseComObject(contacts)
 
End Sub

This code sets the reminder for this week. You might want to set it to something else.

Responding to Items collection event

You watch all items in an address book and take action when contacts are created, edited, or removed. To make this happen, you need to add an OutlookItemsEvent class. You can do this by using the Visual Studio to click Project > Add New Item. In the Add New Item dialog windows, find the Add-in Express Items on the left-hand side.

In the Add New Item dialog windows, find the Add-in Express Items on the left-hand side, select the Outlook Items Events Class and click Add.

Expand it select Outlook. Now, select the Outlook Items Events Class and click Add. You will now have a new class names OutlookItemsEventsClass1. This is where we will add the code for the items events.

This edit is easy because we already had the folder setup from the previous example. And were ready to go with the address book items. Let’s take a quick look at ProcessItemAdd, ProceeItemChange, and ProcessItemRemove.

Public Overrides Sub ProcessItemAdd(Item As Object)
 
    Dim contact As Outlook._ContactItem = TryCast(Item, Outlook._ContactItem)
    If contact IsNot Nothing Then
        contact.Body = contact.Body & vbNewLine & "Added on: " & Now.Date()
        contact.Save()
    End If
 
End Sub
 
Public Overrides Sub ProcessItemChange(Item As Object)
 
    Dim contact As Outlook._ContactItem = TryCast(Item, Outlook._ContactItem)
    If contact IsNot Nothing Then
        contact.Body = contact.Body & vbNewLine & "Last Edited on: " & Now.Date()
    End If
 
End Sub
 
Public Overrides Sub ProcessItemRemove()
 
    MsgBox("Contact deleted.", MsgBoxStyle.OkOnly)
 
End Sub

ProcessItemAdd and ProcessItemChange are similar because they both pass an Item object. Item is the address book item that is being added or changed. Thus, in these two samples, access Item, cast it is a ContactItem, and edit its Body property.

The ProcessItemRemove event does not include the Item object. Thus, you can’t take any last minute action on that contact that is dying. But you can respond to the event according to your requirements. Mine were fairly benign.

Take action before moving an address book item

This sample piggy-backs off the previous sample. But instead of the times, we want to monitor a folder and take action before a user moves an item. To do this, you respond to the ProcessBeforeItemMove event in the OutlookItemsEventsClass1 class.

Public Overrides Sub ProcessBeforeItemMove(item As Object, moveTo As Object, _
    e As AddinExpress.MSO.ADXCancelEventArgs)
 
    Dim contact As Outlook._ContactItem = TryCast(item, Outlook._ContactItem)
 
    If contact IsNot Nothing Then
        Dim query As String = "[Email1Address]= '" & contact.Email1Address & "'"
 
        If moveTo IsNot Nothing Then
 
            Dim moveToItems As Outlook._Items = moveTo.Items
            Dim alreadyThere As Outlook._ContactItem = moveToItems.Find(query)
            If alreadyThere Is Nothing Then
                contact.Body = contact.Body & vbCrLf & vbCrLf & "Moved on " & Now.Date()
                contact.Save()
            Else
                Marshal.ReleaseComObject(alreadyThere)
            End If
 
            Marshal.ReleaseComObject(moveToItems)
        End If
    End If
 
End Sub

And, I know, the sample is nothing special. Here, the code only changes the body of the contact item currently in-transit. But, I think you get the idea.

To wrap-up the add-in, we need to edit the AddinInitialize event:

Friend FolderItemEvents As OutlookItemsEventsClass1 = Nothing
 
Private Sub AddinModule_AddinInitialize(sender As Object, e As EventArgs) _
    Handles MyBase.AddinInitialize
 
    FolderItemEvents = New OutlookItemsEventsClass1(Me)
    FolderItemEvents.ConnectTo(ADXOlDefaultFolders.olFolderContacts, True)
 
End Sub

Notice too the need for the class-level FolderItemEvents object.

And the AddinBeginShutdown event:

Private Sub AddinModule_AddinBeginShutdown(sender As Object, e As EventArgs) _
    Handles Me.AddinBeginShutdown
 
    If FolderItemEvents IsNot Nothing Then
        FolderItemEvents.RemoveConnection()
        FolderItemEvents = Nothing
    End If
 
End Sub

These two events create and remove the connection to the OutlookItemsEventsClass1 (by storing it in the FolderItemEvents object.

***

That’s it and that’s all but we have more samples in the queue. Stay tuned.

Available downloads:

These code samples were created using Add-in Express for Office and .net:

VB.NET samples to work with Outlook Address Book

4 Comments

  • Alan says:

    Shouldn’t you count backwards through the contacts in DeleteJohnDoe? Otherwise, when you delete the contact, won’t the value of abItems.Count change and throw an out-of-bounds exception?

  • Ty Anderson says:

    Hi Alan,

    You are correct. Here is the corrected procedure:

    Private Sub DeleteJohnDoe(email As String)

        Dim ab As Outlook.MAPIFolder = GetDefaultAddressBook()
        Dim abItems As Outlook._Items = ab.Items

        For i = abItems.Count To 1 Step -1
            Dim objItem As Object = abItems(i)
            Dim contact As Outlook._ContactItem = TryCast(objItem, Outlook._ContactItem)

            If contact IsNot Nothing Then
                If contact.Email1Address = email Then contact.Delete()
            End If

            Marshal.ReleaseComObject(objItem)
        Next

        Marshal.ReleaseComObject(abItems)
        Marshal.ReleaseComObject(ab)

    End Sub

  • Marc says:

    Question I have a 4 mails box in my outlook and I want to scan contacts in each (1 by 1). What function I can use to do that
    Thanks a lot

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

    Hello Marc,

    Get message stores in your Outlook. For each store get the Contacts folder in that store. Then scan the folder as shown above.

    Reference:
    https://docs.microsoft.com/en-us/office/vba/api/outlook.namespace.stores
    https://docs.microsoft.com/en-us/office/vba/api/outlook.stores
    https://docs.microsoft.com/en-us/office/vba/api/outlook.store.getdefaultfolder

Post a comment

Have any questions? Ask us right now!