What's New in Microsoft Office Outlook 2003 for Developers?

 

Randy Byrne
Micro Eye, Inc.
Microsoft Outlook MVP

February 2004

Applies to:
    Microsoft® Visual Basic® .NET 2003
    Microsoft Office Outlook® 2003
    Microsoft Windows® SharePoint™ Services
    Microsoft Office SharePoint Portal 2003

Summary: Learn how to use Visual Basic .NET to integrate Microsoft Office Outlook 2003 with Microsoft SharePoint™ Products and Technologies. Although changes to the Outlook Object Model are small in scope, new properties are added to support integration with Microsoft Windows SharePoint Services (formerly known as SharePoint Team Services) and Microsoft Office SharePoint Portal Server 2003. The sample Visual Basic .NET Outlook Add-in allows you to import a Contact list from a SharePoint site into Outlook and directly export Outlook Contact items to a SharePoint site. (32 printed pages)

Note   The information in this article that applies to Microsoft Windows SharePoint Services also applies to Microsoft Office SharePoint Portal Server 2003, which is built on the Windows SharePoint Services platform. The code samples can be used on sites created with SharePoint Portal Server.

Download odc_OLWhatsNew2k3Sample.EXE.

Download the odc_OLWhatsNew2k3Sample sample file. (599 KB)

Contents

Introduction
New Objects, Methods, Properties, and Events
Revised and Improved Security Model
Integrating with SharePoint Sites
Conclusion

Introduction

Microsoft® Office Outlook® 2003 offers many new and improved features in terms of performance, connectivity, and usability. The programming enhancements to Outlook are small in scope, with the exception of a major change in Outlook object model security. Previous versions of Outlook blocked many properties and methods to prevent the spread of e-mail worms and viruses. Outlook 2003 trusts all installed Add-ins including Microsoft Outlook Visual Basic® for Applications (VBA) by default in terms of access to previously blocked properties and methods. Outlook developers have an opportunity to create new integration scenarios with Microsoft Windows® SharePoint™ Services. Windows SharePoint Services provides the foundation for Microsoft Office SharePoint Portal Server 2003. Microsoft SharePoint Products and Technologies offer a new Web-based collaboration platform for rapid deployment of team-based Web sites and sharing contacts, tasks, documents, and events among team members. For more information about Microsoft SharePoint Products and Technologies, see the Microsoft SharePoint Products and Technologies home page on MSDN.

New Objects, Methods, Properties, and Events

The changes to the Outlook object model reflect the changes to the Outlook user interface. A small number of these changes relate to integration with SharePoint Products and Technologies. The following tables provide a quick overview of the new objects, methods, properties, and events in the Microsoft Office Outlook object model followed by sample VBA code for some selected events and methods.

Table 1. New objects in the Outlook object model

Name Applies To Description
Conflicts Any Outlook item-type object such as a MailItem object The Conflicts object contains a set of Conflict objects representing all items that are in conflict with a particular Outlook item such as a MailItem, AppointmentItem, TaskItem, and so forth. If the Count property of this object is non-zero, the item is involved in a conflict.
Conflict Conflicts collection object Represents an item that is in conflict with another Outlook item.

Table 2. New methods in the Outlook object model

Name Applies To Description
AddPicture ContactItem object Adds a picture to an Outlook Contact. You must supply the full path to the picture in the Picture argument. If the Contact already has a picture attached to it, this method overwrites the existing picture.
AddStoreEx Namespace object Adds a Personal Folders file (PST) in the specified format to the current profile. Specify the file location of the PST by using the Store argument. Specify the format of the PST with the Type argument. Valid Type arguments are olStoreANSI, olStoreDefault, or olStoreUnicode. Use olStoreANSI to preserve compatibility with Outlook 97-2002 PST formats.
DeselectFolder Explorer object If the Outlook Explorer is currently displaying the Calendar folder specified in the MAPIFolder argument simultaneously with another Calendar folder, the specified folder is closed. Applies to Calendar folders only.
IsFolderSelected Explorer object Returns a Boolean value that determines if the folder specified in the MAPIFolder argument is currently displayed in the Outlook Explorer window.
RemovePicture ContactItem object Removes the picture associated with an Outlook Contact.
Save Search object Saves the Search object using the name specified in the Name argument and returns a MAPIFolder object representing the Search Folder created by the Search object. Create complex search conditions using search syntax explained in the Microsoft Exchange Server 2003 Software Development Kit.
SelectFolder Explorer object Displays the folder specified in the MAPIFolder argument if it can be displayed simultaneously with the current folder in the Outlook Explorer window. If the folder cannot be displayed in a side-by-side view (Calendar folders only), the Explorer CurrentFolder object changes to the specified folder.
SetControlItemProperty Inspector object Binds an Outlook object model property specified in the PropertyName argument to a control on an inspector specified in the Control argument

The following code example creates a Search object that returns all Inbox items with "RE:" in the message subject. Using the new Save method of the Search object, it creates a Search Folder named RE Search and prints the number of items in the Search Folder to the Immediate window. Search Folders are one of the most powerful new features of Outlook. Search Folders allow users to see consolidated search results for items located in multiple Outlook folders based upon criteria such as Large Messages, For Follow Up, or Unread Mail. Search Folders appear under the Search Folders node in the Outlook folder tree as illustrated in Figure 1.

**Note   **A user cannot edit the Criteria for Search Folders that are created programmatically. The Criteria button is disabled in the Custom Search Folder dialog box.

Figure 1. The Search Folders node in Outlook

