SUMMARY
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:
- Launching the mail program from the control panel.
- Selecting a profile that has the Microsoft Exchange Server service installed.
- Pulling up the Properties for Microsoft Exchange Server.
- Selecting the Advanced tab.
- Adding an additional mailbox to open.
The sample code below illustrates the steps needed to add an additional mailbox to an existing MAPI profile.
back to the top
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 the Microsoft fee-based
consulting line at (800) 936-5200. For more information about Microsoft Certified
Partners, please visit the following Microsoft Web site:
For more information about the support options that are available and about how to contact Microsoft, visit the following Microsoft Web site:
//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>
/*******************************************************************************
AddMailbox
This function will add an additional Exchange mailbox to an existing MAPI
profile. It assumes that you have already initialized MAPI.
Parameters:
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"
Output:
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,
PR_DISPLAY_NAME,
PR_SERVICE_NAME,
PR_SERVICE_UID };
// 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,
(LPSPropTagArray)&sptCols,
&sres,
NULL,
0,
&lpSvcRows);
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,
0,
&lpProvAdmin);
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",
4,
rgval,
0,
0,
(LPMAPIUID)lpSvcRows->aRow->lpProps[iSvcUID].Value.bin.lpb);
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,
NULL,
MAPI_MODIFY,
&lpProfileSection);
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,
0,
&ulProps,
&lpGlobalVals);
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.
memcpy(NewVals.Value.bin.lpb,
lpGlobalVals->Value.bin.lpb,
lpGlobalVals->Value.bin.cb);
// Next, copy the new UID onto the end of the list.
memcpy(NewVals.Value.bin.lpb + lpGlobalVals->Value.bin.cb,
lpSvcRows->aRow->lpProps[iSvcUID].Value.bin.lpb,
lpSvcRows->aRow->lpProps[iSvcUID].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.
NewVals.ulPropTag = PR_STORE_PROVIDERS;
// Set the property on the global profile section.
hRes = lpProfileSection->SetProps(ulProps,
&NewVals,
NULL);
if (FAILED(hRes)) goto error_handler;
printf("Set the new list on the global profile section.\n");
goto cleanup;
error_handler:
printf("ERROR: hRes = %0x\n", hRes);
cleanup:
// 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)
{
HRESULT hRes = S_OK;
MAPIInitialize(NULL);
hRes = AddMailbox(
"My Profile",
"Mr Mailbox",
"/o=MyOrganization/ou=My-Site/cn=Recipients/cn=MMailbox",
"MyServer",
"/o=MyOrganization/ou=My-Site/cn=Configuration/cn=MyServer");
MAPIUninitialize();
}
back to the top