Chapter 7: Address Books and Recipients

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

This article is an excerpt from Programming Applications for Microsoft Office Outlook 2007 by Randy Byrne and Ryan Gregg, from Microsoft Press (ISBN 9780735622494, copyright Microsoft Press 2007, all rights reserved). No part of these chapters may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, electrostatic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.

To communicate electronically, you need an addressing system. This chapter first provides an overview of common address books in Microsoft Office Outlook 2007, including the Exchange Global Address List, the Outlook Address Book, and custom address books. Once you have the overview, you will dive into the Recipients collection and the Recipient object. These objects provide the foundation for related objects such as the AddressEntry object. Derived from the AddressEntry object, the ExchangeUser object exposes detailed information about a user on Microsoft Exchange Server. This information includes manager and direct reports relationships. The ExchangeDistributionList object lets you enumerate Exchange distribution list owners and membership. There are plenty of code samples to help you get started. Finally, you display the Outlook Address Book programmatically using the SelectNamesDialog object.

In this chapter, you will:

  • Use the Recipient object to determine PrimarySmtpAddress.

  • Learn how to use the new ExchangeUser and ExchangeDistributionList objects.

  • Learn about AddressList and AddressEntry objects.

  • Display the Outlook 2007 Address Book dialog box programmatically, modify dialog labels and recipient selectors, and return a Recipients collection.

Contents

  • An Overview of Outlook Address Books

  • The Recipients Collection and Recipient Objects

  • The AddressLists Collection and AddressList Objects

  • The AddressEntries Collection and AddressEntry Object

  • The ExchangeUser Object

  • The ExchangeDistributionList Object

  • The SelectNamesDialog Object

  • Summary

  • Additional Resources

An Overview of Outlook Address Books

This chapter focuses on the objects that allow you to send items to a collection of recipients or, conversely, allow you to understand which recipient sent an item or the recipients to whom the item was addressed. Before we discuss how to use address-related objects, here’s a quick overview of the address book providers that ship with Outlook.

Exchange Global Address List

If the user is configured with an Exchange account, his or her mailbox sits on an Exchange server, and the Exchange Address Book provider provides services that allow the Outlook client to render addresses in the Address Book dialog box and resolve recipients to a unique Exchange address. Chapter 2, "Outlook as a Platform,” provides an extensive discussion of address book providers and the Exchange Address Book provider in particular.

The Exchange Global Address List (GAL) contains an aggregated list of all messaging recipients for an organization. All data in the GAL comes from Windows Active Directory directory service by way of global catalog servers. The GAL contains entries for individual mailbox users, remote users (known as Exchange contacts, which you should not confuse with an Outlook contact) who do not belong to the corporate domain, e-mail distribution lists, and resources such as conference rooms. In an Exchange environment, there will always be a GAL in the AddressLists collection. You should be aware that it is possible for a given mailbox or address entity (such as an Exchange public folder) to be hidden from the GAL.

NoteNote

Because Microsoft Office Outlook 2007 requires Microsoft Exchange Server 2000 or later, technologies such as Microsoft Exchange Server 5.5 directory services are no longer used. Exchange Server 2000 and later versions always integrate directly with Windows Active Directory. Due to this integration, services such as distribution lists and address lists are delivered through Active Directory.

A new feature of Outlook 2007 when running against a Microsoft Exchange Server 2007 server is the hierarchical address book. When the hierarchical address book is turned on by an Exchange administrator, members of an organization are displayed in a tree view control and they are grouped by department. The Outlook 2007 object model does not provide programmatic access to the nodes of the hierarchical address book.

Exchange Containers

Exchange 2000 and later versions support the concept of an address list container, which allows the user to select a subset of addresses in the GAL for display in the Outlook Address Book dialog box. An Exchange administrator can create a build rule for an Exchange container by using the Exchange System Manager console. These build rules use the lightweight directory access protocol (LDAP) search filter syntax to create an Exchange container. For example, you could create an address list of all full-time employees in the engineering department of your organization. Similarly, you can create a container for all conference rooms across the entire company. From an Outlook object model perspective, you cannot create an Exchange container programmatically. You can enumerate the containers within the AddressLists collection and then enumerate all the AddressEntry objects within the individual container.

Offline Address Book

Cached mode allows an Exchange user to work when disconnected from the Exchange server. The offline address book (OAB) provides similar functionality for the address book in a disconnected state. The OAB contains user properties that Outlook utilizes to send an e-mail message or display information about a user. By using an OAB, Outlook does not have to connect to the Exchange server to resolve names or open the information for each user. This design reduces network traffic and improves performance.

The OAB is a snapshot of information from the GAL. Consequently, not all the information in the GAL is available in the OAB. The following information in the GAL is not available in the OAB:

  • Custom properties added by a server administrator, such as the employee ID of each employee

  • Information about the organizational hierarchy, such as manager and direct reports lists

  • Distribution list memberships

Using the Offline Address Book dialog box available through the Send/Receive Setting dialog box, the user or an IT administrator can elect to download full OAB details or no details. Your code should examine the ExchangeConnectionMode property of the Namespace object to determine if the user is in a disconnected state. If the user is disconnected, your code should handle the possibility that you won’t be able to obtain custom properties, information about the user’s position in the organizational hierarchy, or distribution list membership. For complete details on the ExchangeConnectionMode property, see Chapter 6, "Accessing Outlook Data."

Outlook Address Book

The Outlook Address Book (also known as the Contacts Address Book, or CAB) provider allows Outlook to display addresses for all items that contain at least one e-mail address or fax number entry in a Contacts folder. By default, the Outlook Address Book for your default Contacts folder is shown as an address list in the Outlook Address Book. If the user is configured for only a Post Office Protocol 3 (POP3) or Internet Message Access Protocol (IMAP) account, the Outlook Address Book is the only address book that will appear by default. The user can control whether non-default Contacts folders will appear in the address book. You can also programmatically control whether a Contacts folder appears in the Outlook Address Book by setting the ShowAsOutlookAB property on the Folder object. Typically, all Outlook users will have a CAB in their list of address books. Outlook 2007 provides new methods that let you obtain the corresponding Contacts folder for a given Contacts address list.

Other Address Book Providers

Although there are other address book providers that can be installed with Outlook 2007, these address book providers represent the exception rather than the rule. Internet directory services are used to find e-mail addresses that are not in a local Outlook Address Book or a corporate-wide directory such as the GAL. LDAP provides access to Internet directories. To communicate with an LDAP server, Outlook requires network connectivity to connect to the LDAP server. Depending on the capabilities of the LDAP server, an address entry for an Internet directory might only return the distinguished name and display name for the address entry.

You can also install custom address book providers that appear in the AddressLists collection. Custom address book providers return an AddressList.AddressListType equal to OlAddressList.olCustomAddressList. An example of a custom address book provider is the Microsoft Office Outlook Mobile Service (OMS) provider that ships with Outlook 2007. If OMS is configured as an address book, then OMS provides an address list for all items in the default Contacts folder that have a mobile phone number. Unlike the Outlook Address Book that returns address entries that have an e-mail address or fax number, OMS only returns address entries that have a mobile phone number.

The Recipients Collection and Recipient Objects

Before discussing Outlook address books and address entries, it’s helpful to understand the Recipients collection and Recipient objects. Think of a Recipient object as a virtual AddressEntry object. Unlike an AddressEntry object, a Recipient object has no corresponding address book container per se. AddressEntry objects can be stored in a variety of locations, including an Outlook Contacts folder or the Exchange GAL. Once a Recipient object is resolved to a physical AddressEntry object, you can use the AddressEntry property of the Recipient object to return the actual AddressEntry object for the Recipient object. A Recipient object is said to be resolved when its Resolved property equals true.

