CDOLive LLC The Premier Resource for Microsoft Collaboration Data Objects             

Tips and Tricks

This tips and tricks section provides some basic and also special tasks for CDO 1.x and ASP. Note that the following examples should serve only as an idea to create your own solution and are not checked for proper function. You can find a lot of checked and proper running samples at the CDOLive Code Sample Library.

Common Tasks
Task Description
Check if a valid Microsoft Windows NT session is established Before you can log on with CDO 1.x to a Microsoft Exchange server  5.x mailbox you need to establish a valid Microsoft Windows NT 4.x session. To check if a user is authenticated run the following code in a server-side ASP script file:

If Request.ServerVariables("LOGON_USER") = "" Then
    Response.Status = "401 Access Denied"
End If

If the LOGON_USER is blank, you are authenticated as IUSR_<machine> and you can't open a mailbox without authenticate properly. Otherwise, the LOGON_USER displays the <domain\user> name of the authenticated user.
Log on anonymous To log on anonymously it is necessary to know the Microsoft Exchange Organization (AKA Enterprise), Site and Server name. The CDO Rendering library 1.x application object provides an undocumented method to pull that information out of the Microsoft Windows NT 4.x Registry of the server which has Microsoft Outlook Web Access 5.x installed. The following code snippet shows how it is done:

' Create renderer application
On Error Resume Next
Set objRenderApp = Server.CreateObject("AMHTML.Application")

' Pull configuration out of the registry
Err.Clear
On Error Resume Next
objRenderApp.LoadConfiguration 1,_
"HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\_
MSExchangeWeb\Parameters"
strEnterprise = objRenderApp.ConfigParameter("Enterprise")
strSite = objRenderApp.ConfigParameter("Site")
strServer = objRenderApp.ConfigParameter("Server")

' Construct CDO profile
strProfileInfo = "/o=" + strEnterprise + "/ou=" + strSite +_
"/cn=Configuration/cn=Servers/cn=" + strServer + vbLF + "anon" + vbLF + "anon"

' Create CDO session
Err.Clear
On Error Resume Next
Set objSession = Server.CreateObject("MAPI.Session")

' Logon with anonymous CDO profile
Err.Clear
On Error Resume Next
objSession.Logon "", "", False, True, 0, True, strProfileInfo

Log on authenticated To log on authenticated it is necessary to provide only a Microsoft Exchange Servername and a valid mailbox. The CDO Rendering library 1.x application object provides an undocumented method to pull the Microsoft Exchange Servername out, but not a valid mailbox. The following code snippet shows how it is done:

' Set render application
On Error Resume Next
Set objRenderApp = Server.CreateObject("AMHTML.Application")

' Pull configuration out of the registry
Err.Clear
On Error Resume Next
objRenderApp.LoadConfiguration 1,_
"HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\_
MSExchangeWeb\Parameters"
strServer = objRenderApp.ConfigParameter("Server")

' If the Exchange mailbox alias and the Windows NT UserID are the same,
' use the following code to retrieve the DOMAIN\UserID from the IIS
' server variables and then manipulate the string to return just the Windows
' NT UserID:

strLogonID = Request.ServerVariables("Logon_User")
strMailbox = Right(strLogonID, Len(strLogonID) - InStr(strLogonID, "\"))

' Construct CDO profile
strProfileInfo = strServer + vbLF + strMailbox

' Create CDO session
Err.Clear
On Error Resume Next
Set objSession = Server.CreateObject("MAPI.Session")

' Logon with authenticated CDO profile
Err.Clear
On Error Resume Next
objSession.Logon "", "", False, True, 0, True, strProfileInfo
Open the public information store After a session is successfully established the information stores must be opened once to make sure everything is OK. Otherwise it is possible that the session logon did not return an error but the current session does not have permissions to open the particular information store. The following code snippet shows how it is done for public folders:

' MAPI properties to access the public information store
Const CdoPR_STORE_SUPPORT_MASK = &H340D0003
Const CdoPR_STORE_PUBLIC_FOLDERS = &H00004000

' We need to force the store to open before anonymous access will work
Set objInfoStores = objSession.InfoStores
For intCounter = 1 To objInfoStores.Count
  Set objInfoStore = objInfoStores.Item(intCounter)
  lMask = objInfoStore.Fields.Item(CdoPR_STORE_SUPPORT_MASK)
  If lMask And CdoPR_STORE_PUBLIC_FOLDERS Then
    Exit For
  End If
Next
Special Tasks
Task Description
Increase logging level for debugging The CDO rendering library 1.x application object supports a LoggingLevel property which controls how much information is written to the event log.

' Get the current logging level for startup category
strLevel = objRenderApp.LoggingLevel(1)

The following categories are defined:

Category Description
CATEGORY_STARTUP >or "1" Events that occur during the creation of the rendering object
CATEGORY_GENERAL or "2" Events that occur while the rendering object is generating HTML output
CATEGORY_CONTENT or "3" Unused
CATEGORY_SECURITY or "4" Unused
CATEGORY_INTERNAL or "5" Unused
CATEGORY_SHUTDOWN or "6" Unused

The logging level construct is an array with five elements, one for each logging category. Each element in the array can have a value from 0 to 5, representing the logging verbosity for that category.

' Set logging level for startup category to verbose
objRenderApp.LoggingLevel(1) = 4

The following logging levels are defined for each category:

Level Description
0 Critical – log only the most severe failure events (default).
1 Minimal – include nearly all error events.
2 Basic – include certain important success events.
3 Extensive – include most routine success events.
4 Verbose – include all events not related to internal workings.
5 Internal – include events of interest only to users familiar with the internal workings of the CDO Rendering Library.

The default is level 0. It is the least verbose and logs only the most severe errors for that logging category. Level 5 is the most verbose and logs all events at all levels of severity.
Render the rich text body of a message The CDO rendering library 1.x contains an automatic RTF to HTML conversion engine. With this feature it is possible to build rich web pages with a single e-mail message. You can also use an HTML message body (with Microsoft Outlook 98/2000) to maintain a complete HTML page in a single message object. Use the following code snippet to render the message subject and body:

' MAPI properties for message subject and RTF text body
Const CdoPR_SUBJECT = &H0037001F
Const CdoPR_RTF_COMPRESSED = &H10090102

' Create object  renderer and set DataSource to message object
Set objRenderer = objRenderApp.CreateRenderer(2)
objRenderer.DataSource = objMessage

' Render the subject and message body into HTML code
objRenderer.RenderProperty CdoPR_SUBJECT, 0, Response
objRenderer.RenderProperty CdoPR_RTF_COMPRESSED, 0, Response
Render the plain text body of a message Sometimes you want to include a short description, stored in the message body, in the table view of a container render. This is possible by including the plain text body in the CDO Rendering library 1.x container renderer columns collection:

' MAPI properties for message subject and plain text body
Const CdoPR_SUBJECT = &H0037001F
Const CdoPR_BODY = &H1000001F

' Create container renderer and set datasource to message collection
Set objRenderer = objRenderApp.CreateRenderer(3)
objRenderer.DataSource = objMessages

' Create format and add patterns
Set objFormat = objRenderer.Formats.Add(CdoPR_SUBJECT)
Set objPatterns = objFormat.Patterns
objPatterns.Add "*",_
"<font face='Arial, Helvetica, sans-serif' size='-1'>%value%</font>"
Set objFormat = objRenderer.Formats.Add(CdoPR_BODY)
objPatterns.Add "*",_
"<font face='Arial, Helvetica, sans-serif' size='-1'>%value%</font>"

' Create view and set columns
Set objView = objRenderer.Views.Add("DefaultView")
Set objColumns = objView.Columns

' Add columns to view
objColumns.Add "Subject", CdoPR_SUBJECT, 30, 0, 0
objColumns.Add "Description", CdoPR_BODY, 40, 32, 1
objRenderer.CurrentView = "DefaultView"
Hide the heading row of a container renderer To build a powerful content management with public folders, it might be a good idea to remove the default heading row of the container render. If you include the following code nobody would imagine that you manage your whole Intra/Internet content within Microsoft Exchange server public folders:

' MAPI properties for message class, delivery time and subject
Const CdoPR_MESSAGE_CLASS = &H001A001F
Const CdoPR_MESSAGE_DELIVERY_TIME = &H0E060040
Const CdoPR_SUBJECT = &H0037001F

' Create view and set columns
Set objView = objRenderer.Views.Add("DefaultView")
Set objColumns = objView.Columns

' Add columns to view
' Note: do not remove the blank character otherwise the heading row
' will end up in an undefined state
objColumns.Add " ", CdoPR_MESSAGE_CLASS, 1, 8, 1
objColumns.Add " ", CdoPR_MESSAGE_DELIVERY_TIME, 18, 0, 2
objColumns.Add " ", CdoPR_SUBJECT, 50, 32, 3
objRenderer.CurrentView = "DefaultView"

' Hide heading row
' Note: do not remove this lines otherwise the heading row
' will become visible with the default color
objRenderer.HeadingRowPrefix = "<tr valign='top'>"
objRenderer.HeadingRowSuffix = "</tr>"
Download an attachment It is possible to access the attachments of a particular message. You just need to sent the binary data stream to the browser like this:

' MAPI property for attachment binary data
Const CdoPR_ATTACH_DATA_BIN = &H3701010

' Set attachment filename
If objMessage.Attachments.Count <> 0 Then
  Set objAttachment = objMessage.Attachments.GetFirst()
  bstrFileName = objAttachment.Name
End If

' Add the appropriate HTTP header to the response object
Response.AddHeader "Content-Disposition", "attachment;filename="_
+ bstrFileName

' Create object  renderer and set DataSource to attachment object
Set objRenderer = objRenderApp.CreateRenderer(2)
objRenderer.DataSource = objAttachment

' Send the attachment data stream back to the browser
objRenderer.RenderProperty CdoPR_ATTACH_DATA_BIN, 0, Response

For a list of the most common MAPI property tags, please take a look at 'Digging deeper into CDO', Property Tags and Types or use the CDO.HLP file, which is located on the Microsoft Exchange Server 5.5 CD-ROM. Note, that an updated version is included with the Microsoft Exchange Server 5.5 Service Pack 1 (or higher). You can also download the most current version from CDOLive cdo.zip (1,065 Kbyte).