Sub CreateSearchFolder()
    Dim olApp As Outlook.Application
    Dim objSearch As Outlook.Search
    Dim folInbox As Outlook.MAPIFolder
    Dim strFolderPath As String
    Dim strScope As String
    Dim strFilter As String
    Dim objSearchFolder As Outlook.MAPIFolder
    
    On Error Resume Next
    Set olApp = New Outlook.Application
    'Create a MAPIFolder object for Inbox
    Set folInbox = olApp.GetNamespace("MAPI") _
       .GetDefaultFolder(olFolderInbox)
    'Get the Folder Path
    strFolderPath = folInbox.FolderPath
    'Build a scope string
    strScope = "SCOPE ('shallow traversal of " _
       & AddQuotes(strFolderPath) & "')"
    'Build a filter string (WHERE clause without the WHERE)
    strFilter = AddQuotes("urn:schemas:mailheader:subject") _
       & " LIKE 'RE:%'"
    'Create the Search object by calling AdvancedFind
    Set objSearch = _
       olApp.AdvancedSearch(strScope, strFilter, False, "RE Search")
    'Save the Search as a Search Folder
    Set objSearchFolder = objSearch.Save ("RE Search")
    Debug.Print objSearchFolder.Items.Count
End Sub

Public Function AddQuotes(strText) As String
    On Error Resume Next
    AddQuotes = Chr$(34) & strText & Chr$(34)
End Function

One of the problems frequently encountered in Outlook development is creating a custom form page and control programmatically and binding that control to an Outlook item property. The SetControlItemProperty is a new method of the Outlook object model that lets you set a control binding programmatically. The following code example creates a meeting request item, adds a page named Binding Example and then adds a Text Box control to the Binding Example page. When a user clicks the To. . . button to set attendees for the meeting request, those attendees appear in the text box on the Binding Example page of the Appointment form.

Sub SetControlItemPropertyExample()
    Dim myInspector As Outlook.Inspector
    Dim myAppt As Outlook.AppointmentItem
    Dim ctrl As Object
    Dim ctrls As Object
    Dim myPages As Outlook.Pages
    Dim myPage As Object
    
    Set myAppt = Application.CreateItem(olAppointmentItem)
    Set myInspector = myAppt.GetInspector
    myAppt.MeetingStatus = olMeeting
    myAppt.Subject = "Test Appointment"
    Set myPages = myInspector.ModifiedFormPages
    Set myPage = myPages.Add("Binding Example")
    Set ctrls = myPage.Controls
    Set ctrl = ctrls.Add("Forms.TextBox.1")
    ctrl.Top = 10
    ctrl.Left = 10
    myInspector.SetControlItemProperty ctrl, "To"
    myAppt.Display
End Sub

Table 3. New properties in the Outlook object model

Name Applies To Description
AutoResolvedWinner Any Outlook item-type object such as a MailItem object Returns a read-only Boolean value that determines if the item is a winner of an automatic conflict resolution.
Conflicts Any Outlook item-type object such as a MailItem object The Conflicts object contains a set of Conflict objects representing all items that are in conflict with a particular Outlook item such as a MailItem or AppointmentItem. If the Count property of this object is non-zero, the item is involved in a conflict.
EnableSharedAttachments MailItem object Sets or returns a Boolean value that determines whether the Attachment Options task pane is displayed in the Outlook Inspector for a message. Using the Attachment Options task pane, a user can collaborate using a Document Workspace site instead of exchanging multiple versions of the attachment in e-mail messages.
ExchangeConnectionMode Namespace object Returns an OlExchangeConnectionMode constant that indicates the current connection mode the user is using. Returns olNoExchange in a POP, IMAP, or Hotmail profile.
FlagIcon MailItem or MeetingItem object Returns or sets an olFlagIcon constant indicating one or none of the six flag types supported in Outlook 2003.
HasCoverSheet MailItem object Returns or sets a Boolean value that determines the setting of the Use Cover Sheet option in the Fax user interface, which indicates what is displayed in the body of the mail item.
HasPicture ContactItem object Returns a read-only Boolean value to determine if a ContactItem object has a picture associated with it.
IsIPFax MailItem object Sets or returns a Boolean value that determines if an e-mail item is a fax.
IsSharePointFolder MAPIFolder object Returns a read-only Boolean value that determines if the folder is a folder associated with a SharePoint site.
MeetingWorkspaceURL AppointmentItem or MeetingItem object Returns the URL for the Meeting Workspace site to which the meeting or appointment item is linked.
Permission MailItem object Returns or sets an olPermission constant that determines whether a message has protected contents using Microsoft® Windows® Rights Management (RM) technology.
PermissionService MailItem object Sets or returns an OlPermissionService constant that determines the permission service that is used when sending an e-mail message protected with Windows Rights Management technology.
SenderEmailAddress MailItem, MeetingItem, or PostItem object Returns a read-only String that represents the e-mail address of the sender of the e-mail message, meeting item, or post.
SenderEmailType MailItem, MeetingItem, or PostItem object Returns a read-only String that represents the type of entry for the e-mail address of the sender of the message, meeting item, or post, such as 'SMTP' for an Internet address or 'EX' for a Microsoft Exchange server address.
ShowItemCount MAPIFolder object Sets or returns an OlShowItemCount constant that indicates whether to display the number of unread messages in the folder or the total number of items in the folder in the navigation pane.

Notice that properties such as EnableSharedAttachments, IsSharePointFolder, and MeetingWorkspaceURL relate to Outlook integration with SharePoint Products and Technologies. However, all of these properties only reflect user actions in the Outlook user interface. They do not let you directly create a Meeting Workspace site, Document Workspace site, or linked Contact items. To accomplish some of these actions programmatically, see the "Integrating with SharePoint Sites" section later in this article.