You add Recipient objects to the Recipients collection to create recipients for an outbound e-mail message, sharing request, or meeting request. You can examine the Recipients collection to enforce certain mail rules, such as controlling Reply All behavior to prevent corporate spam. When an inbound item arrives in your mailbox, it also has a Recipients collection that lets you understand the destination recipients of the message. Outlook also stamps inbound messages with certain properties that you can use to determine the sender of a message or the organizer of an appointment.

Outlook Object Model Guard Considerations

You should be aware that when you attempt to access a Recipient, Recipients, SelectNamesDialog, AddressEntry, AddressEntries, AddressList, or AddressLists object, Outlook will display an Address Book warning dialog box unless your code is trusted from the perspective of the object model guard. The Outlook object model guard is discussed in detail in Chapter 19, "Trust and Security." See the discussion in Chapter 19 about how to ensure that your code is trusted and does not display security prompts when you access objects that contain e-mail addresses.

The CreateRecipient Method

Typically, Recipient objects are associated with sendable items such as a MailItem object. Sendable items always expose a Recipients property that lets you access the Recipients collection for the item. However, it is possible to create a free-standing Recipient object that is not bound to the Recipients collection of an item. To create a Recipient object, you use the CreateRecipient method of the Namespace object. This unbound Recipient object can be passed to a method such as GetSharedDefaultFolder that allows you to open a shared Exchange folder and display that folder in an Explorer window. GetSharedDefaultFolder is used in Exchange delegate scenarios where the delegate has permission to access the folder of the delegator. You must resolve the Recipient object before you pass it to the GetSharedDefaultFolder method. To resolve a Recipient object, you call its Resolve method.

When you create a Recipient object using the CreateRecipient method of the Namespace object or the Add method of the Recipients collection, you must provide a recipient name. The Recipient object is then resolved against this name. A recipient name can take any of the following formats:

  • Display name   The display name of the recipient as it appears in an address list. Display names are not necessarily unique, and you should not assume that a given name will resolve.

  • Alias   An Exchange alias is a unique identifier that corresponds to the Messaging Application Programming Interface (MAPI) property PR_ACCOUNT. An Exchange alias is unique but does not guarantee that the recipient will resolve.

  • Simple Mail Transfer Protocol (SMTP) address   An SMTP address takes the form username@domain. For example, someone@example.com is a valid SMTP address.

The following code sample opens the Calendar folder of the current user’s manager. If the user does not have permission to open the manager’s Calendar folder or an error occurs, an alert dialog box is displayed to the user.

private void DisplayManagerCalendar() 
{ 
    Outlook.AddressEntry addrEntry =  
        Application.Session.CurrentUser.AddressEntry; 
    if (addrEntry.Type  == "EX") 
    { 
        Outlook.ExchangeUser manager =  
            Application.Session.CurrentUser. 
            AddressEntry.GetExchangeUser().GetExchangeUserManager(); 
        if (manager != null) 
        { 
            Outlook.Recipient recip = 
                Application.Session.CreateRecipient(manager.Name); 
            if (recip.Resolve()) 
            { 
                try 
                { 
                    Outlook.Folder folder = 
                        Application.Session.GetSharedDefaultFolder( 
                        recip, 
                        Outlook.OlDefaultFolders.olFolderCalendar) 
                        as Outlook.Folder; 
                    folder.Display(); 
                } 
                catch 
                { 
                    MessageBox.Show(
                        "Could not open manager's calendar.", 
                        "GetSharedDefaultFolder Example", 
                        MessageBoxButtons.OK, 
                        MessageBoxIcon.Error); 
                } 
            } 
 
        } 
    } 
}

Working with the Recipients Collection Object

The Recipients collection implements typical collection object methods such as Add, Remove, and Item (the Index operator). It also supports a ResolveAll method that resolves all the Recipient objects in the collection. If all Recipient objects in the collection are resolved, then ResolveAll returns true. If one or more of the Recipient objects fail to resolve, then ResolveAll returns false.

Adding Recipients to a MailItem Object

When you add a Recipient object to the Recipients collection of a MailItem object, you can control whether the recipient is a To, Cc, or Bcc recipient by setting the Type property of the Recipient object. Unfortunately, the Type property of the Recipient object is typed as an int (Integer in Microsoft Visual Basic) and does not correlate to a specific recipient type enumeration. You can, however, determine the type of a message Recipient object by setting the Type property to a value from the OlMailRecipientType enumeration. The following code sample sets To, Cc, and Bcc recipients for a message by setting the Recipient.Type property to the correct value of OlMailRecipientType.

private void SetRecipientTypeForMail() 
{ 
    Outlook.MailItem mail = Application.CreateItem( 
        Outlook.OlItemType.olMailItem) as Outlook.MailItem; 
    mail.Subject = "Sample Message"; 
    Outlook.Recipient recipTo =  
        mail.Recipients.Add("someone@example.com"); 
    recipTo.Type = (int)Outlook.OlMailRecipientType.olTo; 
    Outlook.Recipient recipCc = 
        mail.Recipients.Add("someonecc@example.com"); 
    recipCc.Type = (int)Outlook.OlMailRecipientType.olCC; 
    Outlook.Recipient recipBcc = 
        mail.Recipients.Add("someonebcc@example.com"); 
    recipBcc.Type = (int)Outlook.OlMailRecipientType.olBCC; 
    mail.Recipients.ResolveAll(); 
    mail.Display(false); 
}

Adding Recipients to an AppointmentItem Object

Adding recipients to an AppointmentItem object that represents a meeting request is very similar to adding recipients to a message. In the case of an AppointmentItem object, you use the OlMeetingRecipientType enumeration to specify whether the recipient of the message is a required, optional, or resource attendee. The following code sample creates an appointment and adds required and optional attendees. It also adds a conference room for the meeting. Notice that you must set the MeetingStatus property to OlMeetingStatus.olMeeting to change the appointment into a meeting request.

private void SetRecipientTypeForAppt() 
{ 
    Outlook.AppointmentItem appt =  
        Application.CreateItem( 
        Outlook.OlItemType.olAppointmentItem) 
        as Outlook.AppointmentItem; 
    appt.Subject = "Customer Review"; 
    appt.MeetingStatus = Outlook.OlMeetingStatus.olMeeting; 
    appt.Location = "36/2021"; 
    appt.Start = DateTime.Parse("10/20/2006 10:00 AM"); 
    appt.End = DateTime.Parse("10/20/2006 11:00 AM"); 
    Outlook.Recipient recipRequired = 
        appt.Recipients.Add("Ryan Gregg"); 
    recipRequired.Type =  
        (int)Outlook.OlMeetingRecipientType.olRequired; 
    Outlook.Recipient recipOptional = 
        appt.Recipients.Add("Peter Allenspach"); 
    recipOptional.Type =  
        (int)Outlook.OlMeetingRecipientType.olOptional; 
    Outlook.Recipient recipConf = 
        appt.Recipients.Add("Conf Room 36/2021 (14) AV"); 
    recipConf.Type =  
        (int)Outlook.OlMeetingRecipientType.olResource; 
    appt.Recipients.ResolveAll(); 
    appt.Display(false); 
}

Resolving Recipients

To resolve a recipient, you can call the ResolveAll method of the Recipients collection or the Resolve method of the Recipient object. Both of these methods return a bool (Boolean in Visual Basic) that indicates whether the recipient has been resolved. To determine the resolution status, you can examine the Resolved property of the Recipient object. When the Resolved property is false, the EntryID property of the Recipient object is null (Nothing in Visual Basic). When a Recipient object is resolved, it is resolved against address lists in the user’s profile according to the ResolutionOrder property of the AddressList objects in the AddressLists collection. For more information about resolution order, see the section "Determining Resolution Order of Address Lists" later in this chapter.

