We had a request for such an application from one of our customers so I though I would share the code with the community.

The application creates a new Inbox rule in the default message store. The rule will be triggered for all the incoming messages that have a specific message class (defined in the code) and will set the sensitivity of these messages to Private, making them visible only to the owner of the mailbox.

The source code below and the project in attachment:

/*MAPICreateRule.cpp : Defines the entry point for the console application.

This file contains code that demonstrates how to create an inbox rule that sets the
message sensitivity to private using Extended MAPI.

The relevant function is CreateRule, which creates the rule.

To build this code, you need to add the following files to your link settings:
- mapi32.lib

This code is provided as a sample only. Microsoft offers no warranty or
support for it. Use at your own risk.

*********************************************************************************/

#include "stdafx.h"
#include "InitGuid.h"
#include "Mapix.h"
#include "mapiutil.h"
#include "EdkMdb.h"
#include "EdkGuid.h"

#define MDB_ONLINE ((ULONG) 0x00000100)

// Macro to get the number of bytes needed for MAPIAllocateBuffer for a ROWLIST.
#define CbNewROWLIST(_centries) (offsetof(ROWLIST,aEntries) + (_centries)*sizeof(ROWENTRY))

// Forward function declarations.
HRESULT CreateRule(LPMAPIFOLDER lpFolder);

// main
int MainProcessing()
{
HRESULT hRes = S_OK; // MAPI return code.
LPMAPISESSION lpSession = NULL; // Session pointer.
LPMDB lpMDB = NULL; // Information store pointer.
LPMAPIFOLDER lpInbox = NULL; // Folder pointer.
LPENTRYID lpStoreEID = NULL; // Pointer to entry ID of message store.
ULONG cbStoreEID = 0; // Count of bytes in message store entry ID.
LPENTRYID lpInboxEID = NULL; // Pointer to entry ID of Inbox.
ULONG cbInboxEID = 0; // Count of bytes in Inbox entry ID.
ULONG ulObjType = 0; // Object Type indicator.
SRestriction sres; // Restriction for looking up the default store
SPropValue spv; // Restriction property for looking up the default store
LPMAPITABLE pStoresTbl = NULL; // holds the list of store entries
LPSRowSet pRow = NULL; // row to process one store at a time

enum {EID, NAME, NUM_COLS};
static SizedSPropTagArray(NUM_COLS,sptCols) = {NUM_COLS, PR_ENTRYID, PR_DISPLAY_NAME};

// Initialize MAPI.
if (FAILED(hRes = MAPIInitialize(NULL)))
{
printf("MAPIInitialize failed in main.\n");
goto error;
}

// Log on.
printf("Choose the profile that you want to create a new OOF rule in.\n");

if (FAILED(hRes = MAPILogonEx(NULL,
NULL, // or specify the profile name here as an LPWSTR/LPTSTR
NULL,
MAPI_LOGON_UI |
MAPI_NEW_SESSION |
MAPI_NO_MAIL,
&lpSession)))
{
printf("MAPILogonEx failed in main.\n");
goto error;
}

LPMAPITABLE ptable = NULL;
lpSession->GetMsgStoresTable(0, &ptable);

//Set up restriction for the default store
sres.rt = RES_PROPERTY; //Comparing a property
sres.res.resProperty.relop = RELOP_EQ; //Testing equality
sres.res.resProperty.ulPropTag = PR_DEFAULT_STORE; //Tag to compare
sres.res.resProperty.lpProp = &spv; //Prop tag and value to compare against

spv.ulPropTag = PR_DEFAULT_STORE; //Tag type
spv.Value.b = TRUE; //Tag value

//Convert the table to an array which can be stepped through
//Only one message store should have PR_DEFAULT_STORE set to true, so only one will be returned
hRes = HrQueryAllRows( ptable, //Table to query
(LPSPropTagArray) &sptCols, //Which columns to get
&sres, //Restriction to use
NULL, //No sort order
0, //Max number of rows (0 means no limit)
&pRow); //Array to return
if (FAILED(hRes))
{
printf("Rows could not be retrieved.\n");
printf("ERROR hRes = %0x\n", hRes);
goto cleanup;
}
else
{
printf("Rows retrieved.\n");
}

//Open the first returned (default) message store
hRes = lpSession->OpenMsgStore( NULL,//Window handle for dialogs
pRow->aRow[0].lpProps[EID].Value.bin.cb,//size and...
(LPENTRYID)pRow->aRow[0].lpProps[EID].Value.bin.lpb,//value of entry to open
NULL,//Use default interface (IMsgStore) to open store
MDB_WRITE | MDB_ONLINE,//Flags
&lpMDB);//Pointer to place the store in

if (FAILED(hRes))
{
printf("Message Store Not Opened.\n");
printf("ERROR hRes = %0x\n", hRes);
goto cleanup;
}
else
{
printf("Message Store Opened.\n");
}

// Get the Inbox.
if (FAILED(hRes = lpMDB->GetReceiveFolder(NULL,
NULL,
&cbInboxEID,
&lpInboxEID,
NULL)))
{
printf("GetReceiveFolder failed in main.\n");
goto error;
}

// Open the Inbox.
if (FAILED(hRes = lpMDB->OpenEntry(cbInboxEID,
lpInboxEID,
NULL,
MAPI_BEST_ACCESS,
&ulObjType,
(LPUNKNOWN *)&lpInbox)))
{
printf("OpenEntry failed in main.\n");
goto error;
}

// Create the rule.
if (FAILED(hRes = CreateRule(lpInbox)))
{
printf("CreateRule failed in main.\n");
goto error;
}


// Log off.
if (FAILED(hRes = lpSession->Logoff(0,0,0)))
{
printf("Logoff failed in main.\n");
goto error;
}
else
printf("Logoff succesful.\n");

goto cleanup;

// Report error number.
error:
printf("ERROR: hRes = 0%x\n", hRes);

// Clean up memory and uninitialize MAPI.
cleanup:
if (pStoresTbl) pStoresTbl->Release();
if (lpInbox) lpInbox->Release();
if (lpMDB) lpMDB->Release();
if (lpSession) lpSession->Release();

MAPIUninitialize();

return 0;
}