Table 4. New events in the Outlook object model

Name Applies To Description
NewMailEx Event for Application object This event returns a comma-separated string containing the Entry IDs of all new items received in the Inbox. It fires for all items received in the Inbox, including standard messages, meeting requests, and task requests. If you are running in cached Exchange mode, it fires before any client-based rules that might move Inbox items to other mailbox folders. This event fires before the NewMail event.

The NewMailEx event is a welcome addition to the Outlook object model. It provides complete information about new mail items in comparison to the NewMail event, which only fires when New Mail arrives but does not inform you about the specific items that have arrived. The following code fragment shows you how to use the NewMailEx event in Outlook VBA. It prints the message subject to the Immediate window.

Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
    Dim varEntryIDs
    Dim objItem
    Dim i As Integer
    On Error Resume Next
    varEntryIDs = Split(EntryIDCollection, ",")
    For i = 0 To UBound(varEntryIDs)
        Set objItem = Application.Session.GetItemFromID(varEntryIDs(i))
        Debug.Print "NewMailEx " & objItem.Subject
    Next
End Sub

Revised and Improved Security Model

One of the most significant developments for Outlook 2003 developers is a revision of object model security, most commonly known as the Outlook object model guard component of the Outlook E-mail Security Update. The Outlook E-mail Security Update blocks certain properties, methods, and objects in the object model to prevent e-mail worms and viruses from using the object model for malicious purposes. Although some properties are added to the list of blocked properties, in general the security model is improved for Outlook 2003 developers because all installed COM Add-ins (including Outlook VBA code which is in itself an installed Add-in) and VBScript code behind published forms is now trusted from the perspective of the Outlook E-mail Security Update. Your calls to blocked object model properties and methods no longer display the security warning dialog box shown in Figure 2.

Figure 2. The Security Warning dialog box

A Practical Security Example

In order for your calls to blocked object model properties and methods to work without the display of the security warning dialog box shown in Figure 2, you must use the secure Outlook Application object returned in the OnConnection event of a COM Add-in, or the Application object in Outlook VBA or in code behind Outlook forms.

Important   If you use the New keyword to instantiate another instance of the Outlook Application object, all objects that derive from that Application object and their blocked properties and methods cause the Outlook security warning dialog boxes to appear. Therefore, you may need to update some add-ins.

The VBA code in UnTrustedCode displays the security warning dialog box while the code in TrustedCode uses the trusted Application object and does not display security warnings.

Sub UnTrustedCode()
    Dim olApp As New Outlook.Application
    Dim oMail As Outlook.MailItem
    Set oMail = _
        olApp.Session.GetDefaultFolder(olFolderInbox).Items(1)
    MsgBox oMail.SenderEmailAddress, vbInformation
End Sub

Sub TrustedCode()
    Dim olApp As Outlook.Application
    Set olApp = Application
    Dim oMail As Outlook.MailItem
    Set oMail = _
        olApp.Session.GetDefaultFolder(olFolderInbox).Items(1)
    MsgBox oMail.SenderEmailAddress, vbInformation
End Sub

Blocked Properties and Methods

The following table lists the properties and methods that display the Object Model Guard Warning dialog boxes in Outlook 2003. New blocked properties for Outlook 2003 are marked with an asterisk (*).Outlook 2003 adds protection to the body properties of all items including the IMaddress field of contact items, and the wordeditor and htmleditor inspectors.

Table 5. Blocked properties and methods

Object Restricted Properties Restricted Methods
Action   Execute
AddressEntries Any property Any method
AddressEntry Any property Any method
AppointmentItem Body*

Organizer
RequiredAttendees
OptionalAttendees
Resources
NetMeetingOrganizerAlias

Respond

SaveAs

Send

ContactItem Body*

Email1Address
Email1AddressType
Email1DisplayName
Email1EntryID
Email2Address
Email2AddressType
Email2DisplayName
Email2EntryID
Email3Address
Email3AddressType
Email3DisplayName
Email3EntryID

IMAddress*
NetMeetingAlias
ReferredBy

SaveAs
DistListItem Body* GetMember

SaveAs

Inspector HTMLEditor*

WordEditor*

 
ItemProperties Any restricted property for an Item  
JournalItem Body*

ContactNames

SaveAs
MailItem Body*

HTLMBody*

SenderEmailAddress*
SenderEmailType*

SenderName

SentOnBehalfOfName
ReceivedByName
ReceivedOnBehalfOfName
ReplyRecipientNames
To
Cc
Bcc

SaveAs

Send

MeetingItem Body*

SenderName

SaveAs
NameSpace CurrentUser

GetRecipientFromID

 
PostItem Body*

HTMLBody*

SenderName

SaveAs
Recipient Any property Any method
Recipients Any property Any method
TaskItem Body*

ContactNames
Contacts
Delegator
Owner
StatusUpdateRecipients
StatusOnCompletionRecipients

SaveAs

Send

UserProperties   Find
UserProperty Formula  

Outlook Security in the Context of Microsoft Exchange Server

The revised security model discussed previously applies to Outlook using default security settings. Exchange Administrators can still use the Outlook Security Settings public folder and the Administrative form to create customized security settings for object model calls and Trusted Add-ins.

If you use the Administrative form to establish new default security settings and exception groups for your organization, these settings override the default security settings for Outlook. In summary, Administrators must decide whether to:

  • Use the list of trusted Add-ins in the security form
  • Trust all installed Add-ins
  • Trust no Add-ins