It is possible for an address to not be resolved due to an ambiguous or invalid name. For example, let’s assume that you want to resolve a recipient where the recipient name equals "Jane." Because there could be more than one individual named Jane in an organization, Outlook displays the Check Names dialog box (also known as the Ambiguous Name Resolution dialog box) shown in Figure 7-1 to allow the user to resolve an ambiguous name.

Figure 7-1. The Check Names dialog box

The Check Names dialog box

You can write code that will display the Check Names dialog box programmatically if the recipient cannot be resolved. The following ResolveRecipient method displays the Check Names dialog box if the name cannot be resolved. If the user cancels the Check Names dialog box, the code presents the Select Names dialog box to the user. The Select Names dialog box is the Outlook Address Book. If the user selects a name from the Select Names dialog box and the name is resolved, then ResolveRecipient returns the AddressEntry property of the resolved Recipient object. If the user cancels the Select Names dialog box, ResolveRecipient returns null.

private void ResolveRecipients(Outlook.Recipients recips) 
{ 
    if (recips == null) 
    { 
        throw new ArgumentNullException(); 
    } 
    if (recips.ResolveAll()) 
    { 
        return; 
    } 
    else 
    { 
        for(int i = recips.Count; i > 0; i--) 
        { 
            if (!recips[i].Resolve()) 
            { 
                Outlook.SelectNamesDialog snd =  
                    Application.Session. 
                    GetSelectNamesDialog(); 
                snd.Recipients.Add(recips[i].Name); 
                snd.NumberOfRecipientSelectors =  
                    Outlook.OlRecipientSelectors.olShowTo; 
                snd.AllowMultipleSelection = false; 
                snd.Display(); 
                if (!snd.Recipients.ResolveAll()) 
                { 
                    recips.Remove(i); 
                } 
                else 
                { 
                    recips.Remove(i); 
                    recips.Add(snd.Recipients[1].Address); 
                } 
                snd = null; 
            } 
        } 
    } 
} 
NoteNote

The Check Names dialog box and the Select Names dialog box are parented to the main Outlook window. The Check Names dialog box is modal to the Select Names dialog box. The Select Names dialog box is modeless. You cannot parent these dialog boxes to your own custom dialog box.

Obtaining the SMTP Address of a Recipient

The Recipient object does not directly expose the SMTP address of a resolved recipient. However, you can use the PropertyAccessor object to obtain the MAPI property PR_SMTP_ADDRESS. The following GetSMTPAddress method returns the SMTP address of a resolved recipient.

private string GetSMTPAddress(Outlook.Recipient recip) 
{ 
    const string PR_SMTP_ADDRESS = 
        "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"; 
    if (recip != null) 
    { 
        if (!recip.Resolved) 
        { 
            return null; 
        } 
        else 
        { 
            Outlook.PropertyAccessor pa = recip.PropertyAccessor; 
            try 
            { 
                string smtpAddress = 
                    pa.GetProperty(PR_SMTP_ADDRESS).ToString(); 
                return smtpAddress; 
            } 
            catch { return null; } 
        } 
    } 
    else 
    { 
        throw new ArgumentNullException(); 
    } 
}

The AddressLists Collection and AddressList Objects

The AddressLists collection represents all address lists available in the current profile. You obtain an instance of the AddressLists collection from the AddressLists property of the Namespace object.

Enumerating AddressList Objects

To enumerate the AddressList objects in the AddressLists collection, use a for-each construct as shown in the following example. This example creates a string that contains the Name, ResolutionOrder, IsReadOnly, and IsInitialAddressList properties of the AddressList object and writes the string to the trace listeners of the Listeners collection.

private void EnumerateAddressLists() 
{ 
    Outlook.AddressLists addrLists =  
        Application.Session.AddressLists; 
    foreach (Outlook.AddressList addrList in addrLists) 
    { 
        StringBuilder sb = new StringBuilder(); 
        sb.AppendLine("Display Name: " + addrList.Name); 
        sb.AppendLine("Resolution Order: "  
            + addrList.ResolutionOrder.ToString()); 
        sb.AppendLine("Read-only : "  
            + addrList.IsReadOnly.ToString()); 
        sb.AppendLine("Initial Address List: "  
            + addrList.IsInitialAddressList.ToString()); 
        sb.AppendLine(""); 
        Debug.WriteLine(sb.ToString()); 
    } 
}

The AddressListType Property

To determine the type of AddressList object, you should use the new AddressListType property. This property returns an OlAddressListType constant. Valid OlAddressListType values are shown in Table 7-1.

Table 7-1. OlAddressListType values

Value

Description

OlCustomAddressList

A custom address book provider

OlExchangeContainer

A container for address lists on an Exchange server

olExchangeGlobalAddressList

An Exchange GAL

olOutlookAddressList

An address list that corresponds to the Outlook Contacts Address Book

olOutlookLdapAddressList

An address list that uses LDAP

Determining Resolution Order of Address Lists

New to Outlook 2007, the ResolutionOrder property lets you determine the resolution order for a specific AddressList object. The ResolutionOrder property indicates the order that Outlook uses to resolve recipient addresses.

NoteNote

The order of resolution for the ResolutionOrder property is one-based. The first AddressList object to be used for resolving recipient names has a ResolutionOrder value equal to 1. If an AddressList object is not used to resolve addresses, then its ResolutionOrder property has a value of –1.

The ResolutionOrder property corresponds to the position of the address list in the When Sending Mail, Check Names Using These Address Lists In The Following Order list box in the Addressing dialog box shown in Figure 7-2. To access the Addressing dialog box, click Tools. In the Address Book dialog box, click Options.

Figure 7-2. The Addressing dialog box controls resolution order

Addressing dialog box controls resolution order

The ResolutionOrder property is read-only. You cannot change the resolution order of an address list through the Outlook object model.

Finding a Specific AddressList Object

The AddressLists collection does not support an explicit method to find an address list. Because the AddressLists collection is generally a small collection, you can simply iterate over the collection and find the specific AddressList object by performing a name comparison. There are some helper methods that have been introduced in Outlook 2007 to return the GAL in particular. Because the name of the GAL is dependent on the locale, Outlook 2007 introduces the GetGlobalAddressList method on the Namespace object. The following code sample displays a message with the number of address entries in the GAL.

private void DemoGetGlobalAddressList() 
{ 
    Outlook.AddressList gal =  
        Application.Session.GetGlobalAddressList(); 
    string message = "There are " + gal.AddressEntries.Count  
        + " entries in the GAL."; 
    MessageBox.Show(message, "Global Address List",  
        MessageBoxButtons.OK, MessageBoxIcon.Information); 
}

Determining the Contacts Folder for a Contacts Address Book

One of the problems that troubled developers in past versions of Outlook was the inability to obtain a reference to the Contacts folder that corresponded to a given CAB. Because multiple CABs can have the same name, resolving the address book name to a Contact folder name was not productive. In Outlook 2007, the GetContactsFolder method on the AddressList object solves this problem for you. If the AddressList object represents a Contacts folder, then GetContactsFolder will return a Folder object that represents the Contacts folder. If the AddressList object does not represent a Contacts folder or the Contacts folder cannot be found (in the case of a Contacts folder in the Public Folders store), then GetContactsFolder returns null (Nothing in Visual Basic).

