How to add more Exchange mailboxes to a MAPI profile



This step-by-step article details the process of adding a mailbox to a MAPI profile. This will allow you to open this additional mailbox with delegate access. The owner of this mailbox must grant you delegate access prior to following this process.

This process is the programmatic equivalent to:
  1. Launching the mail program from the control panel.
  2. Selecting a profile that has the Microsoft Exchange Server service installed.
  3. Pulling up the Properties for Microsoft Exchange Server.
  4. Selecting the Advanced tab.
  5. Adding an additional mailbox to open.
The sample code below illustrates the steps needed to add an additional mailbox to an existing MAPI profile.

Sample Code

Microsoft provides programming examples for illustration only, without warranty either expressed or implied, including, but not limited to, the implied warranties of merchantability and/or fitness for a particular purpose. This article assumes that you are familiar with the programming language being demonstrated and the tools used to create and debug procedures. Microsoft support professionals can help explain the functionality of a particular procedure, but they will not modify these examples to provide added functionality or construct procedures to meet your specific needs.
If you have limited programming experience, you may want to contact a Microsoft Certified Partner or Microsoft Advisory Services. For more information, visit these Microsoft Web sites:

Microsoft Certified Partners -

Microsoft Advisory Services -

For more information about the support options that are available and about how to contact Microsoft, visit the following Microsoft Web site:;EN-US;CNTACTMS
//The following headers may be required if not already in the project:
#include <stdio.h>
#include <mapix.h>
#include <MAPITAGS.H>
#include <MAPIUTIL.H>
#include <edkmdb.h>



This function will add an additional Exchange mailbox to an existing MAPI
profile. It assumes that you have already initialized MAPI.

lpszProfile The name of the profile you are going to modify.
lpszMailboxDisplay The string that will be displayed in the profile UI.
Outlook uses the format "Mailbox - John Doe"
lpszMailboxDN The distinguished name of the mailbox to add.
Ex. "/o=Microsoft/ou=Test/cn=Recipients/cn=JohnD"
lpszServer The DNS name of the server where the additional
mailbox resides.
lpszServerDN The distinguished name of the server where the
additional mailbox resides.
Ex. "/o=Microsoft/ou=Test/cn=Configuration/cn=TestSrv"

HRESULT hRes Returns S_OK if completed successfully, otherwise
returns a MAPI error.

HRESULT AddMailbox(LPSTR lpszProfile,
LPSTR lpszMailboxDisplay,
LPSTR lpszMailboxDN,
LPSTR lpszServer,
LPSTR lpszServerDN)
HRESULT hRes = S_OK; // Result code returned from MAPI calls.
LPPROFADMIN lpProfAdmin = NULL; // Profile Admin pointer.
LPSERVICEADMIN lpSvcAdmin = NULL; // Message Service Admin pointer.
LPPROVIDERADMIN lpProvAdmin = NULL; // Provider Admin pointer.
LPMAPITABLE lpMsgSvcTable = NULL; // MAPI table pointer.
LPPROFSECT lpProfileSection = NULL;// Profile Section Pointer.
LPSRowSet lpSvcRows = NULL; // Row set pointer.
SPropValue rgval[4]; // Property value structure to hold configuration info.
SPropValue NewVals; // Property value structure to hold global profile info.
SRestriction sres; // Restriction structure (used in HrQueryAllRows).
SPropValue SvcProps; // Property value structure used in restriction.
LPSPropValue lpGlobalVals = NULL; // Property value struct pointer for global profile section.
ULONG ulProps = 0; // Count of props.
ULONG cbNewBuffer = 0; // Count of bytes for new buffer.

// Enumeration for convenience.
enum {iDispName, iSvcName, iSvcUID, cptaSvc};

