|
This tips and tricks section provides some basic and also special tasks for CDO. 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.
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).
| Task | Description | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Implement a detailed error trapping | Because CDO does not display any dialog boxes, logon screens, or
error messages, it is a good choice to implement a detailed error
trapping. Each time you use: Err.Clear On Error Resume Next Set Object = Expression check if an error is returned with: If Err.Number <> 0 Then ' Your error handling here, use Err.Number and Err.Description to identify the problem Else ' Your code here ... End If |
|||||||||||||||
| Frequently object creation needs more system resources | Because CDO internally creates a temporary object for each
period that appears in the statement, reuse objects whenever
possible. Do not use: Subject = objSession.Inbox.Messages.Item(1).Subject Create intermediary objects by using: Set objMessages = objSession.Inbox.Messages Set objMessage = objMessages.Item(1) strSubject = objMessage.Subject once and use it within the rest of your code. |
|||||||||||||||
| Use the 'For Each', 'Next' statement to loop through a collection | If you need to loop through a collection, you can use the 'For
Each', 'Next' statement: For Each objMessage In objMessages strSubject = objMessage.Subject Next |
|||||||||||||||
| Do not use the 'For Each', 'Next' statement to loop through a collection and add or delete objects of the collection at the same time | Be aware of that if you want to add or delete objects from a
collection while looping through the same collection, do not use the
'For Each', 'Next' statement. This will end up in
an undefined behavior. Always use the 'For', 'Next'
statement to accomplish that: For intCounter = 1 To objFields.Count Set objField = objFields(intCounter).Value Debug.Print objField.Value Next Note that you cannot use the Count property with so called large collections. For a large collection the service provider cannot always maintain an accurate count of member objects. Large collections support Get methods that enable you to access individual members of the collection. The following collections are large collections: Messages; AddressEntries; Folders For a so called small collection the service provider maintains an accurate count of member objects. You can directly access individual members of the collection using an index. The following collections are small collections: AddressLists; Attachments; InfoStores; Recipients; Fields; Columns; Formats; Patterns; Views |
|||||||||||||||
| Loop through a large collection | As mentioned above you cannot loop through a so called large
collection using the 'For', 'Next' statement
if you want to modify the collection at the same time. Instead of
use the following code: ' Get first element Set objMessage = objMessages.GetFirst() ' Loop through the collection Do While Not objMessage Is Nothing ' Pull out subject of next message Debug.Print objMessage.Subject ' Get next message Set objMessage = objMessages.GetNext() Loop |
|||||||||||||||
| Delete items of a large collection | If you want to delete items of a collection you must use a
reversal loop, because the count of the collection is not updated at
the same time. Use the following code: ' Get message collection Set objMessages = objSession.Inbox.Messages ' Loop recursive through the message collection While objMessages.Count <> 0 objMessages(intCounter).Delete Wend |
|||||||||||||||
| Check the version of the CDO library | You can check the version of the installed CDO library by using
the following code in your Outlook form: ' Create MAPI session Set objSession = CreateObject("MAPI.Session") ' Logon using an existing MAPI session objSession.Logon "", "", False, False, 0 ' Check the version of the CDO library strVersion = objSession.Version If you have Microsoft Outlook 98 installed, but the result of the check above is "1.1" or "1.0a", it is possible that CDO 1.21 is not installed properly on your machine. If you are running Microsoft Windows NT open a command window, change to your windows\system directory (e. g. 'C:\WINNT\SYSTEM32') and run 'REGSVR32.EXE CDO.DLL' to re-register the CDO library. A complete list of the CDO library version numbers can be found at 'Digging deeper into CDO', Versions. |
|||||||||||||||
| Log on, send a message and log off | Sending a message using CDO is very simple. In VBScript use: ' Create MAPI session Dim objSession Set objSession = CreateObject("MAPI.Session") In VB and VBA use: Dim objSession As MAPI.Session Set objSession As New MAPI.Session ' Logon using an existing MAPI session objSession.Logon "", "", False, False, 0 ' Or, logon using an existing MAPI profile with a new session objSession.Logon "<Profile Name>", "", False, True, 0 ' Or, logon using an new MAPI session with a dynamically created profile strProfileInfo = "<Your Servername>" & vbLf & "<Your Mailbox>" objSession.Logon "", "", False, True, 0, False, strProfileInfo ' Create a new message Set objNewMessage = objSession.Outbox.Messages.Add ' Add a subject objNewMessage.Subject = "This is a message created with CDO" ' Add text to the message body ' Note that CDO 1.x cannot add text formatted with RTF or HTML ' Only Plain Text is supported in the current version objNewMessage.Text = "Welcome to the world of CDO. Enjoy your life!" ' Add recipient and resolve against the directory Set objRecipient = objNewMessage.Recipients.Add objRecipient.Name = "John Doe" objRecipient.Resolve ' Send message objNewMessage.Update objNewMessage.Send ' Logoff from MAPI Session objSession.Logoff Note that if you want to logon using the default MAPI profile, you must determine the name of the MAPI profile which is stored in the registry. There is an article 'Logging on to Active Messaging Session w/ Default Profile' at the Microsoft Knowledge Base about that behavior. For more information, please take a look at Knowledge Base Articles about CDO & Scripting and Routing |
|||||||||||||||
| Post a message to a folder | You can post a message to a particular folder using CDO, not
necessary if it is a public or private folder: ' Set the destination folder, in this sample the inbox Set objFolder = objSession.Inbox ' Create a new message in that folder Set objNewMessage = objFolder.Messages.Add ' Add content objNewMessage.Subject = "This is a message created with CDO" objNewMessage.Text = "Welcome to the world of CDO. Enjoy your life!" objNewMessage.ConversationTopic = objNewMessage.Subject objNewMessage.TimeReceived = Now objNewMessage.TimeSent = Now objNewMessage.Sent = True objNewMessage.Submitted = False objNewMessage.Unread = True ' Post (NOT sent) message objNewMessage.Update Note that in Microsoft Visual Basic you can use the With statement to speed up your code like this: ' Set the destination folder, in this sample the inbox Set objFolder = objSession.Inbox ' Create a new message in that folder Set objNewMessage = objFolder.Messages.Add ' Add content With objNewMessage .Subject = "This is a message created with CDO" .Text = "Welcome to the world of CDO. Enjoy your life!" .ConversationTopic = objNewMessage.Subject .TimeReceived = Now .TimeSent = Now .Sent = True .Submitted = False .Unread = True End With ' Post (NOT sent) message objNewMessage.Update |
|||||||||||||||
| Get an Outlook default folder | Microsoft Outlook maintains a set of default folders to store
different type of data. This folder can be accessed by the following
way: ' CDO 1.x folder constants Public Const CdoDefaultFolderCalendar = 0 Public Const CdoDefaultFolderContacts = 5 Public Const CdoDefaultFolderDeletedItems = 4 Public Const CdoDefaultFolderInbox = 1 Public Const CdoDefaultFolderJournal = 6 Public Const CdoDefaultFolderNotes = 7 Public Const CdoDefaultFolderOutbox = 2 Public Const CdoDefaultFolderSentItems = 3 Public Const CdoDefaultFolderTasks = 8 ' Get the default calendar folder Set objFolder =_ objSession.GetDefaultFolder(CdoDefaultFolderCalendar) Note that you can not use this method to access other users folder. To access other users folder you need to logon to the mailbox of the user in question and open the appropriate folder. Logon to the appropriate mailbox is only possible if the Microsoft Windows NT account in question does have the required permission. Also it is not possible to access the "Drafts" folder with this method, because it is not supported by the current version of CDO. An alternate way is to get the "Drafts" folder by using the following method: ' MAPI property to access the drafts folder Public Const CdoPR_DRAFTS_FOLDER = &H36D70102 ' Get inbox folder Set objInbox = objSession.Inbox ' Get entry ID of drafts folder strDraftsEntryID = objInbox.Fields.Item(CdoPR_DRAFTS_FOLDER) ' Get drafts folder Set objFolder = objSession.GetFolder(strDraftsEntryID, Null) ' Finally display the name of the folder MsgBox objFolder.Name If CDO 1.2.1 and Microsoft Outlook 98 are sharing a stored profile, GetDefaultFolder returns CdoE_NO_SUPPORT if the ObjectType parameter specifies CdoDefaultFolderCalendar. To avoid this behavior, the recommended procedure is to use different profiles for CDO and Outlook 98. You can do this by specifying separate stored profiles for each, or by supplying the ProfileInfo parameter in the Session object's Logon method. |
|||||||||||||||
| Create a new Outlook folder | While it is possible with CDO 1.x to add folders there seems to
be no way to create Outlook standard folders, like contacts, tasks,
calendar etc. However, you can use the following code to define the
folder type when creating the new folder: ' MAPI properties used Const CdoPR_CONTAINER_CLASS = &H3613001E ' Create new folder Set objFolder = objFolders.Add("MyFolder") ' Get fields collection Set objFields = objFolder.Fields ' Set folder type field objFields.Add CdoPR_CONTAINER_CLASS, "IPF.Contact" ' Save changes objFolder.Update |
|||||||||||||||
| Get a valid AppointmentItems collection | With CDO 1.2x Microsoft added support for appointments.
Unfortunately they are only supported in the default calendar folder
of the primary delivery location. Use the following code to get a
valid AppointmentItems collection: ' Get the default calendar folder Set objFolder =_ objSession.GetDefaultFolder(CdoDefaultFolderCalendar) ' Get the Appointment Items collection Set ojbAppointmenItems = objFolder.Messages ' Loop through the AppointmentItems collection For Each objAppointment In objAppointmentItems ' Display start time of each appointment MsgBox objAppointment.StartTime Next Note that you can't retrieve a valid appointment item object from an Exchange Server public folder or any other folder than your default calendar. This is a design limitation of CDO 1.2x. |
|||||||||||||||
| Get the parent of the current folder | Sometimes it is necessary to determine what the parent folder
is. Use the following code to get the parent folder as CDO folder
object: ' Constant for default calendar folder Public Const CdoDefaultFolderCalendar = 0 ' Get default calendar folder Set objFolder = objSession.GetDefaultFolder(0) ' Get parent folder entry ID strParentID = objFolder.FolderID ' Get parent folder as CDO object Set objParentFolder = objSession.GetFolder(strParentID, Null) |
|||||||||||||||
| Get the sender information of an Outlook item | If you want to get the information of the a sender of a message
within an Outlook form use the following code: ' Create MAPI session Set objSession = CreateObject("MAPI.Session") ' Logon using an existing MAPI session objSession.Logon "", "", False, False, 0 ' Get folder where the current Outlook item lives Set objFolder = Item.Parent ' Get the Outlook item with CDO Set objMessage = objSession.GetMessage(Item.EntryID, objFolder.StoreID) ' Get the sender of the message Set objSender = objMessage.Sender ' Pull out some properties of the sender MsgBox "Sender name: " objSender.Name MsgBox "Sender address: " objSender.Address ' Close MAPI session objSession.Logoff |
|||||||||||||||
| Populate a combo box of an Outlook form with the Global Address List | If you want to populate a combobox with all names of the global
address list use the following code: ' Constant for global address list Public Const CdoAddressListGAL = 0 ' Create object reference to the combo box Set objList = Item.GetInspector.ModifiedFormPages("Message").ComboBox1 objList.Clear ' Get global address list Set objAddressList = objSession.GetAddressList(CdoAddressListGAL) ' Get address entries of the global address list Set objAddressEntries = objAddressList.AddressEntries ' Loop through the address entries collection For Each objAddressEntry In objAddressEntries ' Add each address entry to the combo box objList.AddItem objAddressEntry.Name Next |
|||||||||||||||
| Add an attachment to a message |
You can add four different types of attachments to a message, but
you must take care of the different properties which must be set: ' Adding an attachment Set objAttachment = objMessage.Attachments.Add ' Setting the position where the attachment should be placed ' In this case at the beginning of the message, use -1 to place the ' attachment at the end of the message body. Note that this is only ' necessary for RTF enabled messages. objAttachment.Position = 0 ' Setting the attachment type and add it as a file ' Note that a list of possible attachment types is shown in the table below objAttachment.Type = CdoFileData objAttachment.ReadFromFile "c:\autoexec.nt" objAttachment.Source = "c:\autoexec.nt" ' Or, add the attachment as link to a file objAttachment.Type = CdoFileLink objAttachment.Source = "\\Server\Share\autoexec.nt" ' Setting the attachment name objAttachment.Name = "autoexec.nt" ' Or, add the attachment as OLE object objAttachment.Type = CdoOLE objAttachment.Source = "Word.Document" ' Setting the attachment name objAttachment.Name = "doc1.doc" ' Or, add the attachment as MAPI message objAttachment.Type = CdoEmbeddedMessage objAttachment.Source = <ID property of the message object> ' Finally update the message to add the attachment objMessage.Update The attachment overwrites the placeholder character at the position specified by the attachment's Position property. A space is normally used for the placeholder character. The CDO Library does not actually place the attachment within the message; that is the responsibility of the messaging client application. You can also use the value –1 for the Position property, which indicates that the attachment should be sent with the message, but should not be placed by the Position property. The CDO Library supports several different kinds of attachments: files, links to files, OLE objects, and embedded messages. An attachment's type is specified by its Type property. To add an attachment, use the related Attachment object property or method appropriate for that type, as shown in the following table:
More information can be found in 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). |
|||||||||||||||
| Extract all attachments of a message | You can extract all attachments
from a message using the following code: ' Set the destination folder Set objFolder = objSession.Inbox ' Get message collection of the inbox Set objMessages = objSession.Inbox.Messages ' Get first message of inbox Set objMessage = objMessages.Item(1) ' Loop through the attachments collection For Each objAttachment In objMessage.Attachments ' Extract all attachments to the filesystem strAttachName = objAttachment.Name objAttachment.WriteToFile("c:\" & strAttachName) Next The WriteToFile method overwrites the file without warning if a file of that name already exists. It operates differently, depending on the value of the Attachment object's Type property. The following table describes its operation:
Note that the current version of CDO does not support WriteToFile for CdoFileLink or CdoEmbeddedMessage attachments. |
|||||||||||||||
| Copy/Move a message | You
can copy a message using the CopyTo method of CDO: ' Set the destination folder Set objFolder = objSession.Outbox ' Get message collection of the inbox Set objMessages = objSession.Inbox.Messages ' Get first message of inbox Set objMessage = objMessages.GetFirst() ' Create a copy of the message in the inbox Set objCopyMessage = objMessages.CopyTo(objFolder.ID) ' Update copied message objCopyMessage.Update Set objCopyMessage = Nothing Note that the message body will retain the rich text formatting (RTF) if you use the CopyTo method. You can also move a message using the MoveTo method: Set objNewMessage = objMessage.MoveTo(objSession.Inbox.ID,_ objSession.Inbox.StoreID) All properties that have been set on this message are moved, whether they have read-only or read/write access. Each property is moved with its value and access unchanged. Note that the current version of CDO does not support the MoveTo method on AppointmentItem objects. |
|||||||||||||||
| Send a message with high priority |
While it is possible with CDO 1.x to send a message with a
particular importance, it is not possible to set the message
priority directly. This is especially useful if you want to have
your Exchange Server MTA handle the message with a higher priority.
You can use the following code to set the message priority: ' MAPI property used Const CdoPR_PRIORITY = &H00260003 ' Message priority options Const CdoPR_PRIORITY_LOW = -1 Const CdoPR_PRIORITY_NORMAL = 0 Const CdoPR_PRIORITY_HIGH = 1 ' Create new message Set objMessage = objSession.Outbox.Messages.Add ' Set message priority objMessage.Fields.Add CdoPR_PRIORITY, CdoPR_PRIORITY_HIGH ' Set recipient objMessage.Recipients.Add("John Doe", "John@Doe.net", "SMTP") ' Update and send message objMessage.Update objMessage.Send |