To demonstrate how this works in practice, take a look at the following code sample. This sample uses the GetDefaultFolder method to return the default Contacts folder. Once you’ve obtained a Folder object representing the default Contacts folder, you enumerate the AddressLists collection and use GetContactsFolder to find the AddressList object that represents the default Contacts folder (see Figure 7-3). You compare the EntryID values of these two folder objects using the new CompareEntryIDs method of the Namespace object. Once you have a match, you set the InitialAddressList property of the SelectNamesDialog object to the AddressList object that represents the default Contacts folder. When you set this property of the SelectNamesDialog object, you cause the specified AddressList object to be displayed first in the Outlook Address Book no matter what the default settings are for the initial address list. Finally, the Outlook Address Book is displayed by calling the Display method of the SelectNamesDialog object.

private void ShowContactsFolderAsInitialAddressList() 
{ 
    Outlook.AddressLists addrLists; 
    Outlook.Folder contactsFolder =  
        Application.Session.GetDefaultFolder( 
        Outlook.OlDefaultFolders.olFolderContacts)  
        as Outlook.Folder; 
    addrLists = Application.Session.AddressLists; 
    foreach(Outlook.AddressList addrList in addrLists) 
    { 
        Outlook.Folder testFolder = 
            addrList.GetContactsFolder() as Outlook.Folder; 
        if (testFolder != null) 
        { 
            // Test to determine if Folder returned 
            // by GetContactsFolder has same EntryID 
            // as default Contacts folder. 
            if (Application.Session.CompareEntryIDs( 
                contactsFolder.EntryID, testFolder.EntryID)) 
            { 
                Outlook.SelectNamesDialog snd =  
                    Application. 
                    Session.GetSelectNamesDialog(); 
                snd.InitialAddressList = addrList; 
                snd.Display(); 
            } 
        } 
    } 
}

Figure 7-3. Use the GetContactsFolder method to display the Contacts address list

GetContactsFolder method displays Contacts

The AddressEntries Collection and AddressEntry Object

The AddressEntries collection and AddressEntry object let you access the contents of an individual AddressList object. The AddressEntries object represents the collection of AddressEntry objects in the parent AddressList object. The AddressEntry object represents an individual address entry in an address list. The AddressEntry object has been enhanced in Outlook 2007 so that you can accurately determine the type of the AddressEntry object. For users connected to an Exchange server, Outlook 2007 introduces two objects that derive from the base AddressEntry object, the ExchangeUser and ExchangeDistributionList objects. Later in this chapter you’ll see how these new objects make your development work easier when discovering information about an Exchange user. If your organization has implemented an organizational hierarchy in Active Directory, you can use the ExchangeUser object to build an organizational chart or traverse the hierarchy by understanding manager and direct reports relationships.

To enumerate addresses in an address list, you obtain the AddressEntries collection from the AddressEntries property of the AddressList object. The following code sample enumerates the first 100 primary SMTP addresses in the GAL. To obtain the SMTP address for an AddressEntry object, you must cast it to an ExchangeUser or ExchangeDistributionList object using the GetExchangeUser or GetExchangeDistributionList methods on the AddressEntry object. In the case of an AddressEntry object that represents an Exchange user, this method returns an ExchangeUser object that exposes properties of the AddressEntry object in a first-class manner. Instead of using property tags as required by Collaboration Data Objects 1.21, you use the correct ExchangeUser property such as JobTitle, Department, Alias, PhoneNumber, or PrimarySMTPAddress.

private void EnumerateGAL() 
{ 
    Outlook.AddressList gal =  
        Application.Session.GetGlobalAddressList(); 
    if (gal != null) 
    { 
        for (int i = 1;  
            i <= Math.Min(100,gal.AddressEntries.Count -1); i++) 
        { 
            Outlook.AddressEntry addrEntry = 
                gal.AddressEntries[i]; 
            if(addrEntry.AddressEntryUserType ==  
                Outlook.OlAddressEntryUserType. 
                olExchangeUserAddressEntry 
                || addrEntry.AddressEntryUserType == 
                Outlook.OlAddressEntryUserType. 
                olExchangeRemoteUserAddressEntry) 
            { 
                Outlook.ExchangeUser exchUser =  
                    addrEntry.GetExchangeUser(); 
                Debug.WriteLine(exchUser.Name + " "  
                    + exchUser.PrimarySmtpAddress); 
            } 
            if (addrEntry.AddressEntryUserType == 
                Outlook.OlAddressEntryUserType. 
                olExchangeDistributionListAddressEntry) 
            { 
                Outlook.ExchangeDistributionList exchDL =  
                    addrEntry.GetExchangeDistributionList(); 
                Debug.WriteLine(exchDL.Name + " "  
                    + exchDL.PrimarySmtpAddress); 
            } 
        } 
    } 
}

The AddressEntryUserType Property

To determine the type of AddressEntry object, you should use the new AddressEntryUserType property. This property returns an OlAddressEntryUserType constant. Valid OlAddressEntryUserType values are shown in Table 7-2.

Table 7-2. OlAddressEntryUserType values

Value

Description

olExchangeAgentAddressEntry

An address entry that is an Exchange agent.

olExchangeDistributionListAddressEntry

An address entry that is an Exchange distribution list.

olExchangeOrganizationAddressEntry

An address entry that is an Exchange organization.

olExchangePublicFolderAddressEntry

An address entry that is an Exchange public folder.

olExchangeRemoteUserAddressEntry

An Exchange user that belongs to a different Exchange forest.

olExchangeUserAddressEntry

An Exchange user that belongs to the same Exchange forest.

olLdapAddressEntry

An address entry that uses LDAP.

olOtherAddressEntry

A custom or some other type of address entry such as FAX or MOBILE.

olOutlookContactAddressEntry

An address entry in an Outlook Contacts folder.

olOutlookDistributionListAddressEntry

An address entry that is an Outlook distribution list.

olSmtpAddressEntry

An address entry that uses SMTP.

Finding a Specific AddressEntry Object

The Outlook object model does not provide a method to find a specific AddressEntry object in the AddressEntries collection. You also cannot restrict the AddressEntries collection to return a subset of AddressEntry objects. If you need to find a specific AddressEntry object in an AddressList object, you must enumerate the list to find a match. However, you can use recipient resolution to perform a function similar to finding a specific address entry. See the section "Resolving Recipients" earlier in this chapter.

The GetAddressEntryFromID Method

If you have the EntryID value of an AddressEntry object, you can use the GetAddressEntryFromID method of the Namespace object to return the AddressEntry object represented by the EntryID value. GetAddressEntryFromID is new to Outlook 2007. The GetSenderSMTPAddress procedure uses the GetAddressEntryFromID method to return an AddressEntry object that represents the sender of a message.

Although the Outlook object model provides you with the ability to return the SenderName and SenderEmailAddress properties for a MailItem object, these properties don’t correlate to a unique SMTP address. To obtain the EntryID value of the sender’s AddressEntry, the code uses the PropertyAccessor object to return the MAPI property PR_SENT_REPRESENTING_ENTRYID. This property always represents the sender of the message rather than the delegate in a delegate scenario. In the case of a delegate scenario, the PR_SENDER_ENTRYID would represent the delegate rather than the delegator.

