A new MAPI interface is available to let you force connections to go to a specific Exchange Server
[Edit: 1/23/2014 - This new interface did not ship in the December 2013 CU. I was incorrect. I am currently looking into it.]
[Edit: 4/23/2014 - This fix should've released in February]
[Edit: 11/21/2014 - This change was ported to Outlook 2013 in the April 2014 Cumlative Update for Outlook 2013. support.microsoft.com/kb/2878323]
[Edit: 11/17/2016 - This change was ported to Outlook 2016 and should be available in this update https://support.microsoft.com/en-us/kb/3115440 for MSI builds. C2R builds should've had it before that.]
Introduction
When making a connection to an Exchange Server, Outlook's MAPI will use the server configured in the profile for any mailbox access attempt, even if it's a different mailbox on a different server. Additionally, Outlook's MAPI will prefer to use a server that it has connected to in the past over one that it hasn't. Therefore, even if you specify a different mailbox on a different Exchange Server in the call to IExchangeManageStore::CreateStoreEntryID(), Outlook's MAPI will still use the server configured for the profile. This is not normally a problem.
When a MAPI client application attempts to connect to multiple mailboxes using a "hub and spoke" type approach wherein the MAPI application connects to an initial mailbox and then connects to additional mailboxes for some sort of processing, if the mailbox resides on a different server Outlook's MAPI will ignore the specified server in the EntryID and connect to the server configured for the profile (the "home server"). This results in a return code of ecWrongServer (0x478 / 1144) and the MAPI application is redirected to the correct server. Outlook's MAPI recognizes this scenario and redirects to the corrected server. Again , this is not normally a problem.
Enter Exchange 2013 where every mailbox is now given it's own server name. This is called the personalized server name and is a GUID that represents the mailbox's home server. This makes Outlook's MAPI go through the redirect logic for all mailbox connection attempts and causes a small performance hit for each mailbox the MAPI application attempts to connect to. Previously, there was no way to tell Outlook's MAPI to ignore the "home server" and use the server specified in the EntryID. However, as of the December 2013 Cumulative Update for Outlook 2010 there now is.
To do this, a new interface was created to provide the MAPI application a new public API that can produce the Store EntryID needed when calling IMAPISession::OpenMsgStore(). You can use the header defined below and the properties to instruct MAPI to create the Store EntryID that contains a special flag in the EntryID that Outlook's MAPI will know how to parse. When this flag is present, MAPI will prefer the server name contained in the EntryID. When it's not, it will use the conventional logic discussed above.
First, you will need to define the new properties PR_PROFILE_MDB_DN and PR_FORCE_USE_ENTRYID_SERVER
// 0x7CFF001E
#define PR_PROFILE_MDB_DN PROP_TAG(PT_STRING8, 0x7CFF)
// 0x7CFE000B
#define PR_FORCE_USE_ENTRYID_SERVER PROP_TAG(PT_BOOLEAN, 0x7CFE)
Next, you will need to include a new header with the following information
#include <MAPIX.h>
#include <EdkMdb.h>
/*------------------------------------------------------------------------ * *
"IExchangeManageStoreEx" Interface Declaration
* * Used for store management functions.
* *-----------------------------------------------------------------------*/
#define EXCHANGE_IEXCHANGEMANAGESTOREEX_METHODS(IPURE) \
MAPIMETHOD(CreateStoreEntryID2) \
(THIS_ ULONG cValues, \
LPSPropValue lpPropArray, \
ULONG ulFlags, \
ULONG * lpcbEntryID, \
LPENTRYID * lppEntryID) IPURE;
#undef INTERFACE
#define INTERFACE IExchangeManageStoreEx
DECLARE_MAPI_INTERFACE_(IExchangeManageStoreEx, IUnknown)
{
MAPI_IUNKNOWN_METHODS(PURE)
EXCHANGE_IEXCHANGEMANAGESTORE_METHODS(PURE)
EXCHANGE_IEXCHANGEMANAGESTOREEX_METHODS(PURE)
};
#undef IMPL
#define IMPL
DECLARE_MAPI_INTERFACE_PTR(IExchangeManageStoreEx, LPEXCHANGEMANAGESTOREEX);
DEFINE_GUID(IID_IExchangeManageStoreEx, 0x7fe3c629, 0x4d9a, 0x4510, 0xa4, 0x79, 0x56, 0x96, 0x2b, 0x24, 0x6d, 0xc6);
At the call site you will need to pass an array of SPropValues for the following properties
Property: PR_PROFILE_MAILBOX |
Description: The DN of the target mailbox |
Example: /o=Contoso/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=Harris Smithfield9f |
Autodiscover Node: Response/User/LegacyDN |
Property: PR_PROFILE_MDB_DN |
Description: The DN of the target server |
Example: /o=Contoso/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Configuration/cn=Servers/cn=f43abcd7-674b-d43e-8cb5-30b0b2d88c38@contoso.com/cn=Microsoft Private MDB |
Autodiscover Node: Response/Account/Protocol/MdbDN (type EXCH) |
Property: PR_FORCE_USE_ENTRYID_SERVER |
Description: True to indicate that Outlook’s MAPI should use the Server DN from the EntryID instead of the home server. |
Example: N/A |
Here is some example code to show you how it could be used.
LPSPropValue lpspv = nullptr;
MAPIAllocateBuffer((sizeof(SPropValue) * 3), (LPVOID*)&lpspv);
ZeroMemory(lpspv, sizeof(SPropValue) * 3);
lpspv[0].ulPropTag = PR_PROFILE_MAILBOX;
lpspv[0].Value.lpszA = TargetMailboxDN;
lpspv[1].ulPropTag = PR_PROFILE_MDB_DN;
lpspv[1].Value.lpszA = TargetStoreDN;
lpspv[2].ulPropTag = PR_FORCE_USE_ENTRYID_SERVER;
lpspv[2].Value.b = true;
hres = m_pMsgPrivStore->QueryInterface(IID_IExchangeManageStoreEx,
(LPVOID*)&pManageStoreEx);
if (FAILED(hRes) || pManageStoreEx == nullptr)
{
// Handle the error
goto Cleanup;
}
hRes = pManageStoreEx->CreateStoreEntryID2(3,
lpspv,
ulCreateStoreEIDFlags,
&cbEID,
&lpEntryId);
MAPIFreeBuffer(lpsv);
More Information
The “Autodiscover Node” above indicates where in the Autodiscover response for the target mailbox you would find the value for this property.
This EntryID is only supported on the client, specifically Outlook's MAPI.
The EntryID should not be persisted anywhere except in the memory of the application.
If you don’t specify values for all the properties, the returned EntryID will be equal to what you would have received back in a call to IExchangeManageStore::CreateStoreEntryID(),
Comments
Anonymous
January 16, 2014
I tried to implement this, however, even with the Hotfix you mention (support.microsoft.com/.../2849973) installed on Outlook 2010, QueryInterface returns MAPI_E_INTERFACE_NOT_SUPPORTED. I QI IExchangeManageStoreEx on the LPMDB I get from Session->OpenMsgStore of the first mailbox (Ex2013) I open (the one the Outlook profile is configured for), the same LPMDB I use for QI IExchangeManageStore. I have the following DLLs: C:Windowssystem32MAPI32.dll V1.0, Build: 2536, Revision: 0 C:Program Files (x86)Common FilesSYSTEMMSMAPI1033MSMAPI32.DLL V14.0, Build: 6009, Revision: 1000 c:progra~2mi1933~1office14olmapi32.dll V14.0, Build: 7109, Revision: 5000 My customer gets the same error and has the same DLLs except for C:Program Files (x86)Common FilesSYSTEMMSMAPI1033MSMAPI32.DLL V14.0, Build: 6122, Revision: 5000 Do you know if something else needs to be installed for IExchangeManageStoreEx to work?Anonymous
January 22, 2014
Hi Adrian, Thank you for pointing this out. I just tested it and I get the same error. Apparently, this fix was not in the Dec CU. I am still trying to figure out why.Anonymous
April 25, 2014
Hi Dave, I can confirm that this has shipped with the Office Cumulative Update in Feb. 2014 (support.microsoft.com/.../2863918) and it's working. I have found this to be the only way to connect to Exchange 2010 mailboxes when the Outlook profile is configured for an Exchange 2013 mailbox.Anonymous
June 10, 2014
Thanks for the confirmation Adrian.Anonymous
November 17, 2014
HI Dave, Is the CreateStoreEntryID2 implemented in Outlook 2013? Do we still need it in this version?Anonymous
November 20, 2014
Hi Cristian, Yes, you still need this method in Outlook 2013 when trying to prevent the problems listed above. This change was released in the April 2014 Cumulative Update for Outlook 2013. support.microsoft.com/.../2878323Anonymous
September 10, 2015
Hi Dave, We are finding that many new updates when released that break code if it is leveraging IExchangeManageStoreEx interface. The very last which seems to have issue is KB3054881, if we remove this update and go back to KB2878254 then things starts to work. Another HF that seems to have has issue in past was KB2956203. Is it possible to make sure OL hotfixes carries all code that existed in KB2878254 for IExchangeManageStoreEx interface ? Thank you.Anonymous
September 16, 2015
Hi Rajan, All Office updates are cumulative at this point. If you are seeing a problem with the IExchangeManageStoreEx interface then it could be a code defect in the update rather than leaving out prior fixes. My recommendation is to do one or both of the below:
- Confirm that you can reproduce this with MFCMAPI.
- Open a Microsoft support case. If this is a bug in Outlook then the support case will be free.
- Anonymous
September 09, 2016
Will this new interface IExchangeManageStoreEx also supported in Outlook 2016? And when not (that’s my experience), how can I create a storeEntryId V3? At the moment I calculate this Id by adding the “magic” part on an conventional storeEntryId (created with CreateStoreEntryID). But an api call would be nicer…Is storeEntryId V3 the only way to open other users mailbox with Outlook 2016 MAPI?- Anonymous
December 15, 2016
This was added in the July 2016 update for Outlook 2016. https://support.microsoft.com/en-us/kb/3115279
- Anonymous
- Anonymous
June 13, 2017
Thanks for the article.Can you please let me know the value of “ulCreateStoreEIDFlags” to be passed to CreateStoreEntryID2 API. I would like to try with the correct flags.Thanks, Pranay- Anonymous
June 19, 2017
The value is no different than what you would pass to the normal CreateStoreEntryID() method.
- Anonymous