Chinaunix首页 | 论坛 | 博客
  • 博客访问: 360786
  • 博文数量: 157
  • 博客积分: 3001
  • 博客等级: 中校
  • 技术积分: 1330
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-06 13:47
文章分类

全部博文(157)

文章存档

2011年(1)

2010年(28)

2009年(124)

2008年(4)

我的朋友

分类: WINDOWS

2009-08-13 15:22:48

Miscellaneous Outlook Redemption Objects
or Welcome to the world of Extended MAPI

  •    

What's missing from the Outlook Object Model

  • While Outlook does expose a lot of Extended MAPI properties via its object model, there are many (hundreds) of properties that are only accessible via Extended MAPI. Some of these properties were probably deemed not important enough to be included in the Outlook object model, some others are Exchange Server or PST specific and hence didn't quite fit into the object model. If you browse Outlook newsgroups archives, there are plenty of questions like "Whenever I access a recipient address, Outlook gives me an Exchange address, but how do I get an SMTP address?", "How do I find out the size of all messages in a folder?" or "How do I find out sender's e-mail address?". The answer to all of these and many other questions is "Use Extended MAPI". This doesn't make the majority of VB and VBA developers feel warm and cozy, given the fact that VB cannot directly access Extended MAPI interfaces and structures. If you want to get a feeling what properties are available, get .

  • Displaying the Address book - only CDO and Extended MAPI have this ability.

  • Flushing incoming and outgoing message queues - Tools | Send/Receive menu in Outlook or Session.DeliverNow method in CDO, or IMAPIStatus::FlushQueues() in Extended MAPI

  • Comparing two items: how do you find out if two items are the same? You can get away with manually comparing EntryIDs of the two items, but the politically correct way is to call IMAPISession.CompareEntryIDs() in Extended MAPI or Session.CompareIDs() in CDO.

Redemption.MAPIUtils object

To address shortcomings of the Outlook object model, Redemption includes a utility object - Redemption.MAPIUtils. See below examples on how to use this object.


Method name

Arguments

Comments


HrGetOneProp

Returns the value of an Extended MAPI property

MAPIProp - object

Outlook item (MailItem, ContactItem, etc) or its MAPIOBJECT property (MailItem.MAPIOBJECT, etc)
Note that you can access the same properties if you use

 

PropTag - integer

Integer property tag.


HrSetOneProp

Sets an Extended MAPI property.

MAPIProp - object

Outlook item (MailItem, ContactItem, etc) or its MAPIOBJECT property

PropTag - integer

Integer property tag.

Value -variant

The value of the property. Make sure that you pass the value of correct type: if you set a string property, pass a string, passing an integer returns an error

bSave - boolean, optional     

Optional parameter. When set to true, Redemption will call IMAPIProp::SaveChanges(). Otherwise you will need to call Save on the item yourself. Be advised that Outlook keeps its own cache of changes and if Outlook thinks that no changes have been made, calling Save on an Item will not do anything.


GetIDsFromNames

Returns a bytes integer tag for a named property given property's GUID and ID.

MAPIProp - object

Outlook item (MailItem, ContactItem, etc) or its MAPIOBJECT property

GUID - string

String representation of the GUID

ID - variant (integer or string)

Named property ID. Can either be a string or an integer.

bCreate - boolean

If set to true and the property with the above parameters has never been created by Outlook, it will be created. If false, the function returns a valid property tag only if it has been already created.


DeliverNow

Forces the delivery of incoming and/or outgoing messages

Flags (optional)

ParentWndHandle (optional)

Optional arguments:

Flags: any combination of the following flags: fqUpload (1), fqDownload (2), fqUploadDownload (3), fqShowProgress (4), fqAsync (8). If Flags is 0 or missing, the following flags are used: fqUpload+fqDownload+fqShowProgress (7)

ParentWndHandle: parent window handle if Flags includes fqShowProgress flag

 


CompareIDs

Compares if two items are the same

ID1 - string

Entry ID of the first item

ID2 - string

Entry ID of the second item


AddressBook

Displays address book. Similar to CDO's Session.AddressBook(). Returns Recipients collection.

Recipients - object, optional

Recipients object (e.g. MailItem.Recipients) to display in the Address book dialog

Title - string, optional

Title of the address book dialog

OneAddress - boolean, optional

Allow only one address to be selected

ForceResolution - boolean, optional

Force all returned recipients to be resolved