private string GetSenderSMTPAddress(Outlook.MailItem mail) 
{ 
    if (mail == null) 
    { 
        throw new ArgumentNullException(); 
    } 
    string PR_SENT_REPRESENTING_ENTRYID = 
        @"http://schemas.microsoft.com/mapi/proptag/0x00410102"; 
    string PR_SMTP_ADDRESS = 
        @"http://schemas.microsoft.com/mapi/proptag/0x39FE001E"; 
    if (mail.SenderEmailType == "EX") 
    { 
        string senderEntryID = 
            mail.PropertyAccessor.BinaryToString( 
            mail.PropertyAccessor.GetProperty( 
            PR_SENT_REPRESENTING_ENTRYID)); 
        Outlook.AddressEntry sender = 
            Application.Session. 
            GetAddressEntryFromID(senderEntryID); 
        if (sender != null) 
        { 
            // Now we have an AddressEntry representing the Sender.
            if (sender.AddressEntryUserType == 
                Outlook.OlAddressEntryUserType. 
                olExchangeUserAddressEntry 
                || sender.AddressEntryUserType == 
                Outlook.OlAddressEntryUserType. 
                olExchangeRemoteUserAddressEntry) 
            { 
                // Use the ExchangeUser object PrimarySMTPAddress.
                Outlook.ExchangeUser exchUser = 
                    sender.GetExchangeUser(); 
                if (exchUser != null) 
                { 
                    return exchUser.PrimarySmtpAddress; 
                } 
                else 
                { 
                    return null; 
                } 
            } 
            else 
            { 
                return sender.PropertyAccessor.GetProperty( 
                    PR_SMTP_ADDRESS) as string; 
            } 
        } 
        else 
        { 
            return null; 
        } 
    } 
    else 
    { 
        return mail.SenderEmailAddress; 
    } 
}

Displaying AddressEntry Details

To display the Details dialog box for an address entry, you call the Details method of the AddressEntry object. The dialog box displayed depends on the type of address entry. If the AddressEntry object represents an Exchange user, then a dialog box similar to Figure 7-4 is displayed. If the AddressEntry object represents an Exchange distribution list, then a dialog box similar to Figure 7-5 is displayed.

Figure 7-4. Details dialog box for an AddressEntry object that represents an Exchange user

AddressEntry object that represents Exchange user

Figure 7-5. Details dialog box for an AddressEntry object that represents an Exchange distribution list

AddressEntry object representing distribution list

If the AddressEntry object represents an Outlook contact, then a Contact Inspector will be displayed. If the AddressEntry object represents an Outlook personal distribution list, an Outlook distribution list Inspector will appear. If the AddressEntry object represents an SMTP address, then a dialog box similar to Figure 7-6 will be displayed.

Figure 7-6. Details dialog box for an SMTP AddressEntry object

Details dialog box for an SMTP AddressEntry object

Getting Availability Information for a User

You can determine whether someone is available at a given time using the GetFreeBusy method of the AddressEntry object. This method returns a string representing 30 days of availability (also known as free/busy) information starting at midnight on a specified date. Each character in the string indicates whether the person is available during a specified time period. The CompleteFormat parameter of the GetFreeBusy method allows you to specify the granularity of availability details.

If CompleteFormat is set to false, the default value, the string returned by the GetFreeBusy method contains one of the characters shown in Table 7-3 for each time slot in the availability string.

Table 7-3. CompleteFormat equals false

Character

Description

0

The time slot represents a free period.

1

The time slot represents a tentative, out of office, or busy period.

If CompleteFormat is set to true, the string returned by the GetFreeBusy method contains one of the characters shown in Table 7-4 for each time slot in the availability string.

Table 7-4. CompleteFormat equals true

Character

Description

0

The time slot represents a free period.

1

The time slot represents a tentative period.

2

The time slot represents a busy period.

3

The time slot represents an out of office period.

For example, the following statement returns a string 1,440 characters long (48 half-hour periods over 30 days) containing 0 for each half-hour period the person is free, 1 for each period the person has a busy time marked tentative, 3 for each period the person has a busy time marked out of office, and 2 for other busy periods.

string status = myAddressEntry.GetFreeBusy("7/1/07", 30, true);

The following statement returns a string 720 characters long (24 one-hour periods over 30 days) containing 0 for each hour the person is free and 1 for each hour the person is busy, regardless of how the busy periods are designated.

string status = myAddressEntry.GetFreeBusy("7/1/07", 60, false);

The following code sample displays the next time that the user’s manager has an open time slot with a duration of 60 minutes. Note that this code sample makes assumptions about the manager’s working hours and compares the free/busy string character representing a time slot to default working hours. If you want to expand this sample to use actual working hours, take a look at the GetWorkHoursXML sample in the section "GetStorage Method" in Chapter 6. If you have sufficient permission on another user’s calendar, you can obtain working hours from that user’s Calendar folder.

private void GetManagerOpenInterval() 
{ 
    const int slotLength = 60; 
    Outlook.AddressEntry addrEntry =  
        Application.Session.CurrentUser.AddressEntry; 
    if (addrEntry.Type == "EX") 
    { 
        Outlook.ExchangeUser manager = 
            Application.Session.CurrentUser. 
            AddressEntry.GetExchangeUser().GetExchangeUserManager(); 
        if (manager != null) 
        { 
            string freeBusy = manager.GetFreeBusy( 
                DateTime.Now, slotLength, true); 
            for (int i = 1; i < freeBusy.Length; i++) 
            { 
                if (freeBusy.Substring(i, 1) == "0") 
                { 

                    // Get number of minutes into 
                    // the day for free interval.
                    double busySlot = (i - 1) * slotLength; 

                    // Get an actual date/time.
                    DateTime dateBusySlot = 
                        DateTime.Now.Date.AddMinutes(busySlot); 

                    // dateBusySlot.AddMinutes(busySlot); 
                    if (dateBusySlot.TimeOfDay >= 
                        DateTime.Parse("8:00 AM").TimeOfDay & 
                        dateBusySlot.TimeOfDay <= 
                        DateTime.Parse("5:00 PM").TimeOfDay & 
                        !(dateBusySlot.DayOfWeek == 
                        DayOfWeek.Saturday | 
                        dateBusySlot.DayOfWeek == DayOfWeek.Sunday)) 
                    { 
                        StringBuilder sb = new StringBuilder(); 
                        sb.AppendLine(manager.Name  
                            + " first open interval:"); 
                        sb.AppendLine(dateBusySlot.ToString("f")); 
                        Debug.WriteLine(sb.ToString()); 
                    } 
                } 
            } 
        } 
    } 
}
NoteNote

You cannot obtain availability information for an AddressEntry object that represents an Exchange distribution list. If you need to determine availability information for members of a distribution list, you should obtain the members of the list by using the GetExchangeDistributionListMembers method. Once you have an AddressEntries collection that represents the members of the list, determine if the AddressEntry object in the collection represents an ExchangeUser object. If the AddressEntry object represents an ExchangeUser object, then call the GetFreeBusy method on each individual ExchangeUser object in the distribution list.

The ExchangeUser Object

The ExchangeUser object provides detailed information about an AddressEntry object that represents an Exchange mailbox user. The ExchangeUser object is derived from the AddressEntry object and is returned instead of an AddressEntry object when the caller performs a query interface on the AddressEntry object. To perform the cast, just call the GetExchangeUser method on the AddressEntry object.

Working with ExchangeUser Properties

The ExchangeUser object provides first-class access to properties applicable to Exchange users such as FirstName, LastName, JobTitle, and OfficeLocation. This object also implements properties for Japanese phonetic rendering (yomigana) of the following properties:

  • YomiCompanyName

  • YomiDepartment

  • YomiDisplayName

  • YomiFirstName

  • YomiLastName

If these properties are not supported on the version of Exchange Server on which the user’s mailbox is located, they will return an empty string.

You can also access other custom properties specific to the Exchange user that are not exposed in the object model through the PropertyAccessor object. An example of an Exchange custom property would be a property that represents the EmployeeID of the mailbox user (defined as an extension to the Active Directory schema) or a legacy Exchange custom attribute property.

NoteNote

Some of the explicit built-in properties on the ExchangeUser object are read/write properties. Setting these properties requires the code to be running under an appropriate Exchange administrator account. Without sufficient permissions, calling the ExchangeUser.Update method will result in a Permission Denied error. Outlook raises the error when you attempt to save the underlying AddressEntry object rather than when you set the property.

