Friday, June 24, 2022

Outlook 2013 MAPI not working but Outlook (Office 365) works fine

I have a 32-bit Windows Forms application that uses PInvoke to call the MAPI methods to generate emails with attachments.  Its been working for years without issue.  

I then got the request to support the 64-bit version of Outlook.  As a 32-bit application can't use MAPI for a 64-bit mail client I ended up creating a simple 64-bit executable that is launched from the 32-bit application.  

All was well, or so I thought, as my application could now send emails using both the 32-bit and 64-bit versions of Outlook Office 365.  As the months went on we started to get complaints from customers that the email feature was broken with Outlook 2013.  Groan!

Behavior

When attempting to call MAPI with Outlook 2013 as the default mail client, the MAPILogon method would fail with return code 3 (MAPI_E_LOGON_FAILURE/MAPI_E_LOGIN_FAILURE).  No logs or explanations that I could find.  After a lot of research and testing I finally found the root cause.

Calling MAPI on a background worker thread

When supporting the 64-bit Outlook, I decided to task off the operation because I'm impatient.

 Task.Run(() =>
            {
                if (!SendMail32(recipient, subject, body, attachments))
                {
                    SendMail64(recipient, subject, body, attachments);
                }
            });

The in process method, SendMail32, calls the MAPI methods directly and failed when Outlook 2013 was the default mail provider.  Removing the Task.Run resolved the issue for the 32-bit version of Outlook.  My theory is that the MAPI calls have to be made on the main UI thread so that the default mail profile can be found/used.  I don't know why this isn't an issue with Office 365.

Single threaded apartment model

Another thing I learned was that if you want to create a console application that can launch the email client with MAPI, you need to use the STAThread attribute, otherwise you get the same logon failure return code.

class Program
    {
        [STAThread]
        static int Main(string[] args)

Conclusion

This was a frustrating issue and I'm not sure why the latest version of Outlook doesn't need these changes but at least its working now.  Thankfully Outlook 2013 goes out of support in 2023 so that will be one less thing to worry about ;)