RecipLists - integer, optional

Number of wells in the address book dialog (3 by default - To, CC, BCC)

ToLabel - string, optional

"To" label 

CcLabel - string, optional

"CC" label

BccLabel - string, optional

"CC" label

ParentWindow - integer, optional

Handle to the parent window. If none is specified, foreground window will be used as a parent


Cleanup

Redemption needs to keep reference to the IMAPISession Extended MAPI interface. Outlook 2002 might have a problem properly closing if there is an outstanding reference. Calling this method ensures that Redemption cleans up its internal references to all Extended MAPI objects.


AddressBookFilter property (string)

When you set this property, Address Book shown with a call to MAPIUtils.AddressBook will only display the address book container(s) whose name matches the AddressBookFilter. E.g. if you set  AddressBookFilter to "Customers", AddressBook() method will only display subcontainers named "Customers".

ScCreateConversationIndex method

 

 

ParentConversationIndex - string

Returns string

 

The ScCreateConversationIndex method indicates where in a message thread a message belongs.

ParentConversationIndex can be either a ConversationIndex property from Outlook Object Model (MailItem.ConversationIndex)  or from .ConversationIndex  property (hex). For a new conversation index, pass an empty string.

Corresponds to ScCreateConversationIndex  in MAPI or to Session.CreateConversationIndex in CDO 1.21.


GetItemFromID
Returns MessageItem object

 

EntryIDItem - string

Entry Id of the message to open

EntryIDStore - string, optional

Optional Entry Id of a store (StoreID) where the item to open resides.


GetItemFromIDEx
Returns MessageItem object

 

 

EntryIDItem - string

 

Entry Id of the message to open

EntryIDStore - string, optional

Optional Entry Id of a store (StoreID) where the item to open resides.

Flags - integer, optional

Flags to be used when opening the message, e.g. MAPI_MODIFY (0x1) to specify that the write access must be granted, MAPI_NO_CACHE (0x200) to bypass the cache (Outlook 2003), etc.

By default, MAPI_BEST_ACCESS (0x10) is used.


HrGetPropList
Returns a collection of property tags exposed by an Outlook or Redemption object passed as a parameter. The returned collection (PropList) has two properties: Count and Item(Index)

set Utils = CreateObject("Redemption.MAPIUtils")
set PropList = Utils.HrGetPropList(MailItem)
for i = 1 to PropList.Count
  Debug.Print(Hex(PropList(i)))
Next

 

Obj - object

 

 

Any Outlook (MailItem, MAPIFolder, etc) or Redemption (Safe*Item, etc) object

 

bUseUnicode - boolean. optional

 

Force string prop tags to be returned in Unicode rather than ANSI


CreateRecipient
Returns SafeRecipient object which can be used in, for example, calls to SafeDistList.AddMember(), or if you just want to resolve a recipient's name without creating a temporary message first

Name - string

The name of the recipient to be resiolved or an e-mail address

ShowDialog - boolean, optional (default = false)

If true, CreateRecipient can display the name resolution dialog if the name cannot be resolved or if the name is ambigous.

ParentWnd - integer, optional (default = 0)

Handle of the window to be used as a parent of the name resolution dialog (ignored if ShowDialog = false)


Events

 MAPIUtils exposes the following events:


NewMail

Item - object

Unlike NewMail event in Outlook, MAPIUtils.NewMail event passes the new mail item as the argument to the event handler function. Beware that this generates more network traffic that using the Outlook's NewMail event, so declare MAPIUtils objects "with events" only when you need it.


Accessing raw Extended MAPI properties

A short overview of Extended MAPI properties

Most Extended MAPI objects (messages, folders, recipients, attachments, etc) are implemented as amorphous bags of properties. Unlike regular databases, MAPI objects can store both required properties (such as Entry ID) and any other properties that might only exist on a particular instance of an object. An example is a folder that contains both regular email messages and contacts; obviously these two kinds of messages are very different with different sets of properties. From the Extended MAPI point of view both kinds are messages (IMessage interface), the only difference is the sets of properties, but Extended MAPI doesn't care about that.

To access Extended MAPI properties, MAPI defines IMAPIProp interface from which most of Extended MAPI interfaces are derived (IMessage, IMsgStore, IMAPIFolder, IMailUser, IDistList etc). IMAPIProp interface has GetProps() method for retrieving any number of properties that particular object contains. 