Obtaining an ExchangeUser Object from an AddressEntry Object

To obtain an ExchangeUser object from an AddressEntry object, you call the GetExchangeUser method on an AddressEntry object. The following procedure obtains the AddressEntry property for the Recipient object returned by Namespace.CurrentUser. If the AddressEntry object represents an Exchange mailbox user, then the GetExchangeUser method is called to return an ExchangeUser object. The Name, PrimarySMTPAddress, JobTitle, Department, OfficeLocation, BusinessTelephoneNumber, and MobileTelephoneNumber properties are written to the trace listeners of the Listeners collection.

private void GetCurrentUserInfo() 
{ 
    Outlook.AddressEntry addrEntry = 
        Application.Session.CurrentUser.AddressEntry; 
    if (addrEntry.Type == "EX") 
    { 
        Outlook.ExchangeUser currentUser = 
            Application.Session.CurrentUser. 
            AddressEntry.GetExchangeUser(); 
        if (currentUser != null) 
        { 
            StringBuilder sb = new StringBuilder(); 
            sb.AppendLine("Name: "  
                + currentUser.Name); 
            sb.AppendLine("STMP address: " 
                + currentUser.PrimarySmtpAddress); 
            sb.AppendLine("Title: "  
                + currentUser.JobTitle); 
            sb.AppendLine("Department: "  
                + currentUser.Department); 
            sb.AppendLine("Location: "  
                + currentUser.OfficeLocation); 
            sb.AppendLine("Business phone: "  
                + currentUser.BusinessTelephoneNumber); 
            sb.AppendLine("Mobile phone: "  
                + currentUser.MobileTelephoneNumber); 
            Debug.WriteLine(sb.ToString()); 
        } 
    } 
}

The GetExchangeUserManager Method

The GetExchangeUserManager method returns an ExchangeUser object that represents the manager of an ExchangeUser object in the organizational hierarchy. The logged-on user must be online for this method to return an ExchangeUser object. If the user is not online, then GetExchangeUserManager will return null (Nothing in Visual Basic). Your code should test for this possibility. Similar to the GetCurrentUser procedure earlier, this routine writes manager information to the trace listeners of the Listeners collection.

private void GetManagerInfo() 
{ 
    Outlook.AddressEntry currentUser = 
        Application.Session.CurrentUser.AddressEntry; 
    if (currentUser.Type == "EX") 
    { 
        Outlook.ExchangeUser manager = 
            currentUser.GetExchangeUser().GetExchangeUserManager(); 
        if (manager != null) 
        { 
            StringBuilder sb = new StringBuilder(); 
            sb.AppendLine("Name: " 
                + manager.Name); 
            sb.AppendLine("STMP address: " 
                + manager.PrimarySmtpAddress); 
            sb.AppendLine("Title: " 
                + manager.JobTitle); 
            sb.AppendLine("Department: " 
                + manager.Department); 
            sb.AppendLine("Location: " 
                + manager.OfficeLocation); 
            sb.AppendLine("Business phone: " 
                + manager.BusinessTelephoneNumber); 
            sb.AppendLine("Mobile phone: " 
                + manager.MobileTelephoneNumber); 
            Debug.WriteLine(sb.ToString()); 
        } 
    } 
}

The GetDirectReports Method

The GetDirectReports method returns an AddressEntries collection that represents the address entries for all the direct reports of a given Exchange user. If the user has no direct reports, then GetDirectReports().Count will equal zero (0). The logged-on user must be online for this method to return an AddressEntries collection. If the user is not online, GetDirectReports will return null (Nothing in Visual Basic). Your code should test for this possibility. The following procedure obtains a reference to the current user’s manager and then writes information about each of the manager’s direct reports to the trace listeners of the Listeners collection.

private void GetManagerDirectReports() 
{ 
    Outlook.AddressEntry currentUser = 
        Application.Session.CurrentUser.AddressEntry; 
    if (currentUser.Type == "EX") 
    { 
        Outlook.ExchangeUser manager = 
            currentUser.GetExchangeUser().GetExchangeUserManager(); 
        if (manager != null) 
        { 
            Outlook.AddressEntries addrEntries =  
                manager.GetDirectReports(); 
            if (addrEntries != null) 
            { 
                foreach (Outlook.AddressEntry addrEntry 
                    in addrEntries) 
                { 
                    Outlook.ExchangeUser exchUser =  
                        addrEntry.GetExchangeUser(); 
                    StringBuilder sb = new StringBuilder(); 
                    sb.AppendLine("Name: " 
                        + exchUser.Name); 
                    sb.AppendLine("Title: " 
                        + exchUser.JobTitle); 
                    sb.AppendLine("Department: " 
                        + exchUser.Department); 
                    sb.AppendLine("Location: " 
                        + exchUser.OfficeLocation); 
                    Debug.WriteLine(sb.ToString()); 
                } 
            } 
        } 
    } 
}

The GetMemberOfList Method

The GetMemberOfList method returns an AddressEntries collection that represents the address entries for all distribution lists where the Exchange user is a member. If the user is not a member of any distribution lists, then GetMemberOfList().Count will equal zero (0). The logged-on user must be online for this method to return an AddressEntries collection. If the user is not online, GetMemberOfList will return null (Nothing in Visual Basic). Your code should test for this possibility. The following procedure obtains a reference to the current user and then writes information about each of the user’s distribution lists to the trace listeners of the Listeners collection.

private void GetCurrentUserMembership() 
{ 
    Outlook.AddressEntry currentUser = 
        Application.Session.CurrentUser.AddressEntry; 
    if (currentUser.Type == "EX") 
    { 
        Outlook.ExchangeUser exchUser =  
            currentUser.GetExchangeUser(); 
        if (exchUser != null) 
        { 
            Outlook.AddressEntries addrEntries = 
                exchUser.GetMemberOfList(); 
            if (addrEntries != null) 
            { 
                foreach (Outlook.AddressEntry addrEntry 
                    in addrEntries) 
                { 
                    Debug.WriteLine(addrEntry.Name); 
                } 
            } 
        } 
    } 
}

Obtaining Proxy Addresses for an ExchangeUser Object

The ExchangeUser object does not directly expose the proxy addresses for the user. However, you can use the PropertyAccessor object to obtain the MAPI property PR_EMS_AB_PROXY_ADDRESSES. This property is a multivalued string property that contains all the foreign addresses for a given user. The following GetSMTPAddress procedure returns an array of strings containing the proxy addresses for the ExchangeUser object passed as a method argument.

private string[] GetProxyAddresses(Outlook.ExchangeUser exchUser) 
{ 
    const string PR_EMS_AB_PROXY_ADDRESSES = 
        "http://schemas.microsoft.com/mapi/proptag/0x800F101E"; 
    if (exchUser != null) 
    { 
        return exchUser.PropertyAccessor.GetProperty( 
            PR_EMS_AB_PROXY_ADDRESSES) as string[]; 
    } 
    else 
    { 
        throw new ArgumentNullException(); 
    } 
}

The ExchangeDistributionList Object

The ExchangeDistributionList object provides detailed information about an AddressEntry object that represents an Exchange distribution list. The ExchangeDistributionList object is derived from the AddressEntry object and is returned instead of an AddressEntry object when the caller performs a query interface on the AddressEntry object. To perform the cast, just call the GetExchangeDistributionList method on the AddressEntry object.

Compared to the ExchangeUser object, ExchangeDistributionList exposes a limited number of properties such as Alias, Comments, and PrimarySMTPAddress. However, this object does allow you to enumerate the members of the list, return an AddressEntries collection that contains the owners of the distribution list, and determine distribution list membership.