These settings are controlled by using the AddinTrust registry key. When an Add-in is trusted, calls to blocked methods and properties will not display the Outlook security dialogs. The AddinTrust key is located under Software\Policies\Microsoft\Office\11.0\Outlook\Security. Administrators can use the Custom Installation Wizard to rollout this key for new Office installations or the Custom Maintenance Wizard to add the key to existing installations. Both the Custom Installation Wizard and Custom Maintenance Wizard are available as components of the Office 2003 Editions Resource Kit.

0- Look to CheckAdminSettings key for COM Add-in trust setting. The CheckAdminSettings key determines if Outlook uses the Administrative Form to determine if an add-in is in the list of trusted add-ins. If the CheckAdminSettings key is present under Software\Policies\Microsoft\Office\11.0\Outlook\Security, only trust the add-ins in the trusted add-ins list on the Administrative Form. If CheckAdminSettings key is not present, then Trust all installed COM Add-ins.

1- Trust all installed COM Add-ins

2- Trust no installed COM Add-ins

The benefit to the second setting (1) is that administrators can use the security form for all other settings without having to explicitly trust each Add-in on the security form.

For more information about Outlook security settings for Exchange Administrators, see Customizing Outlook 2003 to Help Prevent Viruses.

Additional Security Changes for COM Add-ins

For administrators who want an extra level of security regarding trusted code privileges, Outlook observes some new security settings introduced in Microsoft Office System. Previously, Office applications used Low, Medium, and High security levels to control code execution on an application-by-application basis for Office applications. Office 2003 still observes application-by-application security levels for code execution. However, the Microsoft Office System introduces a new setting for Very High security. The Very High security option is shown on the Security Level page of the Macro Security dialog box shown Figure 3.

Figure 3. Setting the macro security level

The Macro Security option operates in conjunction with the Trusted Publishers page on the Security dialog box.

Figure 4. Trusting all installed add-ins and templates

Unlike previous versions of Outlook, Outlook 2003 exposes a check box that allows you to control whether or not installed Add-ins are trusted or not. The default macro security level is High and the default is to trust all installed add-ins and templates. Administrators can control the default security levels with the Office System Custom Installation Wizard. For more information, see Methods of Customizing Office. If you clear the Trust all installed add-ins and templates check box and the macro security setting is set to the default High Security level, then only digitally signed Add-ins are trusted to load. The actual load behavior of the Add-in depends upon the LoadBehavior setting in the Windows Registry. Most Add-ins are set to load on Outlook startup. The Add-in must be signed with a Class 3 code-signing certificate. For more information about Class 3 code-signing certificates, see Code Signing Digital IDs. The following table shows how VBA and Add-in code load based upon the security level and whether the Trust all installed add-ins and templates box is checked.

Table 6. Security settings and default behavior

Security Level Trust all installed add-ins and templates (checked) Trust all installed add-ins and templates (unchecked)
Very High Checked by default so all Add-ins load, VBA code does not load Not available under Very High security level
High All Add-ins load, VBA code does not load Only digitally signed (Class 3 Certificate) and trusted Add-ins load, unsigned Add-ins do not load, VBA code does not load
Medium All Add-ins load, VBA code loads if user clicks Enable Macros in security warning dialog box Only digitally signed (Class 3 Certificate) and trusted Add-ins load, unsigned Add-ins load if the user selects Enable Macros for each individual Add-in (including Outlook VBA which is actually an Add-in registered under HKLM)
Low All Add-ins load, VBA code loads Digitally signed (Class 3 Certificate) and unsigned Add-ins load, VBA code loads

Integrating with SharePoint Sites

You might be wondering after the previous discussion whether Outlook 2003 offers an expanded window of development opportunities. If your organization adopts Windows SharePoint Services as a Web-based collaboration platform, the answer is a resounding yes! Windows SharePoint Services provides a new collaboration platform for Office users, and the platform is especially attractive for Office System users. From a developer's perspective, the Windows SharePoint Services platform is extensible on both the server side with custom Web Parts and on the client-side with applications that consume Web services provided by SharePoint Products and Technologies. The sample application provided with this article shows you how to consume Web services from Windows SharePoint Services in an Outlook Add-in written using Microsoft Visual Basic .NET 2003. The sample Add-in allows a user to import Contact items from a SharePoint site and to export Outlook Contact items to an existing SharePoint site. The user interface for the Outlook Add-in for SharePoint Products and Technologies is a custom command bar shown in Figure 5.

Figure 5. Add-in for importing contacts from SharePoint lists

**Note   **Due to space considerations, this article does not discuss all the details of writing a managed code Add-in for Outlook. For a complete discussion of writing a managed Add-in for Outlook, see the following articles:

Building Outlook 2002 Add-ins with Visual Basic .NET

Using the COM Add-in Shim to Trust Outlook 2002 Add-ins Built with Visual Studio .NET

The sample application provides an example of an Outlook Add-in created with Visual Basic .NET 2003. Unlike the native import and export functionality for a Contacts list, the sample application lets you import Contact items from a SharePoint list to any Contacts folder in your profile. It does not limit you to importing Contacts to the Outlook folder linked to the SharePoint list. All Contact items in a native Outlook folder linked to a SharePoint list are read-only items. These read-only folders are always contained in a Personal Folders file (.PST) rather than a subfolder of your Mailbox. The sample application improves upon the native folders linked to a SharePoint list by allowing you to import Contacts from a SharePoint list directly into a read-write Contacts folder as shown in Figure 6. This custom Contacts folder can be a subfolder of your Mailbox, so mobile Exchange users using the cached Exchange mode, always have their exported Contacts from the SharePoint list in their Mailbox. Note that unlike the default linked PST-based Contact folder, the sample application does not automatically perform one-way synchronization from the SharePoint list to Outlook. However, you can extend the sample application to support two-way synchronization.

