Introduction to RDO

RDO (Redemption Data Objects) is Redemption's automation-friendly object model for Outlook and Exchange data. Use it in addition to, or instead of, the Outlook Object Model when your code needs direct access to stores, folders, messages, MAPI properties, profiles, tables, rules, and Exchange mailbox data.

RDO is also useful when Extended MAPI is the right API, but you want to use it from C#, VB.NET, VBA, Delphi, C++, or script code through COM-friendly objects instead of writing unmanaged Extended MAPI code directly.

Safe*Item Redemption objects are the minimal-change option for existing Outlook Object Model code that needs to work around security prompts. RDO is the broader object model for code that needs a fuller Outlook, Exchange, and MAPI view of the mailbox.

RDO can share the MAPI session already used by Outlook through RDOSession.MAPIOBJECT, or it can create its own session through one of the RDOSession logon methods. These two options are the usual starting point for code that extends Outlook directly or works with mailbox data without automating every operation through the Outlook Object Model.

RDO combines Extended MAPI-level access with an Outlook-style object model. It can be used from any code: COM add-ins, EXEs, scripts, Windows Services, etc. It can be used in any language that can use COM automation objects, including C#, VB.NET, VBA, Delphi, C++, and scripting languages.

 

Getting Started with RDO

 

The main creatable RDO object is Redemption.RDOSession. All other RDO objects are retrieved through the RDOSession object, either directly or indirectly. Once you create an instance of the Redemption.RDOSession object, you must log on or connect to a MAPI session to be able to access other RDO objects, such as RDOStore, RDOFolder, RDOMail, etc. To differentiate between various Redemption objects (such as Redemption.SafeMailItem), all RDO object names are prefixed with "RDO": e.g. RDOMail object exposes attachments through its Attachments collection, which in turn returns Redemption.RDOAttachments objects, etc.

If you already use the Outlook Object Model, RDOSession corresponds fairly closely to the Outlook Namespace object, but exposes lower-level MAPI access and additional mailbox functionality. If you are maintaining legacy CDO 1.21 code, RDO can also provide a path forward.

There are several ways to log on to a MAPI session in RDO:

  • set the RDOSession.MAPIOBJECT property to Outlook's current session, usually Application.Session.MAPIOBJECT. This is the preferred path for Outlook add-ins and macros because RDO uses the same profile and logged-on session as Outlook.

  • use RDOSession.LogonHostedExchangeMailbox or related Exchange mailbox methods for Exchange and Microsoft 365 mailbox scenarios where your code needs to create its own session.

  • use RDOSession.LogonPstStore for PST-only work. It creates a temporary MAPI profile with the specified PST store as the only service.

  • use RDOSession.Logon to log on to an existing MAPI profile. Legacy code can also pass an IMAPISession retrieved through Extended MAPI or CDO 1.21 to MAPIOBJECT, but new Outlook code normally shares Outlook's Application.Session.MAPIOBJECT instead.

Once you are logged on to a MAPI session, you can start accessing various MAPI objects exposed by RDO. The example below logs to the default MAPI session and prints out the subject of all messages in the Inbox folder:

set Session = CreateObject("Redemption.RDOSession")
Session.Logon
set Inbox = Session.GetDefaultFolder(olFolderInbox)
for each Msg in Inbox.Items
  Debug.Print(Msg.Subject)
next

 

Of course you can mix RDO with the Outlook Object Model. The example below reads the SenderName property blocked by Outlook from an Outlook MailItem object using RDO.

set Session = CreateObject("Redemption.RDOSession")

'make sure RDO uses the same MAPI session as Outlook. Outlook 2002 and up only!
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
Msg = Session.GetItemFromID(MailItem.EntryID)

MsgBox Msg.SenderName

 

The same functionality can of course be implemented using the old SafeMailItem Redemption object:

set SafeItem = CreateObject("Redemption.SafeMailItem")

SafeItem.Item = MailItem

MsgBox SafeItem.SenderName

 

 

Important RDO distinctions from the Outlook Object Model

  • RDOSession gives explicit control over the MAPI session. It can connect to Outlook's session by setting the MAPIOBJECT property, or it can create its own session through Logon, LogonExchangeMailbox, or LogonPstStore.

  • RDO objects can be used from multiple threads, both inside and outside of outlook.exe. Outlook Object Model access is effectively tied to Outlook's main thread: Outlook add-ins can fail when Outlook detects OOM access from a secondary thread, and external automation calls are marshaled back to Outlook's main thread. RDO does not have that object model limitation; initialize MAPI on each worker thread by creating an RDOSession or another creatable Redemption object there, and share the same MAPI session by assigning RDOSession.MAPIOBJECT. See Using Redemption objects on multiple threads.

  • Message import and export are first-class RDO operations. RDOMail.Import can import data into an existing item, RDOMail.SaveAs can export messages to formats such as MSG, EML/RFC822, HTML/MHTML, and Fast Transfer Stream, and RDOFolder2.Import can create one or more items in a folder from a file, stream, or byte array. Outlook has MailItem.SaveAs for supported export formats, but it does not have a comparable general import API.

  • MAPITable exposes Extended MAPI tables wherever the underlying MAPI API provides an IMAPITable, including folders, attachments, recipients, stores, address book containers, ACLs, and other collections. Outlook has Folder.GetTable for folder and search-result rowsets, but RDO provides broader table coverage, SQL-style ExecSQL, explicit restriction objects, and lower-level table access.

  • Extended MAPI properties are available through the Fields() collection on RDO objects derived from _MAPIProp. Properties can be addressed by property tag, such as PR_SUBJECT = 0x0037001E, or by DASL name, such as http://schemas.microsoft.com/mapi/proptag/0x0037001E. Outlook's PropertyAccessor can read many properties, but the Outlook Object Model can block writes to protected or provider-owned properties. RDO stays closer to Extended MAPI: it sends the write to the provider and returns the provider's result if the operation is rejected. See RDOFolder, RDOStore, RDOMail, RDOAttachment, RDOAddressEntry, and RDOAddressList.

  • RDO has dedicated entry points for shared, cached, delegate, archive, and PST stores, including RDOSession.GetSharedMailbox, GetCachedSharedMailbox, GetArchiveMailbox, AddDelegateExchangeStore, and AddPstStore. AddPstStore returns the newly opened RDOStore, and RDOPstStore exposes the PST path.

  • Address book resolution can be scoped to a particular address list, such as the Global Address List or a Contacts folder, instead of resolving against the whole address book. RDOAddressBook.ResolveNameEx and RDOAddressList.ResolveNameEx can also return and inspect ambiguous matches instead of forcing a single resolved recipient, and RDOAddressBook.SearchPath exposes the address book search path used by automatic name resolution.

  • Recoverable items and deletion modes are exposed directly. RDOFolder exposes DeletedItems and DeletedFolders for Exchange recoverable content, while RDOMail.Delete and RDOItems.Remove support move-to-Deleted-Items, soft-delete, and hard-delete behavior.

  • Exchange rules and client-side rules are exposed beyond the standard Outlook rules surface. RDO can work with store and folder rules, public-folder rules, and Outlook client rules, including RWZ rule files through RDOClientRules.

  • RDO exposes Exchange and Outlook data areas that are missing or limited in the Outlook Object Model, including RDOFolder.ACL, RDOSearchFolder, RDOStore.Reminders, RDOQuickSteps, RDOFavorites, and RDOTemplates.

  • Bulk item operations can be performed without opening each item one by one. RDOItems exposes CopyMultiple, MoveMultiple, RemoveMultiple, and progress events for long-running operations.