To obtain an ExchangeDistributionList object from an AddressEntry object, call the GetExchangeDistributionList method on an AddressEntry object.

The GetExchangeDistributionListMembers Method

The GetExchangeDistributionListMembers method returns an AddressEntries collection that contains all the members of the list. Because distribution lists can be nested inside of other distribution lists, the AddressEntries collection returned by GetExchangeDistributionListMembers can represent any type of Exchange AddressEntry object. The logged-on user must be online for this method to return an AddressEntries collection. If the user is not online, GetExchangeDistributionListMembers will return null (Nothing in Visual Basic). Your code should test for this possibility.

The following code sample displays the All Groups container of the Select Names dialog box. When the user selects a distribution list from the list, the distribution list members are written to the trace listeners of the Listeners collection.

Important noteImportant

Expanding distribution list members programmatically can place a performance burden on an Exchange server. Use the GetExchangeDistributionListMembers method cautiously, and understand that your code will be slow when expanding large distribution lists.

private void GetDistributionListMembers() 
{ 
    Outlook.SelectNamesDialog snd = 
        Application.Session.GetSelectNamesDialog(); 
    Outlook.AddressLists addrLists = 
        Application.Session.AddressLists; 
    foreach (Outlook.AddressList addrList in addrLists) 
    { 
        if (addrList.Name == "All Groups") 
        { 
            snd.InitialAddressList = addrList; 
            break; 
        } 
    } 
    snd.NumberOfRecipientSelectors =  
        Outlook.OlRecipientSelectors.olShowTo; 
    snd.ToLabel = "D/L"; 
    snd.ShowOnlyInitialAddressList = true; 
    snd.AllowMultipleSelection = false; 
    snd.Display(); 
    if(snd.Recipients.Count > 0) 
    { 
        Outlook.AddressEntry addrEntry =  
            snd.Recipients[1].AddressEntry; 
        if (addrEntry.AddressEntryUserType ==  
            Outlook.OlAddressEntryUserType. 
            olExchangeDistributionListAddressEntry) 
        { 
            Outlook.ExchangeDistributionList exchDL = 
                addrEntry.GetExchangeDistributionList(); 
            Outlook.AddressEntries addrEntries = 
                exchDL.GetExchangeDistributionListMembers(); 
            if(addrEntries != null) 
                foreach (Outlook.AddressEntry exchDLMember  
                    in addrEntries) 
                { 
                    Debug.WriteLine(exchDLMember.Name); 
                } 
        } 
    } 
}

The GetMemberOfList Method

The GetMemberOfList method returns an AddressEntries collection that represents the address entries for all distribution lists where the Exchange distribution list is a member. If the distribution list is not a member of any other distribution lists, GetMemberOfList returns an AddressEntries collection with Count equal to zero (0). The logged-on user must be online for this method to return an AddressEntries collection. If the user is not online, GetMemberOfList will return null (Nothing in Visual Basic). Your code should test for this possibility.

The GetOwners Method

The GetOwners method returns an AddressEntries collection that represents the address entries for all owners of the Exchange distribution list. If the distribution list has no owners, GetOwners returns an AddressEntries collection with Count equal to zero (0). The logged-on user must be online for this method to return an AddressEntries collection. If the user is not online, GetOwners will return null (Nothing in Visual Basic). Your code should test for this possibility.

The SelectNamesDialog Object

Finally, the Outlook object model will let you display an Outlook Address Book without having to resort to Collaboration Data Objects 1.21, Extended MAPI, or third-party libraries. The SelectNamesDialog object shown in Figure 7-7 displays the Select Names dialog box for the user to select entries from one or more address lists and returns the selected entries in the Recipients collection object returned by the read-only property SelectNamesDialog.Recipients.

To obtain an instance of the SelectNamesDialog instance, you call the GetSelectNamesDialog method on the Namespace object. Once you have an instance of SelectNamesDialog, you set properties or call a method to configure the dialog box in exactly the manner that you desire. To display the dialog box after configuration, you call the Display method. After the dialog box has been displayed, you examine the Recipients property to determine the selected addresses. If the user clicks Cancel or closes the dialog box without selecting recipients, the Recipients property will have a Count value of zero (0).

Figure 7-7. The Select Names dialog box displaying the GAL

Select Names dialog box displaying the GAL

Using the SetDefaultDisplayMode Method

SelectNamesDialog can be used to present the same dialog box in many different variations to the user. Each of these variations can be configured in a locale-independent manner. For example, the Select Names dialog box can be used to select recipients for a message or attendees for an appointment. The SetDefaultDisplayMode method allows you to specify eight different configurations of the dialog box with the OlDefaultSelectNamesDisplayMode enumeration. Valid values for OlDefaultSelectNamesDisplayMode are shown in Table 7-5.

Table 7-5. OlDefaultSelectNamesDisplayMode values

Name

Description

olDefaultDelegates

Displays one edit box for To recipients, uses localized string representing Add for the To button, and localized string representing Add Users for the caption. CcLabel and BccLabel are set to an empty string. Sets AllowMultipleSelection to true and NumberOfRecipientSelectors to olTo.

olDefaultMail

Displays three edit boxes for To, Cc, and Bcc recipients, uses localized strings representing To, Cc, and Bcc for To, Cc, and Bcc buttons, and localized string representing Select Names for the caption. Sets olToCcBcc.

olDefaultMeeting

Displays three edit boxes for Required, Optional, and Resource recipients, uses localized strings representing Required, Optional, and Resources for the To, Cc, and Bcc buttons, and localized string representing Select Attendees and Resources for the caption. Sets AllowMultipleSelection to true and NumberOfRecipientSelectors to olToCcBcc.

olDefaultMembers

Displays one edit box for To recipients, uses localized string representing To for the To button, and localized string representing Select Members for caption. CcLabel and BccLabel are set to an empty string. Sets

AllowMultipleSelection to true and NumberOfRecipientSelectors to olTo.

olDefaultPickRooms

Displays one edit box for Resource recipients, uses localized string representing Rooms for To button, and localized string representing Select Rooms for caption. CcLabel and BccLabel are set to an empty string. Sets AllowMultipleSelection to true and NumberOfRecipientSelectors to olShowTo. InitialDisplayList is set to the GAL.

olDefaultSharingRequest

Displays one edit box for To recipients, uses localized string representing To for To button, and localized string representing Select Names for caption. CcLabel and BccLabel are set to an empty string. Sets AllowMultipleSelection to true and NumberOfRecipientSelectors to olTo.

olDefaultSingleName

Displays no edit boxes for recipients; uses localized string representing Select Name for caption. ToLabel, CcLabel, and BccLabel are set to an empty string. Sets AllowMultipleSelection to false and NumberOfRecipientSelectors to olNone.

olDefaultTask

Displays one edit box for To recipients, uses localized string representing To for To button, and localized string representing Select Task Recipient for caption. CcLabel and BccLabel are set to an empty string. Sets

AllowMultipleSelection to true and NumberOfRecipientSelectors to olTo.

Dialog Caption and Recipient Selectors

If the SetDefaultDisplayMode method doesn’t provide the correct configuration for the dialog box, you can set properties that determine the caption for the dialog box, the number of recipient selectors that appear on the dialog box, and the label for each of the recipient selectors. To change the dialog box caption, set the Caption property on the SelectNamesDialog object. To change the recipient selector labels, set the ToLabel, CcLabel, or BccLabel properties. Each recipient selector corresponds to a different value for the Type property of a Recipient object that is added to a given recipient selector. For example, if the user adds a recipient to the To recipient selector (its actual label does not change Recipient.Type), then Recipient.Type = olMailRecipientType.olTo (1). The Cc recipient selector corresponds to a Recipient.Type = olMailRecipientType.olCC (2), and the Bcc recipient selector makes the Recipient.Type = olMailRecipientType.olBcc (3).

