Microsoft Corporation
March 1997
To use Data Access Objects (DAO) methods and objects with Microsoft® Visual Basic® for Applications in Microsoft Access in order to link or import data from Microsoft Exchange or the Microsoft Outlook™ desktop information manager, you must have the Jet Exchange installable ISAM (Msexch35.dll) installed. The Jet Exchange installable ISAM is a driver that allows you to access data that is stored remotely on a Microsoft Exchange Server or that is stored locally in offline folder (.ost), personal folder (.pst), or personal address book (.pab) files.
Note If you have set up Outlook to use an offline folder file, the offline folder file is a file stored on your hard disk that "mirrors" the folder structure and data stored on your Microsoft Exchange Server. Data from your Exchange Server is copied into the offline folder file whenever you synchronize folders (manually or at a scheduled time). When you start Outlook it gives you the option to connect to your server or work offline. If you choose to connect, you are viewing data directly from the server; if you choose to work offline, you are viewing data from the offline folder.
For this reason, how you are logged on to Outlook determines whether the Jet Exchange installable ISAM (indexed sequential access method) reads data from the offline folder file or from the Exchange Server. For example, if you initially define a link to your Inbox folder while you are working offline in Outlook, the Jet Exchange installable ISAM reads the data from your offline folder file. However, if you open the same database later while Outlook is connected to your Exchange Server, the data will be read from the Inbox folder on the server.
Using the Jet Exchange installable ISAM to access Exchange and Outlook data is primarily useful for reading information from message folders, public folders, address books, and other Outlook items. You can't modify any existing items. And, while it is possible to write new items to Exchange and Outlook message stores, not all fields are available or updatable, which limits your ability to create some items. For more information on these issues, see the "Constraints" section later in this article. If you need more flexibility when working with Outlook objects from Access, you should use Automation interfaces to work with Outlook instead. For more information, see the Outlook section of the Microsoft Office Developer Forum Web site (http://www.microsoft.com/outlookdev/).
Before you can use DAO to gain access to Exchange Client or Outlook data, you must install the Jet Exchange installable ISAM. While you can install the Microsoft Jet Exchange installable ISAM using the Dataacc.exe file that is included in the Office 97 Value Pack, that version of the driver does not register itself, and has certain limitations. To install the most current version of the driver, download and run Wzmapi80.exe from the article entitled "Spotlight on Interoperability: Importing and Linking Microsoft Exchange and Microsoft Outlook Data to Microsoft Access" on the Microsoft Office Developer Forum Web site at (http://www.microsoft.com/AccessDev/Articles/ExchWiz.htm). This will install and register the most current version of Msexch35.dll so that you can use it from DAO, and also installs the Microsoft Exchange and Outlook Wizard so that you can import and link Exchange and Outlook data using the Access user interface.
Note You must have a copy of Microsoft Access 97 installed before you can install the Microsoft Exchange and Outlook Wizard. The Setup program does not provide a way to install only the Microsoft Jet Exchange driver; you must install the wizard components as well.
The procedures for importing and linking Exchange and Outlook data with DAO are similar to the procedures used for importing and linking the other external data sources, such as Microsoft FoxPro® and Microsoft Excel data. Special considerations and examples are provided in the following sections.
When specifying the connection string for Exchange and Outlook data, use the parameters, separated by semicolons, as specified in Table 1.
Table 1. Connection Parameters
To specify this element | Use this parameter |
Source database type | Exchange 4.0 (required) Note This setting also works with Microsoft Exchange version 4.x and 5.0 data. |
Table name | MAPILEVEL=storage|folders where storage is the exact name of a mailbox on a server, a personal folder, or public folder, and folders is the name of one or more nested folders within storage. When listing nested folders, each folder name is separated by the backslash ( \ ) character. (required) |
Source table type | TABLETYPE=0 (for folders) TABLETYPE=1 (for address books; required) |
Database name | DATABASE=path where path is the path to a Microsoft Access database (*.mdb) in which to store system tables used by the driver (usually the current database; required) |
Profile name | PROFILE=profile where profile is the name of the profile to use. (optional; if not specified, the default profile is used) |
Password | PWD=password where password is the logon password. (optional; not required if your network logon password is passed to your Microsoft Exchange Server) |
To gain access to messages in an Exchange Client or Outlook folder, you must specify the path to the folder just above the folder you want use. You do this with the connection string keyword, MAPILEVEL=. For example, to gain access to a folder named "Barbara" in the "Important" subfolder in the "People" folder in the mailbox "Mailbox - Dave Jones", first specify the path to the "Important" folder, using the following connection string:
"Exchange 4.0;MAPILEVEL=Mailbox - Dave Jones|People\Important;"
Then use the SourceTableName property in your DAO code to specify the folder named "Barbara":
tdf.SourceTableName = "Barbara"
You can specify any valid mailbox name to the left of the pipe symbol ( | ) in the connection string, but the mailbox name must be specified exactly as it appears in the left pane of the Exchange Client or Outlook application window. Any spaces and capitalization in the name must be preserved.
In addition to specifying an Exchange Server mailbox name to the left of the pipe symbol ( | ) in the connection string, you can specify the name of a local personal folder file (if you are using one) exactly as it appears in the left pane of the Exchange Client or Outlook application window. Note that this name is not necessarily the same name as the .pst file itself and does not include the file extension. To determine how a personal folder name is mapped to the .pst file name where its information is stored, click Services on the Tools menu in the Microsoft Client or Outlook to display the Services dialog box. On the Services tab, click the name of a personal folder, and then click Properties. In the Personal Folders dialog box, the information in the Name dialog box is the name to specify in your connection string. The information in the Path dialog box specifies the path to the .pst file where mail data is stored.
For example, to gain access to a folder named "ToDo" in the Inbox folder in the personal folder named "Local Folders", use the following connection string:
"Exchange 4.0;MAPILEVEL=Local Folders|Inbox;"
And then use the SourceTableName property in your DAO code to specify the folder named "ToDo":
tdf.SourceTableName = "ToDo"
If you have defined multiple profiles for your Exchange or Outlook installation, or have defined a password that is required to use your profile, you can supply the profile name and password with the keywords PROFILE= and PWD= in the connection string. For example:
"Exchange 4.0;MAPILEVEL=Mailbox - Dave Jones|People\Important;PROFILE=DaveJ;PWD=Cisco;"
To determine the names of profiles on a computer, open the Control Panel and double-click Mail And Fax, and then click Show Profiles. If you don't specify a profile name in your connection string, the default profile (displayed in the When starting Microsoft Windows Messaging, use this dialog box) is used.
If you don't specify a password in your code, and your network doesn't use your network logon password for this purpose, you will be prompted to enter your password when connecting to your Exchange data.
When specifying the connection string to open a folder in an Exchange Client or Outlook mailbox, you must supply a hard-coded path and name of an existing Microsoft Access database using the DATABASE=parameter:
"DATABASE="C:\My Documents\Outlook Data.mdb;"
Or use the Name property to refer to the current database in code:
"DATABASE=" & dbs.Name & ";"
The Microsoft Messaging driver creates system tables in this database to store information about the structure of the Exchange Client or Outlook folders, including any new fields you have appended to these folders. Although it is possible to specify a database other than the current database, it is preferable to specify the current database for this purpose. If you specify a separate database and that database is deleted, or if the system tables named ExchangeTablennn in any database you specify are deleted, all the information about the structure of the folders is lost and must be recreated.
You can open an Exchange or Outlook folder directly by using the OpenDatabase method and specifying the appropriate connection string. You must also specify an existing Access database that will contain the system tables required to maintain the connection when doing so. The OpenDatabase method is useful if you want to simply read information and don't require a persistent connection saved in a database. If you need to create a persistent connection to a folder, you should link it as described in the "Linking Microsoft Exchange or Outlook Folders" section later in this article. The following code example opens a personal folder storage, opens each top-level folder and prints information about the contents of the folder in the Debug Window (Microsoft Access) or Immediate Pane (Visual Basic and Visual Basic for Applications in Microsoft Word, Excel, and Microsoft PowerPoint®).
Sub OpenExchange()
Dim wks As Workspace
Dim dbs As Database
Dim rst As Recordset
Dim strConnect As String
Dim i As Integer
Set wks = CreateWorkspace("wks", "admin", "", dbUseJet)
strConnect = "Exchange 4.0;MAPILEVEL=Personal Folders|;"
Set dbs = wks.OpenDatabase("c:\My Documents\Exchange.mdb", 0, 0, strConnect)
On Error GoTo Open_Err
'Open Each top-level folder and print the first three records.
For Each tbl In dbs.TableDefs
Set rst = dbs.OpenRecordset(tbl.Name, dbOpenDynaset, 0, dbOptimistic)
i = 1
Debug.Print "Records in Folder: " & tbl.Name
Debug.Print "----------------------------------"
While Not rst.EOF And (i < 4)
Debug.Print i, rst!Subject
i = i + 1
rst.MoveNext
Wend
rst.Close
Open_Err:
If (Err) Then
Debug.Print "*****" & tbl.Name, Err, Err.Description
Err.Clear
End If
Next tbl
Debug.Print "Done"
dbs.Close
wks.Close
End Sub
Note This code example explicitly creates a new workspace using the OpenWorkspace method. This isn't required if you are using this code within Access, which automatically creates a default workspace when it is running. This is required if you want to use this code in the Visual Basic programming system, or using Visual Basic for Applications in Word, Excel, or the PowerPoint. Additionally, to use the Jet Exchange installable ISAM from those programs, you must use the References dialog box (in the Tools menu in the Microsoft Office Visual Basic Editor, and in the Project menu in Visual Basic) to establish a reference to Microsoft DAO 3.5 Object Library. A reference to this object library is established by default in Access 97. The code examples in the following sections assume that you are using them in Access and do not create a new workspace.
You can gain access to a folder within an Exchange Client or Outlook mailbox by creating a link to the folder within an Access database. When you link a folder, the folder is treated as a linked table. There are a number of constraints when working with linked folders. For more information see "Constraints" and "Microsoft Exchange and Outlook Table Formats" later in this article. The following DAO code links an Exchange or Outlook folder to an Access database.
Sub LinkExchangeFolder()
Dim dbs As Database
Dim tdf As TableDef
Dim str As String
Const conTableExists = 3012
On Error GoTo Link_Err
'Set a reference to the current database.
Set dbs = CurrentDb
'Build the connection string.
str = "Exchange 4.0;MAPILEVEL=Mailbox - Dave Jones" _
& "|People\Important;TABLETYPE=0;" _
& "DATABASE=" & dbs.Name & ";" _
& "PROFILE=DaveJ;PWD=Cisco;"
'Create a TableDef object. The name specified for the
'TableDef object is displayed as the name of the link
'in the Database window.
Set tdf = dbs.CreateTableDef("Linked Exchange Folder")
'Set connection information and specify a personal address book.
tdf.Connect = str
tdf.SourceTableName = "Barbara"
'Append the TableDef object to create the link.
dbs.TableDefs.Append tdf
'Refresh the database window and clear the database object variable.
RefreshDatabaseWindow
Link_Exit:
dbs.Close
Set dbs = Nothing
Exit Sub
Link_Err:
If Err = conTableExists Then
MsgBox "The table you are trying to create already exists. "
Resume Link_Exit
Else
MsgBox "Error: " & Err.Number & ": " & Err.Description
End If
End Sub
You can link an address book using the same code by specifying TABLETYPE=1 in the connection string, and then specifying the name of the address book with the SourceTableName property:
tdf.SourceTableName = "Personal Address Book"
If you want to add records to a linked folder or address book, you use the same methods used with native Access tables. For example, the following code opens the current database and adds a new record to a previously linked address book named tblMyAddressBook:
Function AddRecord()
Dim dbs As Database
Dim rst As Recordset
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("tblMyAddressBook", dbOpenDynaset)
With rst
AddNew
![First] = "Nancy"
![Last] = "Davolio"
![Phone] = "555-5555"
![Home Phone] = "555-1212"
.Update
End With
dbs.Close
rst.Close
End Function
To import Exchange or Outlook folders, your code first needs to create a new table that contains the fields you want to import. For information on the fields available to you, see "Microsoft Exchange and Outlook Table Formats" later in this article. Once you've created the new table, establish a temporary link to the folder you want to import from, and then run an append query to add records to the new table.
Sub ImportExchangeData()
Dim dbs As Database
Dim tdfImport As TableDef
Dim tdfTemp As TableDef
Dim fldImportance As Field
Dim fldPriority As Field
Dim fldSubject As Field
Dim fldFrom As Field
Dim fldTo As Field
Dim fldCC As Field
Dim fldSize As Field
Dim fldBody As Field
Dim fldReceived As Field
Dim strConnect As String
Const conTableExists = 3012
On Error GoTo Import_Err
'Set a reference to the current database.
Set dbs = CurrentDb
'Create a TableDef object to contain the definition the new table.
Set tdfImport = dbs.CreateTableDef("tblImportMessages")
With tdfImport
'Create the fields you want to include in the new table.
Set fldImportance = .CreateField("Importance", dbLong, 4)
Set fldPriority =.CreateField("Priority", dbLong, 4)
Set fldSubject =.CreateField("Subject", dbText)
Set fldFrom =.CreateField("From", dbText)
Set fldTo =.CreateField("To", dbText)
Set fldCC =.CreateField("CC", dbText)
Set fldSize =.CreateField("Message Size", dbLong, 4)
Set fldBody =.CreateField("Body", dbMemo)
Set fldReceived =.CreateField("Received", dbDate)
End With
'Add the fields you want to include in the new table by appending
'them to the Fields collection.
With tdfImport.Fields
.Append fldImportance
.Append fldPriority
.Append fldSubject
.Append fldFrom
.Append fldTo
.Append fldCC
.Append fldSize
.Append fldBody
.Append fldReceived
End With
'Create the new table by appending it to the database's TableDefs collection.
dbs.TableDefs.Append tdfImport
'Build the connection string.
strConnect = "Exchange 4.0;MAPILEVEL=Personal Folders" _
& "|Inbox;TABLETYPE=0;" _
& "DATABASE=dbs.Name;" _
& "PROFILE=DaveJ;PWD=Cisco;"
'Create a TableDef object that will be used to temporarily link
'the folder.
Set tdfTemp = dbs.CreateTableDef("tblTemp")
'Set Connection Information.
tdfTemp.Connect = strConnect
tdfTemp.SourceTableName = "Barbara"
'Append the TableDef object to create the link.
dbs.TableDefs.Append tdfTemp
'Create the SQL statements that define the append query.
strSQL = "INSERT INTO tblImportMessages"
strSQL = strSQL & "( Importance, Priority, Subject, "
strSQL = strSQL & "[From], To, CC, [Message Size], Body, Received ) "
strSQL = strSQL & "SELECT tblTemp.Importance, tblTemp.Priority, "
strSQL = strSQL & "tblTemp.[Normalized Subject], tblTemp.From, tblTemp.To, "
strSQL = strSQL & "tblTemp.CC, tblTemp.[Message Size], tblTemp.Body, "
strSQL = strSQL & "tblTemp.Received "
strSQL = strSQL & "FROM tblTemp;"
'Execute the append query.
dbs.Execute strSQL
'Delete the link and refresh the database window.
dbs.TableDefs.Delete "tblTemp"
RefreshDatabaseWindow
'Clear the database object variable and exit sub.
Import_Exit:
dbs.Close
Set dbs = Nothing
Exit Sub
Import_Err:
If Err = conTableExists Then
MsgBox "The table you are trying to create already exists. "
Resume Import_Exit
Else
MsgBox "Error: " & Err.Number & ": " & Err.Description
End If
End Sub
If you want to import all of the fields of an Exchange or Outlook table at once, you can use code to run a query like the following:
Function SimpleImport()
Dim dbs As Database
Dim strConnect As String
Dim strSQL As String
Set dbs = CurrentDB
'Build the connection string.
strConnect = "Exchange 4.0;MAPILEVEL=Mailbox - KiraR|Inbox;DATABASE=" _
& dbs.Name & ";"
'Build the SQL statement.
strSQL = "SELECT * INTO ImportTable FROM [" & strConnect & "].MyMessages;"
'Run the query.
dbs.Execute strSQL
'Refresh the database window and clear database object variable.
RefreshDatabaseWindow
dbs.Close
dbs = Nothing
End Function
You can't select which fields are available to you in opened and linked folders; a subset of the total number of Exchange Client or Outlook fields are available, and they are preprogrammed in the Jet Exchange installable ISAM. For information on which fields are available, see "Microsoft Exchange and Outlook Table Formats" later in this article. For linked tables, however, you can rearrange or hide the fields in the Datasheet View of the table to customize its appearance.
You can't modify any records in a linked folder or address book. You can delete records and add new records to a linked folder or address book. However, when adding new records, only certain fields will accept data. For information on which fields will accept data when adding new records, see the tables in the "Microsoft Exchange and Outlook Table Formats" section later in this article. Additionally, you can't use the Seek method, because the Jet Exchange installable ISAM does not support indexing.
If items in the linked Outlook folder use a special form, you must enter the correct form type in the Message Class field when you add new records to the table. If you do not specify a Message Class, Outlook uses the default mail form to display your data. The Message Classes for the standard Outlook folders are listed in Table 2.
Table 2. Message Classes
Folder | Message Class |
Calendar | IPM.Appointment |
Contacts | IPM.Contact |
Inbox | IPM.Note |
Journal | IPM.Activity |
Notes | IPM.StickyNote |
Tasks | IPM.Task |
The Jet Exchange driver makes available the table formats listed in the follow sections. You can't modify any records in a linked folder. When adding new records, you can only enter data in the fields marked as Updatable in the tables that follow. Once you save a new record, it can't be modified.
The Message Table format, specified as TABLETYPE=0 in the Connect property in code, applies to Exchange and Outlook Message and Public folders, and to Outlook Calendar (Appointment), Contacts, Journal, Notes, and Tasks folders. Contacts folders include additional fields in a slightly different order, as listed Table 3.
Note When opening Public Folders, any custom fields that are defined for the folder are not available.
Table 3 lists the fields in the order they are displayed in a linked message folder.
Table3. Message Table Format
Field Name | Type | Size | Updatable |
Importance | Number (Long) | 4 | Yes |
Message Class | Text | 255 | Yes |
Priority | Number (Long) | 4 | Yes |
Subject | Text | 255 | No |
From | Text | 255 | Yes |
Message To Me | Yes/No | 1 | Yes |
Message CC to Me | Yes/No | 1 | Yes |
Sender Name | Text | 255 | Yes |
CC | Text | 255 | No |
To | Text | 255 | No |
Received | Date/Time | 8 | No |
Message Size | Number (Long) | 4 | No |
Body | Memo | - | Yes |
Display Name | Text | 255 | No |
Creation Time | Date/Time | 8 | No |
Last Modification Time | Date/Time | 8 | No |
Subject Prefix | Text | 255 | No |
Has Attachments | Yes/No | 1 | No |
Normalized Subject | Text | 255 | Yes |
Row Type | Number (Long) | 4 | Yes |
Instance Key | OLE Object | - | No |
Object Type | Number (Long) | 4 | No |
EntryId | OLE Object | - | No |
Depth | Number (Long) | 4 | Yes |
Content Unread | Number (Long) | 4 | Yes |
A Contacts table is specified as TABLETYPE=0 in the Connect property in code, but contains a slightly different list of fields than other Message Table Format tables.
Table 4. Contacts Table Format
Field Name | Type | Size | Updatable |
Has Attachments | Yes/No | 1 | No |
Received | Date/Time | 8 | No |
Message Class | Text | 255 | Yes |
Subject Prefix | Text | 255 | No |
Normalized Subject | Text | 255 | Yes |
Importance | Number (Long) | 4 | Yes |
Message To Me | Yes/No | 1 | Yes |
Message CC to Me | Yes/No | 1 | Yes |
Creation Time | Date/Time | 8 | No |
Last Modification Time | Date/Time | 8 | No |
Body | Memo | - | Yes |
To | Text | 255 | No |
CC | Text | 255 | No |
Sender Name | Text | 255 | Yes |
Priority | Number (Long) | 4 | Yes |
Last | Text | 255 | Yes |
First | Text | 255 | Yes |
Company | Text | 255 | Yes |
From | Text | 255 | Yes |
Message Size | Number (Long) | 4 | No |
Display Name | Text | 255 | No |
Mobile Phone | Text | 255 | Yes |
Home Phone | Text | 255 | Yes |
Phone | Text | 255 | Yes |
Alias | Text | 255 | Yes |
Initials | Text | 255 | Yes |
Title | Text | 255 | Yes |
Department | Text | 255 | Yes |
Country | Text | 255 | Yes |
City | Text | 255 | Yes |
State | Text | 255 | Yes |
Address | Text | 255 | Yes |
Zip code | Text | 255 | Yes |
Subject | Text | 255 | No |
Object Type | Number (Long) | 4 | No |
EntryId | OLE Object | - | No |
Instance Key | OLE Object | - | No |
The Address Book format, specified as TABLETYPE=1 in the Connect property in code, applies to Exchange and Outlook Address Book folders. You can't modify any records in a linked address book. When adding new records, you can only enter data in the fields marked as Updatable in the tables that follow. Once you save a new record, it can't be modified. Table 5 lists the fields in the order in which they appear in a linked address book.
Table 5. Address Book Format
Field Name | Type | Size | Updatable |
Object Type | Number (Long) | 4 | No |
Display Name | Text | 255 | No |
E-mail Type | Text | 255 | Yes |
E-mail Address | Text | 255 | Yes |
Notes | Memo | - | Yes |
Creation Time | Date/Time | 8 | No |
Last Modification Time | Date/Time | 8 | No |
Display Type | Number (Long) | 4 | No |
Alias | Text | 255 | Yes |
First | Text | 255 | Yes |
Phone | Text | 255 | Yes |
Home Phone | Text | 255 | Yes |
Initials | Text | 255 | Yes |
Common Name | Text | 255 | Yes |
Last | Text | 255 | Yes |
Company | Text | 255 | Yes |
Title | Text | 255 | Yes |
Department | Text | 255 | Yes |
Office | Text | 255 | Yes |
Primary | Text | 255 | Yes |
Business2 Phone | Text | 255 | Yes |
Mobile Phone | Text | 255 | Yes |
Transmit Name | Text | 255 | Yes |
Pager Phone | Text | 255 | Yes |
Fax Number | Text | 255 | Yes |
Country | Text | 255 | Yes |
City | Text | 255 | Yes |
State | Text | 255 | Yes |
Address | Text | 255 | Yes |
Zip code | Text | 255 | Yes |
Post Office Box | Text | 255 | Yes |
Telex Number | Text | 255 | Yes |
Assistant Phone Number | Text | 255 | Yes |
Home2 Phone | Text | 255 | Yes |
Assistant | Text | 255 | Yes |
Send Rich Text | Yes/No | 1 | Yes |
EntryId | OLE Object | - | No |
Instance Key | OLE Object | - | No |
Important The structure of the tables previously listed may not correspond exactly to the tables available on your Exchange Server offline folder (.ost), personal folder (.pst), or personal address book (.pab) files. The Jet Exchange installable ISAM does not determine the structure of linked tables, and they may vary depending on the version of Exchange or Outlook that you are using. To check the structure of your tables, link a table and then run code like the following:
Function ListFormat()
Dim dbs As Database
Dim tdf As TableDef
Dim fld As Field
Set dbs = CurrentDb
Set tdf = dbs.TableDefs!tblMyTable
For Each fld In tdf.Fields
Debug.Print "Name: " & fld.Name & vbTab &_
" Type: " & fld.Type & vbTab &_
" Updatable: " & fld.DataUpdatable
Next fld
End Function