Figure 6. Contacts exported from a SharePoint list into Outlook (Click picture to see larger image)

Before you review the sample code, you need to download, install, and then test the Microsoft Office Outlook 2003 Add-in for Microsoft SharePoint Products and Technologies. You also must ensure that you have installed the Outlook 2003 Primary Interop Assembly (PIA). Fortunately, the PIAs that enable .NET programmability are included with all editions of the Microsoft Office System CD.

**Note   **You may need to install the Outlook PIA before proceeding if you did not choose the Complete option during installation.

To install the Outlook 2003 PIA:

  1. On a computer with Microsoft Visual Studio® .NET 2003 and the Office System installed, on the Start menu, point to Control Panel, and then click Add or Remove Programs.

  2. In the list of currently installed programs, click Microsoft Office Professional Edition 2003, and then click Change.

  3. In the Microsoft Office 2003 Setup window, click Add or Remove Features, and then click Next.

  4. Check the Choose advanced customization of applications box and click Next.

  5. Expand the Microsoft Office Outlook node.

  6. Click the .NET Programmability Support drop-down and select Run from My Computer as shown in Figure 7.

  7. Click Update to install the selected option.

    Figure 7. Installing .NET Programmability Support (Click picture to see larger image)

After downloading the sample file, extract the sample to the Visual Studio Projects folder. By default, this is located in the My Documents folder. You should now have a folder named WSSAddin folder under the Visual Studio Projects folder.

The WSSAddin folder contains the Visual Basic managed Add-in project. The name of the assembly is WSSAddin. To view this project, open WSSAddin.sln located in the project folder. This folder also contains a subfolder with the name WSSAddinSetup. This contains the managed WSSAddin setup project for deploying the completed solution.

To install the solution:

**Note   **Before installing the managed WSSAddin Add-in .DLL file, close Outlook.

  1. In the project folder, double-click WSSAddin.sln to open it in Visual Studio .NET. In the Solution Explorer, note the two projects: WSSAddin and WSSAddinSetup.
  2. First, rebuild the managed Add-in by right-clicking on the WSSAddin project and then clicking Rebuild.
  3. Next, build the managed Add-in setup project by right-clicking on the WSSAddinSetup project and then clicking Build.
  4. To install the Add-in, right-click WSSAddinSetup and then click Install. This launches the Outlook Add-in for Windows SharePoint Services Setup Wizard.
  5. Click Next.
  6. In the Select Installation Folder dialog box, accept the default or supply a different installation folder, and then click Next.
  7. Click Next to install Outlook Add-in for Windows SharePoint Services.

Working with the Lists Web Service in Windows SharePoint Services

In the sample application, you work with the Lists Web service. The Lists Web service provides several methods for working with lists and list data. From an Outlook perspective, think of List objects as the equivalent of Folder objects and List items as the equivalent of Outlook Item objects such as a ContactItem. A SharePoint site can contain many Lists, including Contacts, Tasks, Events, Announcements, and so forth. In this example, we exclusively use the Contacts List. A sample Contacts List is shown in Figure 8. You can extend the sample code shown in the sample application to work with any SharePoint list and its list items. For more information about the Lists Web service, see the Microsoft SharePoint Products and Technologies Software Development Kit (SDK).

Figure 8. A default Contacts list on a SharePoint site (Click picture to see larger image)

To set a reference to the Lists Web service

  1. In Visual Studio .NET, click Project, and then click Add Web Reference.

    Figure 9. Adding a Web Reference (Click picture to see larger image)

  2. As show in Figure 9, type the URL to the Lists Web service in the URL box using the following format:

    http://Server_Name/[sites/][Site_Name/]_vti_bin/Lists.asmx

  3. Click Go.

  4. In the Web reference name box, type WSS.

  5. Click Add Reference.

Using the Lists Web Service

Once you add a reference to the Lists Web service, you can use the Lists Web Service to import and export Contact information. The Lists Web service exposes Web methods that are essential for working with SharePoint lists. The sample application uses the GetLists, GetListItems, and UpdateListItems methods. The following table describes all the methods of the Lists Web service.

Table 7. Methods of the Lists Web service

Method Description
AddAttachment Adds an attachment to the specified list item in the specified list.
AddList Creates a list in the current site based on the specified name, description, and list template ID.
DeleteAttachment Removes the attachment from the specified list item.
DeleteList Deletes the specified list.
GetAttachmentCollection Returns a list of the URLs for attachments to the specified item.
GetList Returns a schema for the specified list.
GetListAndView Returns the list and view schemas for the specified list.
GetListCollection Returns the names and GUIDs for all the lists in the site.
GetListItemChanges Returns changes made to the list since the specified date and time.
GetListItems Returns information about items in the list based on the specified query.
UpdateList Updates a list based on the specified field definitions and list properties.
UpdateListItems Updates the specified items in a list on the current site.

Importing SharePoint Contact Items

The cbbImport_Click procedure contains the code to import a Contacts list from a SharePoint site to a Contacts folder in Outlook. The first task in this procedure is to obtain the URL for the SharePoint site as follows:

strKey = "Software\Microsoft\Office\Outlook\Addins\" _
& m_ProgID
Reg = Registry.CurrentUser.CreateSubKey(strKey)
strURL = Reg.GetValue("URL", "http://")
Dim strMsg As String = _
    "Type the URL for your SharePoint Site:" & vbCrLf _
    & "http://server_name[/sites/site_name]"