Every Extended MAPI property is set and retrieved using a 4 bytes index: 2 upper bytes contain property id, while 2 lower bytes represent the type of the property (string, integer, binary array, etc). For example, e-mail message subject (PR_SUBJECT) has a hex value of 0x0037001E, where 0x0037 is property id and 0x001E signals its type as PT_STRING8.

Below is a table of Extended MAPI property types:


Property type

Hex value

Description


PT_UNSPECIFIED

0000

Reserved, not accessible to VB

PT_NULL

0001

null value

PT_I2, PT_SHORT

0002

signed 16 bit value

PT_I4, PT_LONG

0003

signed or unsigned 32 bit value

PT_R4, PT_FLOAT

0004

32 bit floating point

PT_R8, PT_DOUBLE

0005

64 bit floating point

PT_CURRENCY

0006

currency (64 bit integer)

PT_APPTIME

0007

date type

PT_ERROR

000A

32 bit error value

PT_BOOLEAN

000B

boolean

PT_OBJECT

000D

embedded object, not accessible to VB

PT_I8, PT_LONGLONG

0014

64 bit signed integer, not accessible to VB

PT_STRING8

001E

8 bit string

PT_UNICODE

001F

unicode string

PT_SYSTIME

0040

date type

PT_CLSID

0048

OLE GUID

PT_BINARY

0102

byte array


For example, PR_SENDER_EMAIL_ADDRESS Extended MAPI property tag has a hex ID of 0C1F and type PT_STRING8, therefore its 4 bytes property tag (hex) is &H0C1F001E. To access this property using Redemption, use the code below:

dim utils, MailItem, PrSenderEmailAddress, SenderEMail
set utils = CreateObject("Redemption.MAPIUtils")
set MailItem = Application.Session.GetDefaultFolder(6).Items(1)  'Get the first item in the inbox, can be any other item
PrSenderEmailAddress = &H0C1F001E
SenderEMail = utils.HrGetOneProp(MailItem.MAPIOBJECT, PrSenderEmailAddress)
MsgBox SenderEMail

Note that the same result can be achieved using SafeXXXItem object and its Fields collection:

dim sItem, MailItem, PrSenderEmailAddress, SenderEMail
set sItem = CreateObject("Redemption.SafeMailItem")
set MailItem = Application.Session.GetDefaultFolder(6).Items(1)  'Get the first item in the inbox, can be any other item
PrSenderEmailAddress = &H0C1F001E
sItem.Item = MailItem
SenderEMail = sItem.Fields(PrSenderEmailAddress)
MsgBox SenderEMail

Besides the types above Extended MAPI can also deal with multivalued (array) properties. To indicate a multivalued (array) property, "OR" its property type with a (hex) 1000, e.g. to indicate that a property is of type PT_MV_STRING8, "OR" PT_STRING8 (001E) with 1000: it will be 101E in hex. Example: PR_EMS_AB_PROXY_ADDRESSES property is a multivalued property of type PT_MV_STRING8 with a property id of 800F (hex). Its 4 bytes property tag is &H800F101E. If you are curious, this property is not exposed through the Outlook object model, but it has all e-mail addresses (EX, SMTP, FAX, etc) for an Exchange Server user (which is AddressEntry.MAPIOBJECT in Outlook object model, IMailUser in Extended MAPI).

To find out what properties a particular object exposes and their property tags, get MdbView or .

Named properties

So far so good. But what do you do if you want to store your own custom data with an item? How do you make sure that a property tag you select will not conflict with somebody's else property tag? The answer is named properties. While all properties are still accessed using 4 bytes property tags, Extended MAPI provides mechanism for making sure that your own property will not conflict with another named property. To create a custom property, generate a GUID (it is a good idea to use the same GUID for all of your custom properties) and an ID for each of your property. The ID can either be an integer or a string. Given the GUID and ID, Extended MAPI will return a unique for this particular item (or even for a message store) 4 bytes property tag.

This is exactly how Outlook implements UserProperties collection. The GUID for all Outlook's UserProperty's is {00020329-0000-0000-C000-000000000046} (it is PS_PUBLIC_STRINGS symbolic value in Extended MAPI). For example, to access Outlook's Categories property, the GUID is {00020329-0000-0000-C000-000000000046} and property ID is "Keywords" (again, MdbView or will show you the GUID and its ID for any property). Here is how you can access Categories without using Outlook object model: 

