Search code examples
c#cominteropmapioutlook-redemption

Using RDO/MAPI to extract large public folder stores and getting E_MAPI_TOO_BIG


I am attempting to export the contents of my company's fairly large public folder layout (000s of folders) from Exchange Server 2010 using RDO 5.14.

I am hitting the issue that a lot of people find, in that at some point Exchange 2010 gives the error E_MAPI_TOO_BIG because the user I am using has breached the exchange store limits documented here.

The accepted solution in many cases is to call while (Marshal.ReleaseComObject(ref)>0) on every ref and GC.Collect() once in a while which does appear to allow the processing of more items but still doesn't allow me to get more than 500 messages in.

Some playing around with the code. It reveals the following surprising (at least to me) fact.

If I iterate over the items in a folder like this there is no problem:

for (int i = 1; i < items.Count; ++i) {
    IRDOMail item = items.Item(i);
    string SUCCESS = item.EntryID;
}

BUT, if I use this code sample at some point it fails (elsewhere in the code trying to access other folders) with E_MAPI_TOO_BIG:

for (int i = 1; i < items.Count; ++i) {
    IRDOMail item = items.Item(i);
    string FAIL = item.Subject;
}

At this point I've reached the very limit of my COM skills. It suggests to me that some part of de-referencing a COM property of a MailItem in .NET InterOp ends up grabbing a reference that I can't release. If that's the case I'm not sure how I can fix it, if at all?

Similar (but different) behaviour can be seen if I use MAPI without RDO, further suggesting that it is a quirk of MAPI (14.0)?


Solution

  • This turned out to be an issue with program structure and not a direct issue with either RDO or MAPI. Specifically the issue is trying to process the entire tree and items recursively.

    It would seem as if accessing any property of a MAPI/RDO MailItem from the folder creates an internal reference from the folder back to the item. Although I'm not sure that this is true nor how to verify it.

    Therefore if one sub-branch (not just one folder) of the structure contains more than 500 messages you’d get E_MAPI_TOO_BIG trying to 'visit' the structure in the way described.

    The solution then is to use recursion to build a list of folder EntryId's and then iterate over that list using GetFolderFromId() to get the folder and then iterate over the items. None of the MAPI/RDO programming resources that I've found thus far mentions this fact.

    UPDATE

    After spending more time trying to get MAPI working in managed code I've reached the conclusion that it's a fundamentally a bad idea to try and do what I was attempting. Whilst the solution above got me a bit further, it ultimately failed again (with the same error) when I tried to access more properties of the message.

    In hindsight the issue seems to be that it very NEARLY works and a lot of people have managed to get by on that, hence there's quite a lot of resources on-line demonstrating this. But since doing MAPI in managed code is not supported by Microsoft, it would seem that we're on shaky ground to start with. Even if this is COM Interop rather than direct MAPI.

    Doing anything at scale with Exchange requires using one of the other Exchange technologies in my opinion. I ended up using EWS which seems complete and more importantly, reliable. I hope this helps someone!