strURL = InputBox(strMsg, APP_TITLE, strURL)
If strURL = "" Then
    Exit Try
Else
    Reg.SetValue("URL", strURL)
End If

Once we obtain a URL, we need to determine the Outlook folder to which to import the Contact items. The PickFolder method obtains this folder, and the code checks the DefaultItemType of the folder to ensure that the user selects a Contacts folder:

Dim oFolder As Outlook.MAPIFolder = m_olApp.Session.PickFolder
If oFolder Is Nothing Then
    Exit Try
End If
If oFolder.DefaultItemType <> _
Outlook.OlItemType.olContactItem Then
    MsgBox("You can only import to a Contacts folder!", _
        MsgBoxStyle.Exclamation, APP_TITLE)
    Exit Try
End If

The next step is to assign a valid URL to the ListsWS object on the SharePoint site and to ensure that the Web service uses the default user credentials for authentication:

'Assign the URL for Lists Web service
ListWS.Url = strURL & "/_vti_bin/lists.asmx"
'Use Windows credentials
ListWS.Credentials = _
System.Net.CredentialCache.DefaultCredentials
'Set timeout to 20 seconds
ListWS.Timeout = 20000

If the URL for ListWS object is valid and does not throw an error that is trapped in the Catch block, the code calls the GetListItems method of the Lists Web service. To ensure that all default fields of a List item are returned, you must create an XMLNode object named nodViewFields. The nodViewFields object is passed to the GetListItems method as the ViewFields argument. ViewFields is an element that specifies which fields to return in GetListItems call. Be aware that the field names in the XML for nodViewFields are case-sensitive. GetListItems returns its results in nodListItems, which is a System.Xml.XmlNode object. Once you have nodListItems, you can convert the XML into a System.Data.DataSet object, and then enumerate the rows in the DataSet object to create or modify Outlook Contact items. The code determines if the Outlook Contact already exists in the folder by performing a Restrict using the User2 field for the Outlook contact item. User2 contains the URL for editing the contact, and is guaranteed to be unique. If an existing Outlook Contact item is found with the URL contained in User2, then the code uses GetFirst to obtain the existing ContactItem. Otherwise, a new ContactItem is created in the Outlook folder represented by oFolder. The URL required to edit the Contact on the SharePoint list appears in the body of the Contact as shown in Figure 10. Although the following listing is lengthy, it shows you all the steps required to create or update Outlook Contact items from a Contacts list on a SharePoint site. Not shown below, the CheckNull function ensures that a null value is not assigned to an Outlook property.

Figure 10. An imported contact (Click picture to see larger image)

'Create new XmlDocument
Dim xmlDoc = New System.Xml.XmlDocument
'nodViewFields node contains ViewFields
nodViewFields = _
    xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "")
'ViewFields will be returned by GetListItems
'All Names are case-sensitive
nodViewFields.InnerXml = _
    "<FieldRef Name='ID'/><FieldRef Name='Title'/>" _
    & "<FieldRef Name='FirstName'/><FieldRef Name='FullName'/>" _
    & "<FieldRef Name='Email'/><FieldRef Name='Company'/>" _
    & "<FieldRef Name='JobTitle'/><FieldRef Name='WorkPhone'/>" _
    & "<FieldRef Name='HomePhone'/><FieldRef Name='CellPhone'/>" _
    & "<FieldRef Name='WorkFax'/><FieldRef Name='WorkAddress'/>" _
    & "<FieldRef Name='WorkCity'/><FieldRef Name='WorkState'/>" _
    & "<FieldRef Name='WorkZip'/><FieldRef Name='WorkCountry'/>" _
    & "<FieldRef Name='WebPage'/><FieldRef Name='Comments'/>"
'GetListItems retrieves items in Contacts List
nodListItems = _
    ListWS.GetListItems _
    ("Contacts", "", Nothing, nodViewFields, "1000", Nothing)
