Outlook Object Model

Extended MAPI

Outlook Object Model

Accessing anything in the Outlook Object Model

OutlookSpy exposes common Outlook objects directly on the ribbon. How do you inspect child objects, such as the first recipient of the selected message?

You can browse from a parent object to its child objects in the Outlook Object Model browser. For example, open a MailItem window, select the Attachments property, and click Browse to open the Attachments collection.

For indexed collections such as Recipients, select the Recipients property and click Browse. In the Recipients window, open the Functions tab, select Item, click Call, and pass 1 as the parameter. OutlookSpy opens the first Recipient object for that message.

You can also use the Script tab:

BrowseObject(MailItem.Recipients.Item(1))

Executing Outlook commands not available through the Object Model

Some classic Outlook UI commands do not have direct object model methods. How can you identify the command button to execute it programmatically?

If an Outlook object exposes the CommandBars property, OutlookSpy displays a CommandBars tab. Explorer and Inspector objects are common examples.

The CommandBars tab shows command bars and their child controls in a tree. Browse the control you need, note its ID, and use that ID in your own automation code. For example, the classic Send/Receive command uses ID 5488:

Set Btn = Application.ActiveExplorer.CommandBars.FindControl(1, 5488)
Btn.Execute

This is mainly useful for classic Outlook automation scenarios. Newer Office extensibility models do not expose the same CommandBars surface.

Extended MAPI

Comparing two messages

You have a message created by your code and a native Outlook message. They look similar, but Outlook does not handle the generated message correctly.

Open both messages in OutlookSpy with the IMessage command. In one IMessage window, open the Compare tab. Drag PR_ENTRYID from the second message into the Compare tab of the first message.

OutlookSpy compares the property sets and can show properties that are different, missing from one object, extra on one object, or the same on both objects. See the Extended MAPI how-to for a current screenshot of the Compare tab.

Finding changed message properties

You changed something through the Outlook UI and need to identify which Extended MAPI properties changed.

Open the message in an IMessage window. OutlookSpy installs an advise sink with IMsgStore::Advise() to monitor notifications related to the current message.

Open the Watch tab, select the properties you want to monitor, and move them into the watch list. When the message changes, OutlookSpy handles the related fnevObjectModified notifications, compares old and new values, and logs changed properties on the Watch tab.

Opening any object by entry ID

You found a binary property that might be an entry ID, or an IMsgStore::Advise() notification logged an entry ID and you need to identify the object.

IMAPISession, IAddrBook, IMsgStore, and IMAPIFolder windows include an OpenEntry tab. Drag any PT_BINARY or PT_MV_BINARY property to that tab and OutlookSpy tries to open it with the corresponding OpenEntry() method.

If you only have the hex representation of an entry ID, use Enter Entry ID Manually and paste the value. As a shortcut, right-click a PT_BINARY or PT_MV_BINARY property on a GetProps tab and choose IMAPISession::OpenEntry().

Accessing invisible Outlook folders

You can open visible Outlook folders from the Outlook UI, but how do you browse folders that Outlook does not show?

Open the IMsgStore window and click Open Root Container. OutlookSpy calls IMsgStore::OpenEntry(0, NULL, ...), which returns the root folder of the message store.

From the root folder, open the GetHierarchyTable tab and browse child folders from there. This works for folders that are visible in Outlook and folders that are hidden from the normal Outlook UI.

Constructing arbitrary restrictions in Extended MAPI

Programmatically building complex MAPI restrictions is tedious. Can OutlookSpy help inspect a restriction created by Outlook?

Use Outlook to build the restriction for you. In classic Outlook, open Advanced Find, create the criteria in the UI, and run the search. Outlook creates a temporary search folder.

Keep Advanced Find open so Outlook does not delete the temporary folder. In OutlookSpy, open IMsgStore, click Open Root Container, then use GetHierarchyTable to open the root search folder, such as Search Root or Finder. Open the generated search folder from there.

Search folder windows include a GetSearchCriteria tab. That tab displays the restriction Outlook created, which you can use as a model for your own code.

Using OutlookSpy features outside OutlookSpy

You have a COM object or MAPI object in your own code and want to open it directly in OutlookSpy's object browser.

OutlookSpy exposes an API that can display its browser for objects it understands. Create an OutSpy.Utils COM object and call Utils.BrowseObject(Object, ParentWnd).

Set Utils = CreateObject("OutSpy.Utils")
Utils.BrowseObject(MyObject)

Copying properties from one object to another

You have two MAPI objects with different property sets and want to copy one or more properties from one object to another.

Select the properties on the source object, such as IMessage, IMAPIFolder, or another IMAPIProp-derived object. Drop them on the GetProps tab of the target IMAPIProp-derived object.

OutlookSpy calls IMAPIProp::CopyProps() on the source object and saves the target object.

Importing and exporting messages

Outlook can save normal messages as MSG files, but how do you export or import invisible associated messages, such as folder view descriptor messages?

Open any IMessage window and click Save as MSG file. You can then drag the saved MSG file from Windows Explorer back into a folder.

To create a regular or associated message, open an IMAPIFolder window and drop the MSG file on the list in either the GetContentsTable tab or the Associated Contents tab.