MAPI Tables
Examples of accessing Extended MAPI Tables using MAPITable object
Using TableFilter.FindFirst/FindNext/FindLast methods (Search)
Everybody who ever tried to loop through a thousand messages in a folder using Outlook Object Model or CDO knows how painfully slow this can be. True, there are some tricks that can speed things up, e.g. calling Items.SetColumns() beforehand or optimizing the display algorithm (if that's what you need to do) to only retrieve the items visible to a user a couple dozen at a time. Still, neither OOM nor CDO are fast enough to make your code look blazingly fast. How come Outlook has no problem doing that?
The answer is MAPI tables. The general idea is that you can request an arbitrary set of properties from a set of messages in a folder in a single call, there is no need to do that one message at a time. Think of a MAPI table as a 2D array of data - each row corresponds to a single message with each column corresponding to a particular MAPI property. MAPI tables are used all over the place in Extended MAPI - contents and hierarchy tables in folders and address lists, message recipients and attachments, etc.
MAPI tables cannot however retrieve subobjects, such as message recipients or attachments (you can still create restrictions on recipients or attachments, see below). Another limitation in case of the Exchange provider is the size of the returned data - Exchange provider limits it to around 32 kB in a single call; that means you will never be able to retrieve message body if its size is greater than 32 kB and if you request too many rows, Exchange will return fewer rows than requested to keep the size of the returned data below 32 kB.
Redemption wraps IMAPITable Extended MAPI interface as a Redemption.MAPITable object. Similar to the Safe*Item objects, set MAPITable.Item property to any OOM or CDO object that exposes the RawTable property. This means that you can set the MAPITable.Item property to Items, Folders and AddressEntries in OOM and Messages, Folders, AddressEntries and Recipients objects in CDO. MAPITable is also returned by the MAPIFolder.Items.MAPITable object property.
MAPITable object is also exposed by the RDOStores, RDOACL, RDOItems, RDOFolders, RDOAddressLists, RDOAddressEntries, RDORecipients and RDOAttachments collections - you do not need to set the MAPITable.Item property in that case, simply use the MAPITable object returns by the MAPITable property of these collections.
Generally, there are two ways to use the MAPITable object:
1. Set the Columns property, specify the restriction using the MAPITable.Filter object (see examples below), then read the data using GoToFirst/GetRows methods. Use this method if you need to have an absolute control over the restriction.
2. Use the ExecSQL method, which allows to obtain a filtered and ordered set of data (returned in a standard ADODB.Recordset object) using a standard SQL query string. This is probably the easiest way to work with the MAPITable object.
|
||||
Method or property name |
Arguments |
Comments |
||
|
||||
Item (Object), read/write
|
This property must be set to either Items, Folders or AddressEntries in OOM or Messages, Folders, AddressEntries and Recipients objects in CDO |
|||
|
||||
RowCount (integer), read only |
Returns the total number of rows in the table
|
|||
|
||||
Columns (Variant array), read/write |
Use this property to set the table columns. See examples below. You can pass either a comma separated string with the OOM or DASL property names (e.g. "Subject, SenderName") or a variant array of integer property tags.
|
|||
|
||||
GoToFirst |
Sets the table pointer to the first row
|
|||
|
||||
GoToLast |
Sets the table pointer to the last row
|
|||
|
||||
GoTo |
Index - integer |
Sets the table pointer to Index
|
||
|
||||
GetRow |
Returns the current row as a variant array of variants and advances the table pointer to the next row. The properties returned are defined by the Columns property. If the row cannot be retrieved (e.g. the table pointer has reached the end of the table) Empty variant is returned instead of an array.
|
|||
|
||||
Sort Columns, Descending |
Columns - either a comma separated string with the OOM or DASL property names (e.g. "Subject, SenderName"), an integer property tag (when sorting by a single property) or a variant array of integer property tags. Descending - optional. Either a boolean or a variant array of boolean values corresponding to the Columns parameter.
|
Sorts the table on a single or multiple properties. See example below. |
||
GetRows |
Count - integer |
Returns the specified number of rows as a variant array. Each element of the array is another variant array of variant. The current table pointer is advanced by Count.
|
||
ExecSQL(SQLCommand) |
SQLCommand - string |
Returns an instance of the ADODB.Recordset object populated with data returned by executing the specified SQL query. See below for more information.
|
||
CreateBookmark |
|
|
|
Returns a bookmark (integer) that can be used by the GoToBookmark method
|
FreeBookmark Bookmark |
|
Bookmark - integer |
|
Frees a bookmark previously created by CreateBookmark. All bookmarks not freed by FreeBookmark will be freed when the MAPITable object is destroyed.
|
GoToBookmark Bookmark |
|
Bookmark - integer |
|
Scroll the table to the position specified by the bookmark created by CreateBookmark
|
GoToNext |
|
|
|
Scrolls the table to the next row
|
GoToPrevious |
|
|
|
Scrolls the table to the previous row
|
|
Note that under Exchange server if you request PR_ENTRYID property, short-term entry ids will be returned from the table. This kind of entry ids can only be used in the current session, you should never persist them; otherwise short-term entry ids work just like long-term entry ids. To force MAPITable to return long-term entry ids, request the PR_LONGTERM_ENTRYID_FROM_TABLE (0x66700102) property. This property is Exchange specific, to make your code work under both Exchange and PST providers, request both PR_ENTRYID and PR_LONGTERM_ENTRYID_FROM_TABLE properties. If PR_LONGTERM_ENTRYID_FROM_TABLE is missing, fall back to PR_ENTRYID.
Also note that if a property to be returned is too big or if it is not present for a particular row, the row's array element will be a variant of type error with the error type set to the MAPI code (e.g. MAPI_E_NOT_FOUND or MAPI_E_NOT_ENOUGH_MEMORY).
Retrieving table data using ExecSQL method
ExecSQL is the easiest way to retrieve MAPITable data using a standard SQL style query. You do not need to know anything about the raw MAPI restrictions, sort order, etc. Just specify a SQL query as a string and read the data from a standard ADODB.Recordset object. ExecSQL will parse the SQL query to extract the search criteria (WHERE clause), columns to return (SELECT ... clause) and the sort order (ORDER BY clause):
set Table = CreateObject("Redemption.MAPITable") |
ExecSQL supports the following SQL keywords and operators:
SELECT, WHERE, ORDER BY, TOP n, COUNT(*), AS, LIKE, =, <>, >, >=, <, <=, AND, OR, IN, NOT, IS NULL, IS NOT NULL, *
Other SQL keywords (such as INSERT, JOIN, GROUP BY, etc) are not supported.
If COUNT(*) is used in the SELECT clause, the returned recordset will contain a single row with a single value (column named "Count").
Column names in the SELECT, WHERE and ORDER BY clauses can be specified using either the DASL syntax (e.g. "urn:schemas:httpmail:subject" or "http://schemas.microsoft.com/mapi/proptag/0x0037001E") or using the Outlook Object Model or Redemption property name (e.g. Subject or EntryID) - see the list of the supported OOM properties below. Use OutlookSpy to figure out the DASL property names - select a message with the needed property in Outlook, click IMessage button on the OutlookSpy toolbar, select the property in the list, see the DASL edit box on the right hand side.
Important: DASL property names must be enclosed in quotes, e.g. (e.g. "urn:schemas:httpmail:subject"). OOM property names do not need to be quoted (e.g. Subject).
set Table = CreateObject("Redemption.MAPITable") |
The following Outlook Object Model / Redemption property names are supported. Properties not listed below must be specified using their MAPI property DASL syntax (use OutlookSpy).
ActualWork, AllDayEvent, AlternateRecipientAllowed, Anniversary, AssistantName, AssistantTelephoneNumber, Attachments, AutoForwarded, BCC, BillingInformation, Birthday, Body, Business2TelephoneNumber, BusinessAddress, BusinessAddressCity, BusinessAddressCountry, BusinessAddressPostalCode, BusinessAddressPostOfficeBox, BusinessAddressState, BusinessAddressStreet, BusinessFaxNumber, BusinessHomePage, BusinessTelephoneNumber, BusyStatus, CallbackTelephoneNumber, CardData, CarTelephoneNumber, Categories, CC, CheckSum, Children, Color, Companies, CompanyMainTelephoneNumber, CompanyName, Complete, ComputerNetworkName, ConferenceServerAllowExternal, ConferenceServerPassword, ContactAccount, ContactNames, ConversationIndex, ConversationTopic, CreationTime, CustomerID, DateCompleted, DeferredDeliveryTime, DelegationState, Delegator, DeleteAfterSubmit, Department, DLName, DueDate, Duration, Email1Address, Email1AddressType, Email1DisplayName, Email1EntryID, Email2Address, Email2AddressType, Email2DisplayName, Email2EntryID, Email3Address, Email3AddressType, Email3DisplayName, Email3EntryID, End, EndInEndTimeZone, EndUTC, EntryID, ExpiryTime, FileAs, FirstName, FlagDueBy, FlagIcon, FlagRequest, FlagStatus, FTPSite, FullName, Gender, GlobalAppointmentID, GovernmentIDNumber, HasPicture, Height, HidePaperClip, Hobby, Home2TelephoneNumber, HomeAddress, HomeAddressCity, HomeAddressCountry, HomeAddressPostalCode, HomeAddressPostOfficeBox, HomeAddressState, HomeAddressStreet, HomeFaxNumber, HomeTelephoneNumber, IMAddress, Importance, Initials, InternetCodepage, InternetFreeBusyAddress, ISDNNumber, IsOnlineMeeting, IsRecurring, IsRecurring, JobTitle, Journal, Language, LastModificationTime, LastName, Left, Location, MailingAddress, MailingAddressCity, MailingAddressCountry, MailingAddressPostalCode, MailingAddressPostOfficeBox, MailingAddressState, MailingAddressStreet, ManagerName, MeetingStatus, MeetingWorkspaceURL, MessageClass, MiddleName, Mileage, MobileTelephoneNumber, NetMeetingAutoStart, NetMeetingDocPathName, NetMeetingOrganizerAlias, NetMeetingServer, NetMeetingType, NetShowURL, NickName, NoAging, OfficeLocation, OptionalAttendees, Ordinal, OrganizationalIDNumber, Organizer, OriginatorDeliveryReportRequested, OtherAddress, OtherAddressCity, OtherAddressCountry, OtherAddressPostalCode, OtherAddressPostOfficeBox, OtherAddressState, OtherAddressStreet, OtherFaxNumber, OtherTelephoneNumber, OutlookInternalVersion, OutlookVersion, Owner, Ownership, PagerNumber, PersonalHomePage, PrimaryTelephoneNumber, Profession, RadioTelephoneNumber, ReadReceiptRequested, ReceivedByEntryID, ReceivedByName, ReceivedOnBehalfOfEntryID, ReceivedOnBehalfOfName, ReceivedTime, RecipientReassignmentProhibited, Recipients, ReferredBy, ReminderMinutesBeforeStart, ReminderOverrideDefault, ReminderPlaySound, ReminderSet, ReminderSoundFile, ReminderTime, ReplyRecipientNames, ReplyTime, RequiredAttendees, Resources, ResponseRequested, ResponseStatus, Role, SaveSentMessageFolder, SchedulePlusPriority, SelectedMailingAddress, SenderEmailAddress, SenderEmailType, SenderEntryID, SenderName, Sensitivity, Sent, SentOn, SentOnBehalfOfEmailAddress, SentOnBehalfOfEmailType, SentOnBehalfOfEntryID, SentOnBehalfOfName, Size, Spouse, Start, StartDate, StartInStartTimeZone, StartUTC, Status, StatusOnCompletionRecipients, StatusUpdateRecipients, Subject, Submitted, Suffix, TeamTask, TelexNumber, Title, To, Top, TotalWork, TTYTDDTelephoneNumber, UnRead, User1, User2, User3, User4, VotingResponse, WebPage, Width, YomiCompanyName, YomiFirstName, YomiLastName
Any property can be specified either by its Outlook Object Model or MAPI (DASL) name, but the returned data may be different - for the date time properties, if property is specified using the OOM name, the value will be converted from the UTC time zone (used by default by MAPI for most of the date time properties) to the local time zone. If the DASL name is used, no conversion will be performed; the value will be returned as is. Binary properties (such as PR_ENTRYID) will always be returned as a string with a hex representation of the data. Note that this this different from using Fields() or MAPIUtils.HrGetOneProp, which return binary properties as a variant array.
Note that attachments and recipients properties cannot be returned, but one can still create restrictions on these sub-properties. For attachments, Redemption will create a PR_MESSAGE_ATTACHMENTS restriction on 4 OR'ed attachment properties: PR_DISPLAY_NAME, PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME, PR_ATTACH_EXTENSION. For recipients, it will use PR_MESSAGE_RECIPIENTS restriction on 2 OR'ed recipient properties: PR_DISPLAY_NAME and PR_EMAIL_ADDRESS:
set Table =
CreateObject("Redemption.MAPITable") |
For the named MAPI properties, either in the OOM or DASL format, Redemption needs to convert the names to the regular 4 byte MAPI properties using GetIDsFromNames. Since IMAPITable MAPI interface does not expose that method, Redemption tries to access the Parent property of the object assigned to the MAPITable.Item property (assuming it will return MAPIFolder OOM object) and checks to see if the MAPIOBJECT property is exposed. This works in Outlook 2002 or higher. In Outlook 2000 or below, MAPIFolder object in OOM does expose the MAPIOBECT property, therefore Redemption will not be able to perform the conversion and will return an error. This lmitation does not apply to the CDO 1.21 or RDO folders since they always exposed the MAPIOBJECT property.
Examples of accessing MAPI Tables using MAPITable object
Below are two examples that retrieve the subject of each e-mail is a folder. First one is using GetRow, second example uses GetRows() (more efficient as all rows are retrieved in a single pass). They both assume that MAPIFolder variable is initialized to an instance of Outlook's MAPIFolder object. Note that depending on the MAPI provider, GetRows() might returns an error if you request too many rows. It would be a good idea to retrieve rows in chunks of a 100 or so. If you want to open the messages later, also request PR_ENTRYID property so that you'd be able to call either Namespace.GetItemFromID() or MAPIUtils.GetItemFromID(). To convert the entry id to a string (since Redemption returns binary properties as arrays), use MAPIUtils.HrArrayToString()
The third examples illustrates how to retrieve a named property (corresponding to Contact.FileUnder property in OOM in this particular case). Redemption resorts to creating an instance of SafeContactItem to be able to call SafeContactItem.GetIDsFromNames() to find the property tag for the named property.
1. Print the subject of all messages in a folder using MAPITable.GetRow
dim Columns(0) |
2. Print the subject of all messages in a folder using MAPITable.GetRows - more efficient as all rows are retrieved in a single call.
Important Note: Exchange Server provider limits the amount of data that can be retrieved in a single call to around 32 kB, be prepared that the number of rows returned will be less than the requested number. Handle such situations by either retrieving one row at a time using GetRow (see above) or retrieving rows in chunks of 20 or 30 (depends on the amount of data returned).
dim Columns(0) |
3. Print the FileUnder property of all contacts and distribution lists in a folder using MAPITable.GetRows. Since we are dealing with a named property, we need to create an instance of SafeContactItem and call SafeContactItem.GetIDsFromNames to figure out the property tag for the FileUnder property
dim Columns(0) |
Restricting and searching MAPITable contents
Even though you can use MAPITable with a filtered OOM Items collection (such as returned from Items.Restrict), Redemption also implements an independent mechanism of filtering the contents of the MAPI tables if you are using the MAPITable with CDO or if you want to have greater control over restrictions.
It must be noted that using restrictions in Redemption is more work than in OOM, but gives you the same power and flexibility as if you were writing native Extended MAPI code.
Table filtering and searching in Redemption is implemented by the TableFilter object.
TableFilter object is accessible through the MAPITable.Filter object property. Just like OOM, filtering and searching using Redemption is implemented in two closely related pieces. First you need to create a restriction using the TableFilter.SetKind property (more on this below), then you can either restrict the entire collection using MAPITable.Restrict (corresponds to Items.Restrict in OOM) or search for the objects in the table satisfying the specified restriction using MAPITable.FindFirst/FindLast/FindNext methods (correspond to Items.FindFirst and Items.FindNext in OOM).
Note the difference between using Restrict and FindFirst/FindLast/FindNext methods - use Restrict if you know in advance that you will need all of the restricted objects (e.g. all unread messages in a folder); use FindFirst/FindLast/FindNext if you only need one record satisfying the restriction (e.g. you are implementing the type-ahead functionality a-la Outlook address book). Using Restrict is more expensive than FindFirst/FindLast/FindNext as the underlying MAPI implementation needs to search through the whole table as opposed to finding the first/last/Nth occurance.
Very important note: Exchange provider caches all folder contents table restrictions (approx. 1 week by default) and updates the restriction results every time there is a change in the contents table. While this can be very good news if your restriction if constant (e.g. [Unread] = true), it can literally bring your Exchange server down to its knees if you create too many restrictions that you use only once or twice. In this case instead of Restrict use FindFirst/FindLast/FindNext - the results are not cached.
There are essentially two kinds of restrictions in Extended MAPI: one is a restriction consisting of a single element (e.g. Subject property starts with "test") and second is a restriction consisting of one or more sub-elements (e.g. (Delivered >= #05/01/2003#) AND (Delivered < #06/01/2003#)). Restrictions that contain two or more child restrictions are RestrictionAnd and RestrictionOr. RestrictionNot can contain only one subrestriction. Note that a child subrestriction can also contain subrestrictions.
To create a new restriction using Redemption, call TableFilter.SetKind() passing an appropriate enumeration constant (see below). The method returns the specified restriction object which you can use to set the restriction properties. You can also access the restriction using the TableFilter.Restriction property. The new restriction replaces any previous restrictions.
Restriction Kind |
Numeric value |
Corresponding restriction object |
|
||
RES_AND |
0 |
|
RES_BITMASK |
6 |
|
RES_COMPAREPROPS |
5 |
|
RES_CONTENT |
3 |
|
RES_EXIST |
8 |
|
RES_NOT |
2 |
|
RES_OR |
1 |
|
RES_PROPERTY |
4 |
|
RES_SIZE |
7 |
|
RES_SUBRESTRICTION |
9 |
After the restriction is set, you can call either TableFilter.Restrict or TableFilter.FindFirst/FindLast/FindNext. To clear the restriction, call TableFilter.Clear. Note that calling Clear does not apply the NULL restriction (if you restricted the table using Restrict) - you will need to call Restrict again.
When in doubt how to properly construct a restriction that you need, let Outlook do the job: click "Tools | Advanced Find" in Outlook, create the restriction you need, click Find. Without closing the Advanced Find window (otherwise Outlook will delete the corresponding search folder), click IMsgStore button in OutlookSpy, click Open Root Container, go to the GetHierarchyTable tab, double click the Finder folder, in the new IMAPIFolder window go to the GetHierarchyTable tab, open the last folder. This is the search folder Outlook has just created for your search. Go to the GetSearchCriteria tab - that's the restriction tree you need to replicate in your code.
Example of using the RES_BITMASK (RestrictionBitmask). This kind of restriction ANDs the value of the specified property (ulPropTag) with the specified mask (ulMask) and checks whether the result is 0 (relBMR = BMR_EQZ) or 1 (relBMR =
BMR_NEZ) Print the subject of all unread messages in a folder. Return the messages with
(PR_MESSAGE_FLAGS And MSGFLAG_READ) = 0 It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object.
'remove these lines if Redemption
(SafeOutlook) type library
|
Example of the
RES_COMPAREPROPS (RestrictionCompareProps). This kind of restriction compares the values of two specified properties (ulPropTag1 ans ulPropTag2) using the specified operator (Relop -
RELOP_GE, RELOP_GT, RELOP_LE, RELOP_LT, RELOP_NE, RELOP_RE, RELOP_EQ)
Print the PR_SENDER_NAME and PR_SENT_REPRESENTING_NAME properties for all messages in the folder where these properties do not
match (this corresponds to the messages sent of behalf of somebody else, e.g. a
secretary sending on behalf of her boss). It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object.
'remove these lines if Redemption
(SafeOutlook) type library |
Example of the
RES_CONTENT (RestrictionContent). This restriction matches the specified property (ulPropTag) with the search string
(lpProp). using the logic defined by ulFuzzyLevel (FL_FULLSTRING, FL_PREFIX,
FL_SUBSTRING). These 3 constants can be "or"ed with the following modifiers:
FL_IGNORECASE, FL_IGNORENONSPACE, FL_LOOSE. Note that this restriction can only be used with the string properties.
Print the subject of all messages in the folder with the subject containing "redemption". It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object.
'remove these lines if Redemption
(SafeOutlook) type library |
Example of the RES_EXIST (RestrictionExist). This restriction checks if the specified property exists on e message Print the subject of all messages in the folder that have PR_TRANSPORT_MESSAGE_HEADERS property. This property is usually only present on the messages received from the internet. Messages received from Exchange users in the same domain usually do not have this property. It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object.
'remove this line if Redemption (SafeOutlook) type library |
Example of the RES_PROPERTY (RestrictionProperty). This restriction compares the property specified by ulPropTag with the given value (lpProp) using the operator defined by relop (RELOP_GE, RELOP_GT, RELOP_LE, RELOP_LT, RELOP_NE, RELOP_RE, RELOP_EQ). Print the subject of all messages in the folder with an attachment - check if PR_HASATTACH is true It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object.
'remove this line if Redemption
(SafeOutlook) type library |
Example of the RES_SIZE (RestrictionSize). This restriction compares the size of the given property (ulPropTag) with the value specified by cb using the operator given by relop (RELOP_GE, RELOP_GT, RELOP_LE, RELOP_LT, RELOP_NE, RELOP_RE, RELOP_EQ). Print the subject of all messages in the folder with the PR_BODY size in excess of 50 kB. It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object.
'remove this line if Redemption
(SafeOutlook) type library |
Example of the RES_SUBRESTRICTION (RestrictionSub). This restriction allows to set a restriction on one of the message's subobjects, such as a recipient or an attachment
(ulSubObject can only be PR_MESSAGE_ATTACHMENTS or PR_MESSAGE_RECIPIENTS).
Print the subject of all messages in the folder where an attachment has a ".txt" substring in its name. One can search on the PR_ATTACH_EXTENSION property being ".txt"
(FL_FULLSTRING + FL_IGNORECASE), however PR_ATTACH_EXTENSION is not always present, so let's search on ".txt" substring (FL_SUBSTRING +
FL_IGNORECASE) in PR_ATTACH_FILENAME. It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object
'remove these lines if Redemption
(SafeOutlook) type library |
Example of the
RES_NOT (RestrictionNot). This restriction negates the restriction set as it subrestriction. Similar to the RES_EXIST sample, the
sampe above
Prints the subject of all messages in the folder that do *not* have the PR_TRANSPORT_MESSAGE_HEADERS property. This property is usually only present on the messages received from the internet. Messages received from Exchange users in the same domain usually do not have this property.
It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object
'remove this line if Redemption
(SafeOutlook) type library |
Example of the
RES_AND (RestrictionAnd). This restriction applies the AND logical operator to its child restrictions
RES_OR (RestrictionOr) is completely analogous, it just uses the OR operator.
The example prints the subject of all messages satisfying the condition (PR_MESSAGE_DELIVERY_TIME >= Feb. 01, 2003) AND
(PR_MESSAGE_DELIVERY_TIME < Mar. 01, 2003). It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object.
'remove this line if Redemption (SafeOutlook) type library |
Restricting address book container entries
Restrict the "Contacts" address book container for the entries that have a
"dmitry" prefix. This is the only kind of restriction supported by most address book providers unfortunately :-(
This restriction is used when resolving a name manually typed by a user, so the
AB providers don't bother implementing any other restrictions, the only
exception being Exchange GAL.
'remove these lines if Redemption
(SafeOutlook) type library |
Using TableFilter.FindFirst/FindNext/FindLast methods
Example of calling FindFirst/FindNext/FindLast using a specified restriction.
Display the subject of all unread messages in a folder in a loop until there aren't any left.
It is assumed that MAPIFolder variable points to an OOM's MAPIFolder object
'remove these lines if Redemption (SafeOutlook) type library |
Sort capabilities in Redemption are similar to those in Outlook Object Model, with one exception: you can sort on multiple properties at the same time.
To sort the items in the Redemption.MAPITable object, call MAPITable.Sort passing either an integer property tag or a variant array of integer property tags. You can also pass a comma separated string of the OOM or DASL property names (e.g. "Subject, SenderName") - see the example #3 below.
The second (Descending, optional) parameter is either a boolean specifying the sort order (true for descending or false for ascending) or a variant array of boolean values specifying the sort order for each of the property tags passed in the first argument.
Two examples are given below. One sorts the table by a single property PR_MESSAGE_DELIVERY_TIME,
the second example sorts the table first by PR_SUBJECT, then by PR_MESSAGE_DELIVERY_TIME.
1. Sort the table on one property - PR_MESSAGE_DELIVERY_TIME
'Print the subject of all messages in a folder |
2. Sort the table on 2 properties - first on PR_SUBJECT, then on PR_MESSAGE_DELIVERY_TIME
dim Columns(0) |
3. Sort the table specifying the columns as a comma separated string
set Session =
CreateObject("Redemption.RDOSession") |