none
C# NotifyIcon and MapiSendMail returns MAPI_E_FAILURE RRS feed

  • Question

  • Hi,

    We have C# code that uses MAPISendMail (from MAPI32.DLL) to open an instance of the local mail client to send an email.

    It works fine in a x86 platform. But in x64 platform, MapiSendMail returns MAPI_E_FAILURE from NotifyIcon's MouseClick event.

    Sample program:

            public Form1()
            {
                InitializeComponent();
            }
    
            private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
            {
                SendMail(); //doesn't work on x64 platform
            }
    
            private void SendMail()
            {
                MAPI mapi = new MAPI();
                if (mapi.SendMailPopup("test", "testt") > 1)
                    MessageBox.Show("No");
            }
    
            private void btenvoi_Click(object sender, EventArgs e)
            {
                SendMail(); // works
            }
     
        class MAPI
        {
            public bool AddRecipientTo(string email)
            {
                return AddRecipient(email, HowTo.MAPI_TO);
            }
    
            public bool AddRecipientCC(string email)
            {
                return AddRecipient(email, HowTo.MAPI_CC);
            }
    
            public bool AddRecipientBCC(string email)
            {
                return AddRecipient(email, HowTo.MAPI_BCC);
            }
    
            public void AddAttachment(string strAttachmentFileName)
            {
                m_attachments.Add(strAttachmentFileName);
            }
    
            public int SendMailPopup(string strSubject, string strBody)
            {
                return SendMail(strSubject, strBody, MAPI_LOGON_UI | MAPI_DIALOG);
            }
    
            public int SendMailDirect(string strSubject, string strBody)
            {
                return SendMail(strSubject, strBody, MAPI_LOGON_UI);
            }
    
    
            [DllImport("MAPI32.DLL")]
            static extern int MAPISendMail(IntPtr sess, IntPtr hwnd, MapiMessage message, int flg, int rsv);
    
            int SendMail(string strSubject, string strBody, int how)
            {
                MapiMessage msg = new MapiMessage();
                msg.subject = strSubject;
                msg.noteText = strBody;
    
                msg.recips = GetRecipients(out msg.recipCount);
                msg.files = GetAttachments(out msg.fileCount);
    
                m_lastError = MAPISendMail(new IntPtr(0), new IntPtr(0), msg, how, 0);
                
                Cleanup(ref msg);
                return m_lastError;
            }
    
            bool AddRecipient(string email, HowTo howTo)
            {
                MapiRecipDesc recipient = new MapiRecipDesc();
    
                recipient.recipClass = (int)howTo;
                recipient.name = email;
                m_recipients.Add(recipient);
    
                return true;
            }
    
            IntPtr GetRecipients(out int recipCount)
            {
                recipCount = 0;
                if (m_recipients.Count == 0)
                    return IntPtr.Zero;
    
                int size = Marshal.SizeOf(typeof(MapiRecipDesc));
                IntPtr intPtr = Marshal.AllocHGlobal(m_recipients.Count * size);
    
                int ptr = (int)intPtr;
                foreach (MapiRecipDesc mapiDesc in m_recipients)
                {
                    Marshal.StructureToPtr(mapiDesc, (IntPtr)ptr, false);
                    ptr += size;
                }
    
                recipCount = m_recipients.Count;
                return intPtr;
            }
    
            IntPtr GetAttachments(out int fileCount)
            {
                fileCount = 0;
                if (m_attachments == null)
                    return IntPtr.Zero;
    
                if ((m_attachments.Count <= 0) || (m_attachments.Count > maxAttachments))
                    return IntPtr.Zero;
    
                int size = Marshal.SizeOf(typeof(MapiFileDesc));
                IntPtr intPtr = Marshal.AllocHGlobal(m_attachments.Count * size);
    
                MapiFileDesc mapiFileDesc = new MapiFileDesc();
                mapiFileDesc.position = -1;
                int ptr = (int)intPtr;
    
                foreach (string strAttachment in m_attachments)
                {
                    mapiFileDesc.name = Path.GetFileName(strAttachment);
                    mapiFileDesc.path = strAttachment;
                    Marshal.StructureToPtr(mapiFileDesc, (IntPtr)ptr, false);
                    ptr += size;
                }
    
                fileCount = m_attachments.Count;
                return intPtr;
            }
    
            void Cleanup(ref MapiMessage msg)
            {
                int size = Marshal.SizeOf(typeof(MapiRecipDesc));
                int ptr = 0;
    
                if (msg.recips != IntPtr.Zero)
                {
                    ptr = (int)msg.recips;
                    for (int i = 0; i < msg.recipCount; i++)
                    {
                        Marshal.DestroyStructure((IntPtr)ptr, typeof(MapiRecipDesc));
                        ptr += size;
                    }
                    Marshal.FreeHGlobal(msg.recips);
                }
    
                if (msg.files != IntPtr.Zero)
                {
                    size = Marshal.SizeOf(typeof(MapiFileDesc));
    
                    ptr = (int)msg.files;
                    for (int i = 0; i < msg.fileCount; i++)
                    {
                        Marshal.DestroyStructure((IntPtr)ptr, typeof(MapiFileDesc));
                        ptr += size;
                    }
                    Marshal.FreeHGlobal(msg.files);
                }
    
                m_recipients.Clear();
                m_attachments.Clear();
            }
    
            public string GetLastError()
            {
                if (m_lastError <= 26)
                    return errors[m_lastError];
                return "MAPI error [" + m_lastError.ToString() + "]";
            }
    
            readonly string[] errors = new string[] {
    		"OK [0]", "User abort [1]", "General MAPI failure [2]", "MAPI login failure [3]",
    		"Disk full [4]", "Insufficient memory [5]", "Access denied [6]", "-unknown- [7]",
    		"Too many sessions [8]", "Too many files were specified [9]", "Too many recipients were specified [10]", "A specified attachment was not found [11]",
    		"Attachment open failure [12]", "Attachment write failure [13]", "Unknown recipient [14]", "Bad recipient type [15]",
    		"No messages [16]", "Invalid message [17]", "Text too large [18]", "Invalid session [19]",
    		"Type not supported [20]", "A recipient was specified ambiguously [21]", "Message in use [22]", "Network failure [23]",
    		"Invalid edit fields [24]", "Invalid recipients [25]", "Not supported [26]" 
    		};
    
    
            List<MapiRecipDesc> m_recipients = new List<MapiRecipDesc>();
            List<string> m_attachments = new List<string>();
            int m_lastError = 0;
    
            const int MAPI_LOGON_UI = 0x00000001;
            const int MAPI_DIALOG = 0x00000008;
            const int MAPI_DIALOG_MODELESS = 0x00000004;
            const int maxAttachments = 20;
    
            enum HowTo { MAPI_ORIG = 0, MAPI_TO, MAPI_CC, MAPI_BCC };
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public class MapiMessage
        {
            public int reserved;
            public string subject;
            public string noteText;
            public string messageType;
            public string dateReceived;
            public string conversationID;
            public int flags;
            public IntPtr originator;
            public int recipCount;
            public IntPtr recips;
            public int fileCount;
            public IntPtr files;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public class MapiFileDesc
        {
            public int reserved;
            public int flags;
            public int position;
            public string path;
            public string name;
            public IntPtr type;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public class MapiRecipDesc
        {
            public int reserved;
            public int recipClass;
            public string name;
            public string address;
            public int eIDSize;
            public IntPtr entryID;
        }


    If the target platform is "Any CPU", all works. But I can't dut to references (only in x86).

    If i run this sample for x86 platforms in Windows 7 64 bits, the button open a new Window from the local mail client. But if click on the notifyicon, it doesn't work !!!! Why?

    Rgds,

    Mickael.

    Thursday, July 3, 2014 12:52 PM

All replies

  • Hello Mickael,

    Did you try to debug the code? Do you get any exceptions or error messages in the code?

    You may find the Building MAPI Applications on 32-Bit and 64-Bit Platforms article helpful.

    P.S. I have found a similar forum thread which describes a similar issue - MAPI Windows 7 64 bit .
    Thursday, July 3, 2014 12:58 PM
  • Hi Eugene,

    Yes, I tried to debug the code and no exceptions or messages. Just the error 2 (MAPI_E_FAILURE) when I call MapiSendMail. 

    My problem is : Why, in the same program, this function works when I click on a button and doesn't work when I click on the notifyicon? 

    I d'on't think the thread is similar to my problem. When I use MapiSendMail from a button, it works for 32 Bit and 64 Bit Platforms and for x86 and "Any CPU" target platform( in the project). The MapiSendMail function doesn't work when I click on the notifyicon in 64 bits and x86 target platform but works when I click on a button.

    • Edited by Reya52 Thursday, July 3, 2014 1:27 PM
    Thursday, July 3, 2014 1:06 PM
  • Mickael,

    Take a look at the Problem with outlook and MAPISendMail (returns MAPI_E_FAILURE when outlook is running) forum thread. Is this your case?

    Thursday, July 3, 2014 1:38 PM
  • Thanks for your answers.

    No it's not my case. My program run at the same privilege level as Outlook.  It doesn't work if Outlook is running or not when I click on the notifyicon. But it works when I click on a button.

    I don't have this problem when i use MapiSendMail with a button.

    Thursday, July 3, 2014 2:05 PM
  • It looks like the issue is related to the NotifyIcon component, not the MAPISendMail function.

    Did you have a chance to check the current thread id for the NotifyIcon component. Do you call the code from the single thread?

    Thursday, July 3, 2014 2:11 PM