// This structure tells HrQueryAllRows what columns we want returned.
SizedSPropTagArray(cptaSvc,sptCols) = { cptaSvc,

// This structure tells our GetProps call what properties to get from the global profile section.
SizedSPropTagArray(1, sptGlobal) = { 1, PR_STORE_PROVIDERS };

// Get an IProfAdmin interface.

hRes = MAPIAdminProfiles(0, // Flags
&lpProfAdmin); // Pointer to new IProfAdmin
if (FAILED(hRes)) goto error_handler;
printf("Retrieved IProfAdmin interface.\n");

// Get an IMsgServiceAdmin interface off of the IProfAdmin interface.

hRes = lpProfAdmin->AdminServices(lpszProfile, // Profile that we want to modify.
"", // Password for that profile.
NULL, // Handle to parent window.
0, // Flags.
&lpSvcAdmin); // Pointer to new IMsgServiceAdmin.
if (FAILED(hRes)) goto error_handler;
printf("Retrieved IMsgServiceAdmin interface.\n");

// We now need to get the entry id for the Exchange service.
// First, we get the Message service table.

hRes = lpSvcAdmin->GetMsgServiceTable(0, // Flags
&lpMsgSvcTable); // Pointer to table
if (FAILED(hRes)) goto error_handler;
printf("Retrieved message service table from profile.\n");

// Set up restriction to query table.

sres.rt = RES_PROPERTY;
sres.res.resProperty.relop = RELOP_EQ;
sres.res.resProperty.ulPropTag = PR_SERVICE_NAME;
sres.res.resProperty.lpProp = &SvcProps;

SvcProps.ulPropTag = PR_SERVICE_NAME;
SvcProps.Value.lpszA = "MSEMS";

// Query the table to get the entry for the Exchange message service.

hRes = HrQueryAllRows(lpMsgSvcTable,
if (FAILED(hRes)) goto error_handler;
printf("Queried table for Exchange message service.\n");

// Get a provider admin pointer.
hRes = lpSvcAdmin->AdminProviders((LPMAPIUID)lpSvcRows->aRow->lpProps[iSvcUID].Value.bin.lpb,
if (FAILED(hRes)) goto error_handler;
printf("Retrieved IProviderAdmin interface\n");

// Set up a SPropValue array for the properties you need to configure.

// First, display name.
ZeroMemory(&rgval[0], sizeof(SPropValue) );
rgval[0].ulPropTag = PR_DISPLAY_NAME;
rgval[0].Value.lpszA = lpszMailboxDisplay;

// Next, the DN of the mailbox.
ZeroMemory(&rgval[1], sizeof(SPropValue) );
rgval[1].ulPropTag = PR_PROFILE_MAILBOX;
rgval[1].Value.lpszA = lpszMailboxDN;

// Next the name of the server the mailbox is on.
ZeroMemory(&rgval[2], sizeof(SPropValue) );
rgval[2].ulPropTag = PR_PROFILE_SERVER;
rgval[2].Value.lpszA = lpszServer;

// Finally, the DN of the server the mailbox is on.
ZeroMemory(&rgval[3], sizeof(SPropValue) );
rgval[3].ulPropTag = PR_PROFILE_SERVER_DN;
rgval[3].Value.lpszA = lpszServerDN;

// Create the message service with the above properties.
hRes = lpProvAdmin->CreateProvider("EMSDelegate",
if (FAILED(hRes)) goto error_handler;
printf("The new mailbox is added.\n");

// Now let's set the props we need so that the additional mailbox
// will display in the UI.

// Open the global profile section.
hRes = lpProvAdmin->OpenProfileSection((LPMAPIUID)pbGlobalProfileSectionGuid,
if (FAILED(hRes)) goto error_handler;
printf("Opened global profile section.\n");

// Get the list of store providers in PR_STORE_PROVIDERS.
hRes = lpProfileSection->GetProps((LPSPropTagArray)&sptGlobal,
if (FAILED(hRes)) goto error_handler;
printf("Got the list of mailboxes being opened.\n");

// Now we set up an SPropValue structure with the original
// list + the UID of the new service.

// Compute the new byte count
cbNewBuffer = lpSvcRows->aRow->lpProps[iSvcUID].Value.bin.cb + lpGlobalVals->Value.bin.cb;

// Allocate space for the new list of UIDs.
hRes = MAPIAllocateBuffer( cbNewBuffer,
(LPVOID *)&NewVals.Value.bin.lpb);
if (FAILED(hRes)) goto error_handler;
printf("Allocated buffer to hold new list of mailboxes to be opened.\n");

// Copy the bits into the list.
// First, copy the existing list.

// Next, copy the new UID onto the end of the list.
memcpy(NewVals.Value.bin.lpb + lpGlobalVals->Value.bin.cb,
printf("Concatenated list of mailboxes and new mailbox.\n");

// Set the count of bytes on the SPropValue variable.
NewVals.Value.bin.cb = cbNewBuffer;
// Initialize dwAlignPad.
NewVals.dwAlignPad = 0;
// Set the prop tag.

// Set the property on the global profile section.
hRes = lpProfileSection->SetProps(ulProps,
if (FAILED(hRes)) goto error_handler;
printf("Set the new list on the global profile section.\n");

goto cleanup;

printf("ERROR: hRes = %0x\n", hRes);

// Clean up.
if (NewVals.Value.bin.lpb) MAPIFreeBuffer(NewVals.Value.bin.lpb);
if (lpGlobalVals) MAPIFreeBuffer(lpGlobalVals);
if (lpSvcRows) FreeProws(lpSvcRows);
if (lpMsgSvcTable) lpMsgSvcTable->Release();
if (lpSvcAdmin) lpSvcAdmin->Release();
if (lpProfAdmin) lpProfAdmin->Release();
if (lpProvAdmin) lpProvAdmin->Release();
if (lpProfileSection) lpProfileSection->Release();

printf("Done cleaning up.\n");

return hRes;
The following code demonstrates how to call this sample function:
void main(void)

hRes = AddMailbox(
"My Profile",
"Mr Mailbox",

Article ID: 171636 - Last Review: Jul 13, 2009 - Revision: 1