If nodListItems.HasChildNodes Then
    'ChildNodes(1) contains list items
    nodRows = nodListItems.ChildNodes(1)
    If CInt(nodRows.Attributes("ItemCount").Value) = 0 Then
        fWait.Close()
        MsgBox("No SharePoint Contacts available to import!", _
            MsgBoxStyle.Critical, APP_TITLE)
        Exit Try
    End If
    'Use StringReader with nodRows.OuterXML
    Dim xmlSR As System.IO.StringReader = _
        New System.IO.StringReader(nodRows.OuterXml)
    'Read xmlSR into DataSet
    myDS.ReadXml (xmlSR)
    'Tables(1) contains rows
    Dim myTable As System.Data.DataTable = myDS.Tables(1)
    'Enumerate contacts
    For intRow = 0 To myTable.Rows.Count - 1
        'ID contains the Primary Key for the item in the SharePoint list
        strID = myTable.Rows(intRow).Item("ows_ID")
        'Test to determine if a contact already exists
        Dim oContact As Outlook.ContactItem
        Dim colItems As Outlook.Items = oFolder.Items
        'User2 property contains URL to SharePoint list item
        Dim strRestrict As String = "[User2] = '" _
            & strURL & "/Lists/Contacts/EditForm.aspx?ID=" _
            & strID & "'"
        Dim colRestrict As Outlook.Items
        colRestrict = colItems.Restrict(strRestrict)
        If colRestrict.Count Then
            'Contact already exists
            oContact = colRestrict.GetFirst
        Else
            'Create a contact for the row
            oContact = _
            oFolder.Items.Add("IPM.Contact")
        End If
        With oContact
            For intCol = 0 To myTable.Columns.Count - 1
                strColumnName = myTable.Columns(intCol).ColumnName
                strValue = CheckNull(myTable.Rows(intRow).Item(intCol))
                Select Case strColumnName
                    Case "ows_ID"
                        'ID contains the Primary Key for the item in the SharePoint list
                        strID = strValue
                    Case "ows_Title"
                        .LastName = strValue
                    Case "ows_FirstName"
                        .FirstName = strValue
                    Case "ows_FullName"
                        If strValue <> "" Then
                            .FullName = strValue
                        End If
                    Case "ows_Company"
                        .CompanyName = strValue
                    Case "ows_Email"
                        .Email1Address = strValue
                    Case "ows_JobTitle"
                        .JobTitle = strValue
                    Case "ows_WorkAddress"
                        .BusinessAddressStreet = strValue
                    Case "ows_WorkCity"
                        .BusinessAddressCity = strValue
                    Case "ows_WorkState"
                        .BusinessAddressState = strValue
                    Case "ows_WorkZip"
                        .BusinessAddressPostalCode = strValue
                    Case "ows_WorkCountry"
                        .BusinessAddressCountry = strValue
                    Case "ows_WorkPhone"
                        .BusinessTelephoneNumber = strValue
                    Case "ows_HomePhone"
                        .HomeTelephoneNumber = strValue
                    Case "ows_CellPhone"
                        .MobileTelephoneNumber = strValue
                    Case "ows_WorkFax"
                        .BusinessFaxNumber = strValue
                    Case "ows_WebPage"
                        intSep = InStr(strValue, ",", CompareMethod.Text)
                        If intSep > 1 Then
                            strValue = _
                                Microsoft.VisualBasic.Left _
                                (strValue, intSep - 1)
                        Else
                            strValue = ""
                        End If
                        .WebPage = strValue
                    Case "ows_Comments"
                        'Add the URL for the Contact in the SharePoint list
                        'to Body of Contact
                        strComments = "<" & strURL & _
                            "/Lists/Contacts/EditForm.aspx?ID=" _
                            & strID & ">" & vbCrLf & strValue
                        .Body = strComments
                End Select
            Next
            'Add ID to User1 property
            .User1 = strID
            'Add URL to List Item to User2 property
            .User2 = strURL & _
                "/Lists/Contacts/EditForm.aspx?ID=" & strID
            'Finally, save the ContactItem
            .Save()
        End With
    Next
End If

Exporting Outlook Contact Items

The cbbExport_Click procedure contains the code to export Contact items from Outlook to a SharePoint list. The Export Contacts button is only enabled when a user navigates to an Outlook Contacts folder. The Export Contacts button only exports the selected Contacts in the folder view. This method is somewhat awkward, but uses this design because Outlook does not expose an AddressBook method. If you experiment with the Import Contacts button on the Contacts page of the SharePoint site, you may notice that the Outlook Security Warning dialog box shown in Figure 2 appears after you select recipients in the Select Users to Import window. The code in cbbExport does not cause the Security Warning to appear because all Outlook objects in the Add-in are trusted since they derive from the Application object passed in the OnConnection event of the WSSAddin.Connect class.

The purpose of the code in cbbExport is to create an XML fragment that uses CAML to pass as a parameter for the UpdateListItems method of ListsWS object. For more information about CAML, see the Microsoft SharePoint Products and Technologies Software Development Kit (SDK). To create CAML, the code creates an XML.XMLDocument object named xmlDoc, and then creates a root element named Batch. The code then creates child elements named Method for each selected ContactItem in the Contacts folder. Each Method element must have an ID and Cmd attribute. Each Method element represents a selected ContactItem. After you create the Method element, Field elements contain the values for Property values such as FirstName, LastName, CompanyName, and so forth for each selected ContactItem. If the ContactItem contains a value for User1, it is assumed that the Contact already exists in the SharePoint list. The Cmd attribute changes to Update instead of New if the item already exists in the SharePoint list based upon values contained in User1 and User2. Finally, an XML.XMLNode object named nodCAML is created from the InnerXML of xmlDoc. When you pass nodCAML to the UpdateListItems method, it returns a nodResult that contains extended error information about the UpdateListItems call:

'Create new XmlDocument
xmlDoc = New Xml.XmlDocument
'create Root element
xmlRoot = xmlDoc.CreateElement("Batch")
xmlRoot.SetAttribute("OnError", "Continue")
xmlRoot.SetAttribute("ListVersion", "1")
xmlDoc.AppendChild (xmlRoot)
'Iterate over collection of selected items
For intCounter = 1 To colSelectedItems.Count
    'Only process contact items
    'Contacts folder can contain DistList and Contact Items
    If InStr(colSelectedItems.Item _
            (intCounter).MessageClass, "IPM.Contact", _
            CompareMethod.Text) Then
        oContact = colSelectedItems(intCounter)
        'Create a 'New' Method element for CAML
        xmlMethod = xmlDoc.CreateElement("Method")
        xmlMethod.SetAttribute("ID", "Items" & (intCounter + 1))
        If oContact.User1 = "" Then
            xmlMethod.SetAttribute("Cmd", "New")
        Else
            xmlMethod.SetAttribute("Cmd", "Update")
        End If
        xmlRoot.AppendChild (xmlMethod)
        'User1 contains the unique ID
        'User2 contains URL for EditForm.aspx
        If oContact.User1 <> "" And _
            Left(oContact.User2, Len(strURL)) = strURL Then
            'User1 contains existing ID
            xmlField = xmlDoc.CreateElement("Field")
            xmlField.SetAttribute("Name", "ID")
            xmlField.InnerXml = CheckNothing(oContact.User1)
            xmlMethod.AppendChild (xmlField)
        End If
        'Create multiple Field elements
        'FirstName
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "FirstName")
        xmlField.InnerXml = CheckNothing(oContact.FirstName)
        xmlMethod.AppendChild (xmlField)
        'Title
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "Title")
        xmlField.InnerXml = CheckNothing(oContact.LastName)
        xmlMethod.AppendChild (xmlField)
        'FullName
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "FullName")
        xmlField.InnerXml = CheckNothing(oContact.FullName)
        xmlMethod.AppendChild (xmlField)
        'Email
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "Email")
        xmlField.InnerXml = CheckNothing(oContact.Email1Address)
        xmlMethod.AppendChild (xmlField)
        'Company
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "Company")
        xmlField.InnerXml = CheckNothing(oContact.CompanyName)
        xmlMethod.AppendChild (xmlField)
        'JobTitle
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "JobTitle")
        xmlField.InnerXml = CheckNothing(oContact.JobTitle)
        xmlMethod.AppendChild (xmlField)
        'WorkAddress
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "WorkAddress")
        xmlField.InnerXml = CheckNothing(oContact.BusinessAddressStreet)
        xmlMethod.AppendChild (xmlField)
        'WorkCity
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "WorkCity")
        xmlField.InnerXml = CheckNothing(oContact.BusinessAddressCity)
        xmlMethod.AppendChild (xmlField)
        'WorkState
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "WorkState")
        xmlField.InnerXml = CheckNothing(oContact.BusinessAddressState)
        xmlMethod.AppendChild (xmlField)
        'WorkZip
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "WorkZip")
        xmlField.InnerXml = _
CheckNothing(oContact.BusinessAddressPostalCode)
        xmlMethod.AppendChild (xmlField)
        'WorkCountry
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "WorkCountry")
        xmlField.InnerXml = CheckNothing(oContact.BusinessAddressCountry)
        xmlMethod.AppendChild (xmlField)
        'WorkPhone
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "WorkPhone")
        xmlField.InnerXml = CheckNothing(oContact.BusinessTelephoneNumber)
        xmlMethod.AppendChild (xmlField)
        'HomePhone
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "HomePhone")
        xmlField.InnerXml = CheckNothing(oContact.HomeTelephoneNumber)
        xmlMethod.AppendChild (xmlField)
        'CellPhone
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "CellPhone")
        xmlField.InnerXml = CheckNothing(oContact.MobileTelephoneNumber)
        xmlMethod.AppendChild (xmlField)
        'WorkFAX
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "WorkFax")
        xmlField.InnerXml = CheckNothing(oContact.BusinessFaxNumber)
        xmlMethod.AppendChild (xmlField)
        'WebPage
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "WebPage")
        xmlField.InnerXml = CheckNothing(oContact.WebPage)
        xmlMethod.AppendChild (xmlField)
        'Comments
        xmlField = xmlDoc.CreateElement("Field")
        xmlField.SetAttribute("Name", "Comments")
        xmlField.InnerXml = CheckNothing(oContact.Body)
        xmlMethod.AppendChild (xmlField)
    End If
Next
strXML = xmlDoc.InnerXml
'Create XMLNode for CAML Fragment
xmlCAML = New Xml.XmlDocument
nodCAML = xmlCAML.CreateNode(XmlNodeType.DocumentFragment, "", "CAML", "")
nodCAML.InnerXml = strXML
'nodResult returns extended error information
nodResult = ListWS.UpdateListItems("Contacts", nodCAML)

**Note   **The listing above uses two functions to ensure that the CAML is well formed XML and does not cause an error when the UpdateListItems method is called. CheckNothing and CreateValidXML are shown below:

Private Function CheckNothing(ByVal oValue) As String
    On Error Resume Next
    If oValue Is Nothing Then
        CheckNothing = ""
    Else
        'Use the CreateValidXML function to escape
        'invalid XML characters &, ', >, <, ""
        CheckNothing = CreateValidXML(oValue)
    End If
End Function

Private Function CreateValidXML(ByVal strXML As String) As String
    On Error Resume Next
    strXML = Regex.Replace(strXML, "&", "&amp;")
    strXML = Regex.Replace(strXML, "'", "&apos;")
    strXML = Regex.Replace(strXML, "<", "&lt;")
    strXML = Regex.Replace(strXML, ">", "&gt;")
    strXML = Regex.Replace(strXML, Chr(34), "&quot;")
    CreateValidXML = strXML
End Function

Conclusion

Changes to the Outlook object model are limited in scope. However, a new and improved security model allows Add-in developers to write code without the restrictions imposed by the Outlook E-mail Security Update. Code security is still enforced for code that operates outside the installed Add-ins, VBA, and code behind published forms. Exchange administrators can continue to impose a more granular security model on the Outlook object model. Windows SharePoint Services provides a new collaboration platform that works best for Office System users. Using the Microsoft SharePoint Products and Technologies SDK, you can extend Outlook to integrate with SharePoint sites. The sample application discussed in this article is one example of what you can accomplish when you integrate Outlook with SharePoint Products and Technologies.

About the Author

Randy Byrne is the President of Micro Eye, Inc., a Microsoft Certified Partner located in the San Francisco Bay Area. Randy is an Outlook MVP and the author of Building Applications with Microsoft Outlook 2000 and Building Applications with Microsoft Outlook Version 2002 published by Microsoft Press.

© Microsoft Corporation. All rights reserved.