dim utils, MailItem, PrCategories, Categories
set utils = CreateObject("Redemption.MAPIUtils")
set MailItem = Application.Session.GetDefaultFolder(6).Items(1)  'Get the first item in the inbox, can be any other item
PrCategories = utils.GetIDsFromNames(MailItem.MAPIOBJECT, "{00020329-0000-0000-C000-000000000046}", "Keywords", true)
PrCategories = PrCategories + &H101E   'make sure we have the right property type - PT_MV_STRING8
Categories = utils.HrGetOneProp(MailItem.MAPIOBJECT, PrCategories)  'for PT_MV_STRING8 type properties we get back an array of strings
MsgBox Categories(0)

The same result using SafeXXXItem object:

dim sItem, MailItem, PrCategories, Categories
set sItem = CreateObject("Redemption.SafeMailItem")
set MailItem = Application.Session.GetDefaultFolder(6).Items(1)  'Get the first item in the inbox, can be any other item
sItem.Item = MailItem
PrCategories = sItem.GetIDsFromNames("{00020329-0000-0000-C000-000000000046}", "Keywords")
PrCategories = PrCategories + &H101E   'make sure we have the right property type - PT_MV_STRING8
Categories = sItem.Fields(PrCategories)  'for PT_MV_STRING8 type properties we get back an array of strings
MsgBox Categories(0)

The example above is probably a little bit artificial since you can access the same property using Outlook object model - the advantage is you get back an array of strings instead of a comma separated string. In some cases you might have to access named properties with a GUID different from PS_PUBLIC_STRINGS Outlook uses for UserProperties.

 

Examples of accessing raw Extended MAPI properties from VB or VBA

Below are some examples of accessing some Extended MAPI properties using Redemption. Note that you can access these properties using SafeXXXItem objects and their Fields collection - see examples above.

Internet headers  - PR_TRANSPORT_MESSAGE_HEADERS property. If you have spent any time in the Outlook developer newsgroups, you know how often this question is asked:

dim utils, oItem, PrHeaders, Subject
set utils = CreateObject("Redemption.MAPIUtils")
set oItem = Outlook.Session.GetDefaultFolder(6).Items(1)  'Get the first item in the inbox, can be any other mail item
PrHeaders = &H007D001E
Subject = utils.HrGetOneProp(oItem.MAPIOBJECT, PrHeaders)
MsgBox Subject

PR_SENDER_EMAIL_ADDRESS - this property is not exposed through the Outlook object model, but it comes quite handy:

dim utils, MailItem, PrSenderEmailAddress, SenderEMail
set utils = CreateObject("Redemption.MAPIUtils")
set MailItem = Outlook.Session.GetDefaultFolder(6).Items(1)  'Get the first item in the inbox, can be any other mail item
PrSenderEmailAddress = &H0C1F001E
SenderEMail = utils.HrGetOneProp(MailItem.MAPIOBJECT, PrSenderEmailAddress)
MsgBox SenderEMail

Default SMTP address of an Exchange user:

dim utils, MailItem, PrSMTPAddress, SMTPAddress
set utils = CreateObject("Redemption.MAPIUtils")
set MailItem = Outlook.Session.GetDefaultFolder(6).Items(1)  'Get the first item in the inbox, can be any other mail item
PrSMTPAddress= &H39FE001E
'Get SMTP address of the first recipient. It is assumed that the recipient is an Exchange Server user.
SMTPAddress = utils.HrGetOneProp(MailItem.Recipients(1).AddressEntry.MAPIOBJECT, PrSMTPAddress)
MsgBox SMTPAddress

Set a custom icon on a message. This property is not officially documented or supported, and the valid value ranges differ for the different versions of Outlook. The example below sets an "Open Envelope" icon on a mail item. You might want to use this if you don't want to show that an e-mail item was forwarded or replied. Play with the different values, see what custom icons you can set. You cannot set your own truly custom icons, only whatever Outlook already has using an integer index (256 in the example below):

dim utils, PrIconIndex, MailItem
set utils = CreateObject("Redemption.MAPIUtils")
set MailItem = Outlook.Session.GetDefaultFolder(6).Items(1)   'Get the first item in the inbox, can be any other mail item
PrIconIndex = &H10800003
utils.HrSetOneProp(MailItem, _
                          PrIconIndex, _
                         256, _      'this value corresponds to the "Open Envelope" icon. Try different values just for the fun of it!
                         true)         'save the item

 

阅读(2033) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~