NoteNote

The length of the Caption property that is visible in the dialog box depends on screen resolution. The length of the labels for To, Cc, and Bcc recipient selectors is limited to 32 characters. If the recipient selector label contains more than 32 characters, only the first 32 characters will be displayed on the command button. The recipient selector label will always display –> characters after the label text. To provide an accelerator key for the recipient selector edit boxes, include an ampersand (&) character in the label argument string, immediately before the character that serves as the access key. For example, if ToLabel is Local &Attendees, users can press ALT+A to move the focus to the first recipient selector edit box.

Setting the InitialAddressList Property

The user can control the initial address list in the Select Names dialog box and address list resolution order. See the section "Determining Resolution Order of Address Lists" earlier in this chapter. You can override the user’s preference if you want to show a specific address list first, and you can also show only the initial address list so that other address lists are not available in the Address List drop-down list. To set the initial address list, you set the InitialAddressList property of the SelectNamesDialog object to an AddressList object that represents the initial address list that you want to display.

To show only the initial address list in the dialog box, set the ShowOnlyInitialAddressList property to true. The default value of this property is false, meaning that all address lists are displayed. If you do not set the InitialAddressList property and then set ShowOnlyInitialAddressList to true, the AddressList object with AddressList.IsInitialAddressList equal to true will be the only address list available in the drop-down list box.

The following code sample enumerates the AddressLists collection to find the AddressList object that represents the default Contacts folder. It then displays a customized Select Names dialog box, as shown in Figure 7-8, that allows the user to select addresses from the Contacts Address Book that represent winners of a contest. Finally, the selections are displayed in a message box.

Figure 7-8. Customized Select Names dialog box displaying the Contacts address book

Select Names dialog box displaying Contacts

void DemoSetInitialAddressList() 
{ 
    Outlook.AddressList contactsAddrList = null; 
    Outlook.SelectNamesDialog snd = 
        Application.Session.GetSelectNamesDialog(); 

    // First obtain the default Contacts folder.
    string contactsEntryID = 
        Application.Session.GetDefaultFolder( 
        Outlook.OlDefaultFolders.olFolderContacts).EntryID; 

    // Enumerate AddressLists.
    Outlook.AddressLists addrLists =  
        Application.Session.AddressLists; 
    foreach (Outlook.AddressList addrList in addrLists) 
    { 
        if (addrList.GetContactsFolder() != null) 
        { 

            // GetContactsFolder returns Folder object; compare EntryIDs.
            if (Application.Session.CompareEntryIDs( 
                addrList.GetContactsFolder().EntryID, contactsEntryID)) 
            { 
                contactsAddrList = addrList; 
                break; 
            } 
        } 
        else 
        { 
            MessageBox.Show("Could not find Contacts Address Book.", 
                "Lookup Error",  
                MessageBoxButtons.OK,  
                MessageBoxIcon.Error); 
            return; 
        } 
    } 

    // Set additional properties on SelectNamesDialog.
    snd.Caption = "Special Contest"; 

    // Set InitialAddressList to Contacts folder AddressList.
    snd.InitialAddressList = contactsAddrList; 
    snd.NumberOfRecipientSelectors =  
        Outlook.OlRecipientSelectors.olShowTo; 
    snd.ToLabel = "Award Winner(s)"; 

    // Display.
    snd.Display(); 

    // Enumerate names of selected award winners.
    Outlook.Recipients recips = snd.Recipients; 
    if (recips.Count > 0) 
    { 
        StringBuilder sb = new StringBuilder(); 
        foreach (Outlook.Recipient recip in recips) 
        { 
            sb.AppendLine(recip.Name); 
        } 
        MessageBox.Show(sb.ToString(), 
            "Contest Winners", 
            MessageBoxButtons.OK, 
            MessageBoxIcon.Information); 
    } 
}

Displaying the Select Names Dialog Box

To display the Select Names dialog box, you call the Display method on the SelectNamesDialog object. If the user cancels the dialog box, Recipients.Count will equal zero (0). The Select Names dialog box is modeless and parented to the Outlook application window. When you call the Display method, code execution will halt until the user either clicks OK or dismisses the dialog box.

Using SelectNamesDialog.Recipients

The SelectNamesDialog object has a Recipients property that returns a Recipients collection that allows you to set initial addresses in the dialog box or get the addresses selected by the user. The Recipients property is read-only, so you cannot set the Recipients property to another instance of a Recipients collection. However, you can add recipients to the collection by using the Add method for SelectNamesDialog.Recipients.

If you add a Recipient object to the Recipients collection for the SelectNamesDialog object, be sure to specify the Type property of the Recipient object. Recipient.Type controls the recipient selector in which the Recipient object appears. For example, in the next sample, the Type property for the Recipient object that represents a conference room resource is set to OlMeetingRecipientType.olResource, which represents a value of three (3). The conference room consequently appears in the Resources recipient selector. The default Type for a Recipient object added to the Recipients collection is olTo, which represents a value of one (1).

After you call the Display method, you can enumerate the Recipients collection for the SelectNamesDialog object and add to the Recipients collection for another object such as a MailItem or AppointmentItem. The following code sample uses the SetDefaultDisplayMode method to set the mode to Select Names dialog box for a meeting. It then populates the Resources recipient selector with Conf Room 36/2739. Once the dialog box is displayed to the user, it then enumerates the Recipients collection for the instance of SelectNamesDialog and adds those recipients to the Recipients collection for the meeting request represented by the appt variable. Finally, the code displays the meeting request to the user.

private void DemoSelectNamesDialogRecipients() 
{ 
    Outlook.AppointmentItem appt = Application.CreateItem( 
        Outlook.OlItemType.olAppointmentItem) 
        as Outlook.AppointmentItem; 
    appt.MeetingStatus = Outlook.OlMeetingStatus.olMeeting; 
    appt.Subject = "Team Morale Event"; 
    appt.Start= DateTime.Parse("5/17/2007 11:00 AM"); 
    appt.End=DateTime.Parse("5/17/2007 12:00 PM"); 
    Outlook.SelectNamesDialog snd = 
        Application.Session.GetSelectNamesDialog(); 
    snd.SetDefaultDisplayMode( 
        Outlook.OlDefaultSelectNamesDisplayMode.olDefaultMeeting); 
    Outlook.Recipient confRoom =  
        snd.Recipients.Add("Conf Room 36/2739"); 

    // Explicitly specify Recipient.Type.
    confRoom.Type = (int)Outlook.OlMeetingRecipientType.olResource; 
    snd.Recipients.ResolveAll(); 
    snd.Display(); 

    // Add Recipients to meeting request.
    Outlook.Recipients recips = snd.Recipients; 
    if (recips.Count > 0) 
    { 
        foreach (Outlook.Recipient recip in recips) 
        { 
            appt.Recipients.Add(recip.Name); 
        } 
    } 
    appt.Recipients.ResolveAll(); 
    appt.Display(false); 
}

Summary

In this chapter, you’ve learned how to work with Outlook address lists, address entries, and recipients. Unlike previous versions of Outlook, you can now display an Address Book dialog box using the SelectNamesDialog object so that you can customize the addressing components of your solution. The ExchangeUser and ExchangeDistibutionList objects provide richer objects that are easier to program when you are writing code for users connected to an Exchange server. You can determine organizational hierarchy programmatically by using the new

GetExchangeUserManager and GetDirectReports methods. The new and enhanced addressing objects in Outlook 2007 make it possible to write your code without resorting to Collaboration Data Objects 1.21, Extended MAPI, or third-party libraries.

Additional Resources