// CreateRule.
HRESULT CreateRule(LPMAPIFOLDER lpFolder)
{
HRESULT hRes = S_OK; // MAPI return code.
LPMESSAGE lpOOFMsg = NULL; // OOF Message pointer.
LPEXCHANGEMODIFYTABLE lpExchModTable = NULL; // Rule Table pointer.
ACTION *lpAction = NULL; // ACTION pointer.
ACTIONS *lpActions = NULL; // ACTIONS pointer.
SPropValue RuleProps[7]; // Properties to set on OOF rule.
LPSPropValue lpOOFEID = NULL; // PR_ENTRYID for the OOF message.
ULONG ulCount = 0; // Count of props returned by GetProps.
LPROWLIST lpRowList = NULL; // Row List pointer.
LPWSTR messageClass = L"IPM.Note"; // The message class to setup the rule for.
LPWSTR ruleName = L"IPM.Note Sensitivity"; // The name of the new rule.
SPropTagArray taga = {1, {PR_ENTRYID}}; // Props to return from GetProps.
SRestriction sres;
SPropValue SvcProps;

// Set up restriction to filter only specific message classes.
sres.rt = RES_CONTENT;
sres.res.resContent.ulFuzzyLevel = FL_IGNORECASE | FL_SUBSTRING;
sres.res.resContent.ulPropTag = PR_MESSAGE_CLASS;
sres.res.resContent.lpProp = &SvcProps;

SvcProps.ulPropTag = PR_MESSAGE_CLASS;
SvcProps.Value.lpszW = messageClass;

// Open the rules table with an IExchangeModifyTable interface.
if (FAILED(hRes = lpFolder->OpenProperty(PR_RULES_TABLE,
(LPGUID)&IID_IExchangeModifyTable,
0,
MAPI_DEFERRED_ERRORS,
(LPUNKNOWN *)&lpExchModTable)))
{
printf("OpenProperty failed in CreateRule.\n");
goto error;
}
else
printf("Rule Collection Succesfully Open.\n");

// Allocate space for an ACTION structure.
if (FAILED(hRes = MAPIAllocateBuffer(sizeof(ACTION), (LPVOID *) &lpAction)))
{
printf("MAPIAllocateBuffer for ACTION failed in CreateOOF.\n");
goto error;
}

// Allocate space for an ACTIONS structure.
if (FAILED(hRes = MAPIAllocateBuffer(sizeof(ACTIONS), (LPVOID *) &lpActions)))
{
printf("MAPIAllocateBuffer for ACTIONS failed in CreateOOF.\n");
goto error;
}

// Clear the memory.
memset(lpAction, 0, sizeof(ACTION));
memset(lpActions, 0, sizeof(ACTIONS));

// Set up the ACTIONS structure.

// Set the rule version
lpActions->ulVersion = EDK_RULES_VERSION;
// Set the number of actions
lpActions->cActions = 1;
// Set the pointer to the action
lpActions->lpAction = lpAction;

// Set up the ACTION structure.

// Set up the type of action.
lpAction->acttype = OP_TAG;
lpAction->propTag.ulPropTag = PR_SENSITIVITY;
lpAction->propTag.Value.l = SENSITIVITY_PRIVATE;

// Set up the rule properties.

// Set rule sequence to 0.
RuleProps[0].ulPropTag = PR_RULE_SEQUENCE;
RuleProps[0].Value.ul = 0;

// Set the rule provider.
RuleProps[1].ulPropTag = PR_RULE_PROVIDER;
RuleProps[1].Value.lpszA = "MSFT:TDX OOF Rules";

// Set the rule state
RuleProps[2].ulPropTag = PR_RULE_STATE;
RuleProps[2].Value.ul = ST_ENABLED;

// Set the user flags to 2.
RuleProps[3].ulPropTag = PR_RULE_USER_FLAGS;
RuleProps[3].Value.ul = 0;

// Set the condition to NULL (fires on all messages).
RuleProps[4].ulPropTag = PR_RULE_CONDITION;
RuleProps[4].Value.ul = (ULONG) &sres;

// Set the actions for the rule to our ACTIONS structure.
RuleProps[5].ulPropTag = PR_RULE_ACTIONS;
RuleProps[5].Value.ul = (ULONG) lpActions;

// Set the actions for the rule to our ACTIONS structure.
RuleProps[6].ulPropTag = PR_RULE_NAME;
RuleProps[6].Value.lpszW = ruleName;

// Allocate space for the rowlist for ModifyTable.
if (FAILED(hRes = MAPIAllocateBuffer(CbNewROWLIST(1), (LPVOID *)&lpRowList)))
{
printf("MAPIAllocateBuffer for ROWLIST failed in CreateOOF.\n");
goto error;
}

// Set up the row list.

// Number of entries.
lpRowList->cEntries = 1;
// Type of operation.
lpRowList->aEntries->ulRowFlags = ROW_ADD;
// Number of properties being set.
lpRowList->aEntries->cValues = 7;
// Pointer to properties.
lpRowList->aEntries->rgPropVals = RuleProps;

// Call ModifyTable on rule table to add our OOF rule.
if (FAILED(hRes = lpExchModTable->ModifyTable(0, lpRowList)))
{
printf("ModifyTable failed in CreateRule.\n");
goto error;
}
else
printf("Rule Succesfully Created.\n");

goto cleanup;

// Report error.
error:
printf("ERROR: hRes = 0%x\n", hRes);

// Clean up memory.
cleanup:

if (lpRowList) MAPIFreeBuffer(lpRowList);
if (lpAction) MAPIFreeBuffer(lpAction);
if (lpActions) MAPIFreeBuffer(lpActions);
if (lpExchModTable) lpExchModTable->Release();
return hRes;

}

int _tmain(int argc, _TCHAR* argv[])
{

MainProcessing();

return 0;
}