Click here to Skip to main content
Click here to Skip to main content

Programmatically adding attachments to emails in C# and VB.NET

By , 20 Apr 2007
 

Screenshot - SendToNET2.jpg

Updates

By popular demand, this article has been updated to provide for multiple attachments and recipients.

Introduction

Not unlike The Terminator, my previous article explaining how to programmatically add attachments to emails was meant to be a low budget offering for a very straightforward but useful addition to your GUIs. I hadn't quite expected the tsunami of emails and comments, particularly questions about how to do all this in C# and VB.NET. Hopefully, this article will answer those questions and be like Terminator 2 - the ultimate sequel.

And like all good sequels, there are problems along the way. It's not actors wanting exorbitant fees that's the issue. For us, it's the pain of calling unmanaged code - MAPI32 - from managed code. We'll need to delve into the world of .NET Interop Marshaling to explain how some of this works. We'll be using PInvoke - a.k.a. Platform Invoke - to make this all work.

The sample code provides both C# and VB.NET versions, with a simple test program for each.

There's a new Marshaler in town

.NET provides a language-independent development system enabling you to write classes in VB, C++, or C#, and use them in other languages; you can even derive from classes in a different language. But how do you call a function in an unmanaged DLL? You have to somehow convert your C# and VB objects into the necessary structs, char*'s, and function pointers the unmanaged DLL expects. In other words, your parameters must be marshaled.

Marshaling is a complex topic (see MSDN), and Microsoft has gone to great lengths to support unmanaged code interop and COM interop, so I guess they think unmanaged code will be around for a while! Fortunately, the parts we need for this example are pretty straightforward. To call a DLL function from C#, you must declare a function that will tell the compiler where the exported entry point is in the unmanaged DLL - in this case MAPI32.DLL. The DLLImport attribute does this for you.

using System.Runtime.InteropServices;

[DllImport("MAPI32.DLL")]
private static extern int MAPISendMail(IntPtr sess, 
        IntPtr hwnd, MapiMessage message, int flg, int rsv);

The interop in .NET provides default marshaling to handle common types for parameters like strings and ints. Unfortunately, many Win32 API calls use pointers to unmanaged structs so you have to manage your own marshaling for these. You need to create a C# class or struct that mirrors the required unmanaged struct, choose the necessary types within the struct, and mark it up with the [StructLayout] attribute. This is necessary because the CLR controls the physical layout of memory, so if the class needs to be arranged in an expected way, use [StructLayout] to preserve the layout, and .NET will not mess with it.

Default marshaling gotchas

  • If the unmanaged call uses a LPTSTR out parameter, map this to a StringBuilder rather than String. Strings aren't mutable, and the default marshaling type for StringBuilder is also an LPTSTR.
  • Use ref to mark up out parameters or some equivalent. I've used IntPtr in this sample. It's an interop supplied, platform specific type that can be used to represent a pointer or handle.
  • If you make the call, you may get this friendly message at runtime:

    Screenshot - SendToNET1.JPG

    • Check for a mismatch between your unmanaged function signature and the declared [DllImport] C# function declaration.
    • Check the parameter types - particularly Strings vs. StringBuilder and the use of ref.
    • Check that the size of struct parameters match that required by the unmanaged function.
    • Check the types and size of your struct members.

The C# way

using System;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections.Generic;
using System.Windows.Forms;

namespace SendFileTo
{
    class MAPI
    {
        public bool AddRecipientTo(string email)
        {
            return AddRecipient(email, HowTo.MAPI_TO);
        }

        public bool AddRecipientCC(string email)
        {
            return AddRecipient(email, HowTo.MAPI_TO);
        }

        public bool AddRecipientBCC(string email)
        {
            return AddRecipient(email, HowTo.MAPI_TO);
        }

        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);
            if (m_lastError > 1)
                MessageBox.Show("MAPISendMail failed! " + GetLastError(), 
                    "MAPISendMail");

            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();
            m_lastError = 0;
        }
        
        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 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;
    }
}

Here's the code for the C# class. If you compare it to the C++ version in my previous article, you'll see it's basically the same structure with a few additions to cope with the marshaling.

Sidebar

By managing its own memory, you can't just include the mapi.h in your .NET code to get the necessary MapiMessage and MapiFileDesc structures. I've just hand copied the ones I needed, but maybe someone will complete this chore or write a .h converter.

The VB.NET way

Here's the equivalent VB.NET class which doesn't really need any more explanation than given above:

Namespace SendFileTo
    Class MAPI
        Public Function AddRecipientTo(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_TO)
        End Function

        Public Function AddRecipientCC(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_TO)
        End Function

        Public Function AddRecipientBCC(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_TO)
        End Function

        Public Sub AddAttachment(ByVal strAttachmentFileName As String)
            m_attachments.Add(strAttachmentFileName)
        End Sub

        Public Function SendMailPopup(ByVal strSubject As String, 
                ByVal strBody As String) As Integer
            Return SendMail(strSubject, strBody, MAPI_LOGON_UI Or MAPI_DIALOG)
        End Function

        Public Function SendMailDirect(ByVal strSubject As String, 
            ByVal strBody As String) As Integer
            Return SendMail(strSubject, strBody, MAPI_LOGON_UI)
        End Function


        <DllImport("MAPI32.DLL")> _
         Private Shared Function MAPISendMail(ByVal sess As IntPtr, 
             ByVal hwnd As IntPtr, ByVal message As MapiMessage, 
             ByVal flg As Integer, ByVal rsv As Integer) As Integer
        End Function

        Private Function SendMail(ByVal strSubject As String, 
            ByVal strBody As String, ByVal how As Integer) As Integer
            Dim msg As MapiMessage = New MapiMessage()
            msg.subject = strSubject
            msg.noteText = strBody

            msg.recips = GetRecipients(msg.recipCount)
            msg.files = GetAttachments(msg.fileCount)

            m_lastError = MAPISendMail(New IntPtr(0), New IntPtr(0), msg, how, 
                0)
            If m_lastError > 1 Then
                MessageBox.Show("MAPISendMail failed! " + GetLastError(), 
                    "MAPISendMail")
            End If

            Cleanup(msg)
            Return m_lastError
        End Function

        Private Function AddRecipient(ByVal email As String, 
            ByVal howTo As howTo) As Boolean
            Dim recipient As MapiRecipDesc = New MapiRecipDesc()

            recipient.recipClass = CType(howTo, Integer)
            recipient.name = email
            m_recipients.Add(recipient)

            Return True
        End Function

        Private Function GetRecipients(ByRef recipCount As Integer) As IntPtr
            recipCount = 0
            If m_recipients.Count = 0 Then
                Return 0
            End If

            Dim size As Integer = Marshal.SizeOf(GetType(MapiRecipDesc))
            Dim intPtr As IntPtr = Marshal.AllocHGlobal(
                m_recipients.Count * size)

            Dim ptr As Integer = CType(intPtr, Integer)
            Dim mapiDesc As MapiRecipDesc
            For Each mapiDesc In m_recipients
                Marshal.StructureToPtr(mapiDesc, CType(ptr, IntPtr), False)
                ptr += size
            Next

            recipCount = m_recipients.Count
            Return intPtr
        End Function

        Private Function GetAttachments(ByRef fileCount As Integer) As IntPtr
            fileCount = 0
            If m_attachments Is Nothing Then
                Return 0
            End If

            If (m_attachments.Count <= 0) Or (m_attachments.Count > 
                maxAttachments) Then
                Return 0
            End If

            Dim size As Integer = Marshal.SizeOf(GetType(MapiFileDesc))
            Dim intPtr As IntPtr = Marshal.AllocHGlobal(
                m_attachments.Count * size)

            Dim mapiFileDesc As MapiFileDesc = New MapiFileDesc()
            mapiFileDesc.position = -1
            Dim ptr As Integer = CType(intPtr, Integer)

            Dim strAttachment As String
            For Each strAttachment In m_attachments
                mapiFileDesc.name = Path.GetFileName(strAttachment)
                mapiFileDesc.path = strAttachment
                Marshal.StructureToPtr(mapiFileDesc, CType(ptr, IntPtr), False)
                ptr += size
            Next

            fileCount = m_attachments.Count
            Return intPtr
        End Function

        Private Sub Cleanup(ByRef msg As MapiMessage)
            Dim size As Integer = Marshal.SizeOf(GetType(MapiRecipDesc))
            Dim ptr As Integer = 0

            If msg.recips <> IntPtr.Zero Then
                ptr = CType(msg.recips, Integer)
                Dim i As Integer
                For i = 0 To msg.recipCount - 1 Step i + 1
                    Marshal.DestroyStructure(CType(ptr, IntPtr), 
                        GetType(MapiRecipDesc))
                    ptr += size
                Next
                Marshal.FreeHGlobal(msg.recips)
            End If

            If msg.files <> IntPtr.Zero Then
                size = Marshal.SizeOf(GetType(MapiFileDesc))

                ptr = CType(msg.files, Integer)
                Dim i As Integer
                For i = 0 To msg.fileCount - 1 Step i + 1
                    Marshal.DestroyStructure(CType(ptr, IntPtr), 
                        GetType(MapiFileDesc))
                    ptr += size
                Next
                Marshal.FreeHGlobal(msg.files)
            End If

            m_recipients.Clear()
            m_attachments.Clear()
            m_lastError = 0
        End Sub

        Public Function GetLastError() As String
            If m_lastError <= 26 Then
                Return errors(m_lastError)
            End If
            Return "MAPI error [" + m_lastError.ToString() + "]"
        End Function

        ReadOnly errors() As String = 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]"}

        Dim m_recipients As New List(Of MapiRecipDesc)
        Dim m_attachments As New List(Of String)
        Dim m_lastError As Integer = 0

        Private Const MAPI_LOGON_UI As Integer = &H1
        Private Const MAPI_DIALOG As Integer = &H8
        Private Const maxAttachments As Integer = 20

        Enum howTo
            MAPI_ORIG = 0
            MAPI_TO
            MAPI_CC
            MAPI_BCC
        End Enum

    End Class

    <StructLayout(LayoutKind.Sequential)> _
    Public Class MapiMessage
        Public reserved As Integer
        Public subject As String
        Public noteText As String
        Public messageType As String
        Public dateReceived As String
        Public conversationID As String
        Public flags As Integer
        Public originator As IntPtr
        Public recipCount As Integer
        Public recips As IntPtr
        Public fileCount As Integer
        Public files As IntPtr
    End Class

    <StructLayout(LayoutKind.Sequential)> _
    Public Class MapiFileDesc
        Public reserved As Integer
        Public flags As Integer
        Public position As Integer
        Public path As String
        Public name As String
        Public type As IntPtr
    End Class

    <StructLayout(LayoutKind.Sequential)> _
    Public Class MapiRecipDesc
        Public reserved As Integer
        Public recipClass As Integer
        Public name As String
        Public address As String
        Public eIDSize As Integer
        Public enTryID As IntPtr
    End Class
End Namespace

Example use

The attached C# and VB.NET samples show the whole story, but to use this is pretty easy as this fragment shows:

Screenshot - SendToNET3.jpg

using SendFileTo;

namespace TestSendTo
{
    public partial class Form1 : Form
    {
        private void btnSend_Click(object sender, EventArgs e)
        {
            MAPI mapi = new MAPI();

            mapi.AddAttachment("c:\\temp\\file1.txt");
            mapi.AddAttachment("c:\\temp\\file2.txt");
            mapi.AddRecipientTo("person1@somewhere.com");
            mapi.AddRecipientTo("person2@somewhere.com");
            mapi.SendMailPopup("testing", "body text");
            
            // Or if you want try and do a direct send without displaying the 
            // mail dialog mapi.SendMailDirect("testing", "body text");
        }
    }
}

You can call AddAttachment and AddRecipient multiple times to add as many attachments and recipients as you want, although I've put an arbitrary limit of 20 on the attachments just as a precaution. Calling SendMailPopup will display the email client send mail dialog and you can then add further recipients or attachments and hit the send button manually. Alternatively, you can call SendMailDirect which will attempt to send the mail without showing the email client dialog.

Make sure when using the samples with hard coded attachment paths shown above that the files exist in the given locations. If you don't, SendMail will fail.

Errors

If the return value from the underlying MAPISendMail is anything other than OK[0] or User aborted[1], a message box will be displayed with the appropriate error text and code.

I cannot self-terminate. You must lower me into the steel.

Hopefully, this has answered all the questions although I'm sure there will be comments. I've been using the C# code in a few applications for remote bug reporting, and I haven't had any problems. Do let me know if you spot any howlers. I hope there aren't any, otherwise I'll have to stoop to an unworthy Rise Of The Email Attachments.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

David M Brooks
Web Developer
United Kingdom United Kingdom
Member
When Dave isn't trying to play drums, fly helicopters or race cars, he can be found trying to be CTO at www.eventility.co.uk He must try harder!
 
You can read Dave's ramblings in his blog Aliens Ate My GUI
 
Or, if you can be bothered, he twitters on BoomerDave

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionProblem with modeless windowsmemberNikita D. Sinelnikov14hrs 44mins ago 
In my app where are some windows - parent MDI, some MDI childs... and some modeless windows, which are opened from MCD childs. There is the only one window ("error dialog"), which shows an error and a link to open mail client to send error report, shown from Application.ThreadException handler by "error dialog".ShowDialog().
 
The error dialog has .TopMost == false, but it is shown over any other window of the app. It is modal, so all is OK - while link "send report" is not clicked. When it is clicked, the code below is executing:
var ma = new SendFileTo.MAPI();
ma.AddAttachment(attachmentFileName);
ma.AddRecipientTo(recipient);
ma.SendMailPopup("Application error report", "Report text");
and it shows outlook (my mail client) window well, but the dialog and outlook window becomes NOT TOP windows of the app... Another window appears at the top, not even a window that raised an exception handled.
 
I've tried to call SendMailPopup() from the second UI thread in app, hope that does not affect other app windows, but it returns an eroror == 2 ("MAPI_E_FAILURE, One or more unspecified errors occurred. No message was sent" - says MSDN, nothing is clear).
 
So the problem is how to open mail client window to be not affected by any other window of the application (to be in a different thread or even a process)?
QuestionDefault SignaturememberMember 871343623 Nov '12 - 0:55 
Someone had asked about this already but has somebody managed to find a solution on how to retain the signature within Outlook? Other than that it works well Smile | :)
 
Thank you in advance
Questionevent handlermemberluluhuhu18 Nov '12 - 13:39 
hey, i am new to this forum and was attracted here by this awsome post.
 
however i have a further request: is it possible using the first 2 parametres(handles) of MAPISendMail to detect event on send click?
 
thanks in advance.
SuggestionThis is working in VS 2003 (without System.Collections.Generic)memberMember 231400424 Aug '12 - 9:12 
Thank you all for 99% of the work that this class has done for me
 
(without System.Collections.Generic)
(only tested Button Send)
(work without attachment)
(work with many attachment)
(work to: TO, CC, BCC)
 
CODE UNDER Test_Button
 
Private Sub Test_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Test_Button.Click
            Dim mapi As New SendFileTo.MAPI
            mapi.AddAttachment("C:\xxx\yyy.XML")
            mapi.AddAttachment("C:\xxx\yyy.pdf")
            mapi.AddRecipientTo("xxx@mail.it")
            mapi.AddRecipientCC("yyy@mail.it")
            mapi.AddRecipientBCC("zzz@mail.it")
            mapi.SendMailPopup("Subject at 20.30", "Body at 20.30")
End Sub
 
CLASS MODIFIED
'''all commented lines have been replaced with those under
'''to make the code compatible with VB.2003
 
Imports System
Imports System.Runtime.InteropServices
Imports System.IO
'''Imports System.Collections.Generic
Imports System.Windows.Forms
Namespace SendFileTO
      Class MAPI
            Public Function AddRecipientTo(ByVal email As String) As Boolean
                  Return AddRecipient(email, howTo.MAPI_TO)
            End Function
            Public Function AddRecipientCC(ByVal email As String) As Boolean
                  Return AddRecipient(email, howTo.MAPI_CC)
            End Function
            Public Function AddRecipientBCC(ByVal email As String) As Boolean
                  Return AddRecipient(email, howTo.MAPI_BCC)
            End Function
            Public Sub AddAttachment(ByVal strAttachmentFileName As String)
                  ' m_attachments.Add(strAttachmentFileName)
                  ReDim Preserve m_attachments(m_attachments.Length)
                  m_attachments(m_attachments.Length - 1) = strAttachmentFileName
            End Sub
            Public Function SendMailPopup(ByVal strSubject As String, ByVal strBody As String) As Integer
                  Return SendMail(strSubject, strBody, MAPI_LOGON_UI Or MAPI_DIALOG)
            End Function
            Public Function SendMailDirect(ByVal strSubject As String, ByVal strBody As String) As Integer
                  Return SendMail(strSubject, strBody, MAPI_LOGON_UI)
            End Function
 
            <DllImport("MAPI32.DLL")> _
            Private Shared Function MAPISendMail(ByVal sess As IntPtr, ByVal hwnd As IntPtr, ByVal message As MapiMessage, ByVal flg As Integer, ByVal rsv As Integer) As Integer
            End Function
            Private Function SendMail(ByVal strSubject As String, ByVal strBody As String, ByVal how As Integer) As Integer
                  Dim msg As MapiMessage = New MapiMessage
                  msg.subject = strSubject
                  msg.noteText = strBody
                  msg.recips = GetRecipients(msg.recipCount)
                  msg.files = GetAttachments(msg.fileCount)
                  m_lastError = MAPISendMail(New IntPtr(0), New IntPtr(0), msg, how, 0)
                  If m_lastError > 1 Then
                        MessageBox.Show("MAPISendMail failed! " + GetLastError(), "MAPISendMail")
                  End If
                  Cleanup(msg)
                  Return m_lastError
            End Function
            Private Function AddRecipient(ByVal email As String, ByVal howTo As howTo) As Boolean
                  Dim recipient As MapiRecipDesc = New MapiRecipDesc
                  recipient.recipClass = CType(howTo, Integer)
                  recipient.name = email
                  'm_recipients.Add(recipient)
                  ReDim Preserve m_recipients(m_recipients.Length)
                  m_recipients(m_recipients.Length - 1) = recipient
                  Return True
            End Function
            Private Function GetRecipients(ByRef recipCount As Integer) As IntPtr
                  recipCount = 0
                  If m_recipients.Length = 0 Then
                        Return New IntPtr(0)
                  End If
                  Dim size As Integer = Marshal.SizeOf(GetType(MapiRecipDesc))
                  Dim intPtr As IntPtr = Marshal.AllocHGlobal(m_recipients.Length * size)
                  'Dim ptr As Integer = CType(intPtr, Integer)
                  Dim ptr As Integer = intPtr.ToInt32
                  Dim mapiDesc As MapiRecipDesc
                  For Each mapiDesc In m_recipients
                        ' Marshal.StructureToPtr(mapiDesc, CType(ptr, IntPtr), False)
                        Marshal.StructureToPtr(mapiDesc, New IntPtr(ptr), False)
                        ptr += size
                  Next
                  recipCount = m_recipients.Length
                  Return intPtr
            End Function
            Private Function GetAttachments(ByRef fileCount As Integer) As IntPtr
                  fileCount = 0
                  If m_attachments Is Nothing Then
                        Return New IntPtr(0)
                  End If
                  If (m_attachments.Length <= 0) Or (m_attachments.Length > maxAttachments) Then
                        Return New IntPtr(0)
                  End If
                  Dim size As Integer = Marshal.SizeOf(GetType(MapiFileDesc))
                  Dim intPtr As IntPtr = Marshal.AllocHGlobal(m_attachments.Length * size)
                  Dim mapiFileDesc As MapiFileDesc = New MapiFileDesc
                  mapiFileDesc.position = -1
                  'Dim ptr As Integer = CType(intPtr, Integer)
                  Dim ptr As Integer = intPtr.ToInt32
                  Dim strAttachment As String
                  For Each strAttachment In m_attachments
                        mapiFileDesc.name = Path.GetFileName(strAttachment)
                        mapiFileDesc.path = strAttachment
                        Marshal.StructureToPtr(mapiFileDesc, New IntPtr(ptr), False)
                        ptr += size
                  Next
                  ' fileCount = m_attachments.Count
                  fileCount = m_attachments.Length
                  Return intPtr
            End Function
            Private Sub Cleanup(ByRef msg As MapiMessage)
                  Dim size As Integer = Marshal.SizeOf(GetType(MapiRecipDesc))
                  Dim ptr As Integer = 0
                  Dim IntPtrZero As New IntPtr(0)
                  If msg.recips.Equals(IntPtrZero) Then
                        'ptr = CType(msg.recips, Integer)
                        ptr = msg.recips.ToInt32
                        Dim i As Integer
                        For i = 0 To msg.recipCount - 1 Step i + 1
                              'Marshal.DestroyStructure(CType(ptr, IntPtr), GetType(MapiRecipDesc))
                              Marshal.DestroyStructure(New IntPtr(ptr), GetType(MapiRecipDesc))
                              ptr += size
                        Next
                        Marshal.FreeHGlobal(msg.recips)
                  End If
                  If msg.files.Equals(IntPtrZero) Then
                        size = Marshal.SizeOf(GetType(MapiFileDesc))
                        'ptr = CType(msg.files, Integer)
                        ptr = msg.files.ToInt32
                        Dim i As Integer
                        For i = 0 To msg.fileCount - 1 Step i + 1
                              'Marshal.DestroyStructure(CType(ptr, IntPtr), GetType(MapiFileDesc))
                              Marshal.DestroyStructure(New IntPtr(ptr), GetType(MapiFileDesc))
                              ptr += size
                        Next
                        Marshal.FreeHGlobal(msg.files)
                  End If
                  'm_recipients.Clear()
                  ReDim m_recipients(-1)
                  'm_attachments.Clear()
                  ReDim m_attachments(-1)
                  m_lastError = 0
            End Sub
            Public Function GetLastError() As String
                  If m_lastError <= 26 Then
                        Return errors(m_lastError)
                  End If
                  Return "MAPI error [" + m_lastError.ToString() + "]"
            End Function
            ReadOnly errors() As String = 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]"}
            'Dim m_recipients As New List(Of MapiRecipDesc)
            'Dim m_attachments As New List(Of String)
            Dim m_recipients(-1) As MapiRecipDesc
            Dim m_attachments(-1) As String
            Dim m_lastError As Integer = 0
            Private Const MAPI_LOGON_UI As Integer = &H1
            Private Const MAPI_DIALOG As Integer = &H8
            Private Const maxAttachments As Integer = 20
            Enum howTo
                  MAPI_ORIG = 0
                  MAPI_TO
                  MAPI_CC
                  MAPI_BCC
            End Enum
      End Class
      <StructLayout(LayoutKind.Sequential)> _
      Public Class MapiMessage
            Public reserved As Integer
            Public subject As String
            Public noteText As String
            Public messageType As String
            Public dateReceived As String
            Public conversationID As String
            Public flags As Integer
            Public originator As IntPtr
            Public recipCount As Integer
            Public recips As IntPtr
            Public fileCount As Integer
            Public files As IntPtr
      End Class
      <StructLayout(LayoutKind.Sequential)> _
      Public Class MapiFileDesc
            Public reserved As Integer
            Public flags As Integer
            Public position As Integer
            Public path As String
            Public name As String
            Public type As IntPtr
      End Class
      <StructLayout(LayoutKind.Sequential)> _
      Public Class MapiRecipDesc
            Public reserved As Integer
            Public recipClass As Integer
            Public name As String
            Public address As String
            Public eIDSize As Integer
            Public enTryID As IntPtr
      End Class
End Namespace
Suggestionfew changes for vb.net [modified]memberla_morte17 Jul '12 - 4:37 
I changed this class from the original code:
 
Now Works to sending to CC/BCC senders:
Dim mapi As New SendFileTo.MAPI
 mapi.AddRecipientCC("something@domain.com")
 
Now Works to capture LastError value:
Dim LastErrorInt As Integer = mapi.SendMailPopup("subject", "body")
Dim LastError As String = mapi.GetLastError()
 

To catch errors you can use this way:
If mapi.SendMailPopup("subject", "body") > 0 Then
     MessageBox.Show("MAPISendMail failed! " + mapi.GetLastError(), "MAPISendMail")
End If
 

And finally to clean MailMessage and reset LastError values use this code:
mapi.CleanMailMessage()
 

 
Namespace SendFileTo
    Class MAPI
        Public Function AddRecipientTo(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_TO)
        End Function
 
        Public Function AddRecipientCC(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_CC)
        End Function
 
        Public Function AddRecipientBCC(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_BCC)
        End Function
 
        Public Sub AddAttachment(ByVal strAttachmentFileName As String)
            m_attachments.Add(strAttachmentFileName)
        End Sub
 
        Public Function SendMailPopup(ByVal strSubject As String, ByVal strBody As String) As Integer
            Return SendMail(strSubject, strBody, MAPI_LOGON_UI Or MAPI_DIALOG)
        End Function
 
        Public Sub CleanMailMessage()
            Cleanup(msg)
        End Sub
 
        Public Function SendMailDirect(ByVal strSubject As String, ByVal strBody As String) As Integer
            Return SendMail(strSubject, strBody, MAPI_LOGON_UI)
        End Function
 

        <DllImport("MAPI32.DLL")> _
         Private Shared Function MAPISendMail(ByVal sess As IntPtr, ByVal hwnd As IntPtr, ByVal message As MapiMessage, ByVal flg As Integer, ByVal rsv As Integer) As Integer
        End Function
 

        Dim msg As MapiMessage
 
        Private Function SendMail(ByVal strSubject As String, ByVal strBody As String, ByVal how As Integer) As Integer
            msg = New MapiMessage()
            msg.subject = strSubject
            msg.noteText = strBody
 
            msg.recips = GetRecipients(msg.recipCount)
            msg.files = GetAttachments(msg.fileCount)
 
            m_lastError = MAPISendMail(New IntPtr(0), New IntPtr(0), msg, how, 0)
            'If m_lastError > 0 Then
            '    MessageBox.Show("MAPISendMail failed! " + GetLastError(), "MAPISendMail")
            'End If

            'Cleanup(msg)
            Return m_lastError
        End Function
 
        Private Function AddRecipient(ByVal email As String, ByVal howTo As howTo) As Boolean
            Dim recipient As MapiRecipDesc = New MapiRecipDesc()
 
            recipient.recipClass = CType(howTo, Integer)
            recipient.name = email
            m_recipients.Add(recipient)
 
            Return True
        End Function
 
        Private Function GetRecipients(ByRef recipCount As Integer) As IntPtr
            recipCount = 0
            If m_recipients.Count = 0 Then
                Return 0
            End If
 
            Dim size As Integer = Marshal.SizeOf(GetType(MapiRecipDesc))
            Dim intPtr As IntPtr = Marshal.AllocHGlobal(m_recipients.Count * size)
 
            Dim ptr As Integer = CType(intPtr, Integer)
            Dim mapiDesc As MapiRecipDesc
            For Each mapiDesc In m_recipients
                Marshal.StructureToPtr(mapiDesc, CType(ptr, IntPtr), False)
                ptr += size
            Next
 
            recipCount = m_recipients.Count
            Return intPtr
        End Function
 
        Private Function GetAttachments(ByRef fileCount As Integer) As IntPtr
            fileCount = 0
            If m_attachments Is Nothing Then
                Return 0
            End If
 
            If (m_attachments.Count <= 0) Or (m_attachments.Count > maxAttachments) Then
                Return 0
            End If
 
            Dim size As Integer = Marshal.SizeOf(GetType(MapiFileDesc))
            Dim intPtr As IntPtr = Marshal.AllocHGlobal(m_attachments.Count * size)
 
            Dim mapiFileDesc As MapiFileDesc = New MapiFileDesc()
            mapiFileDesc.position = -1
            Dim ptr As Integer = CType(intPtr, Integer)
 
            Dim strAttachment As String
            For Each strAttachment In m_attachments
                mapiFileDesc.name = Path.GetFileName(strAttachment)
                mapiFileDesc.path = strAttachment
                Marshal.StructureToPtr(mapiFileDesc, CType(ptr, IntPtr), False)
                ptr += size
            Next
 
            fileCount = m_attachments.Count
            Return intPtr
        End Function
 
        Private Sub Cleanup(ByRef msg As MapiMessage)
            Dim size As Integer = Marshal.SizeOf(GetType(MapiRecipDesc))
            Dim ptr As Integer = 0
 
            If msg.recips <> IntPtr.Zero Then
                ptr = CType(msg.recips, Integer)
                Dim i As Integer
                For i = 0 To msg.recipCount - 1 Step i + 1
                    Marshal.DestroyStructure(CType(ptr, IntPtr), GetType(MapiRecipDesc))
                    ptr += size
                Next
                Marshal.FreeHGlobal(msg.recips)
            End If
 
            If msg.files <> IntPtr.Zero Then
                size = Marshal.SizeOf(GetType(MapiFileDesc))
 
                ptr = CType(msg.files, Integer)
                Dim i As Integer
                For i = 0 To msg.fileCount - 1 Step i + 1
                    Marshal.DestroyStructure(CType(ptr, IntPtr), GetType(MapiFileDesc))
                    ptr += size
                Next
                Marshal.FreeHGlobal(msg.files)
            End If
 
            m_recipients.Clear()
            m_attachments.Clear()
            m_lastError = 0
        End Sub
 
        Public Function GetLastError() As String
            If m_lastError <= 26 Then
                Return errors(m_lastError)
            End If
            Return "MAPI error [" + m_lastError.ToString() + "]"
        End Function
 
        ReadOnly errors() As String = 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]"}
 
        Dim m_recipients As New List(Of MapiRecipDesc)
        Dim m_attachments As New List(Of String)
        Dim m_lastError As Integer = 0
 
        Private Const MAPI_LOGON_UI As Integer = &H1
        Private Const MAPI_DIALOG As Integer = &H8
        Private Const maxAttachments As Integer = 20
 
        Enum howTo
            MAPI_ORIG = 0
            MAPI_TO
            MAPI_CC
            MAPI_BCC
        End Enum
 
    End Class
 
    <StructLayout(LayoutKind.Sequential)> _
    Public Class MapiMessage
        Public reserved As Integer
        Public subject As String
        Public noteText As String
        Public messageType As String
        Public dateReceived As String
        Public conversationID As String
        Public flags As Integer
        Public originator As IntPtr
        Public recipCount As Integer
        Public recips As IntPtr
        Public fileCount As Integer
        Public files As IntPtr
    End Class
 
    <StructLayout(LayoutKind.Sequential)> _
    Public Class MapiFileDesc
        Public reserved As Integer
        Public flags As Integer
        Public position As Integer
        Public path As String
        Public name As String
        Public type As IntPtr
    End Class
 
    <StructLayout(LayoutKind.Sequential)> _
    Public Class MapiRecipDesc
        Public reserved As Integer
        Public recipClass As Integer
        Public name As String
        Public address As String
        Public eIDSize As Integer
        Public enTryID As IntPtr
    End Class
End Namespace


modified 17 Jul '12 - 11:57.

BugHow to correct the abort message notification if window is closedmemberla_morte17 Jul '12 - 3:39 
change from:
 
If m_lastError > 1 Then
      MessageBox.Show("MAPISendMail failed! " + GetLastError(), "MAPISendMail")
End If
 

to:
If m_lastError > 0 Then
      MessageBox.Show("MAPISendMail failed! " + GetLastError(), "MAPISendMail")
End If
 
on this function:
Private Function SendMail(ByVal strSubject As String, ByVal strBody As String, ByVal how As Integer) As Integer

QuestionAlso, how might one go about setting the Request Read Receipt Flag?memberanalog99910 Jun '12 - 12:41 
Anyone figure out how to set the "request read receipt" flag as well?
QuestionWorks great - but how to set Originator / Sender?memberanalog99910 Jun '12 - 11:34 
Code works great, thanks a lot, saved me a ton of time. Curious if anyone has figured out how to code up a set originator routine. Here's what I have added to the class, and it is not working with the popup functionality which launches Windows Live Mail.
 
MapiRecipDesc m_sender = null;
 
bool SetSenderInternal(string email)
{
    m_sender = new MapiRecipDesc();
    m_sender.recipClass = (int)HowTo.MAPI_ORIG;
    m_sender.name = email;
    m_sender.address = email;
    m_sender.eIDSize = 0;
    m_sender.entryID = IntPtr.Zero;
    return true;
}
 

 
IntPtr GetSender()
{
    Type rtype = typeof(MapiRecipDesc);
    int rsize = Marshal.SizeOf(rtype);
    IntPtr ptrr = Marshal.AllocHGlobal(rsize);
 
    Marshal.StructureToPtr(m_sender, ptrr, false);
    return ptrr;
}
 
public bool SetSender(string email)
{
    return SetSenderInternal(email);
}
 
and then in SendMail() I add the following line:
 
if (m_sender != null)
{
    msg.originator = GetSender();
}

Questioncommentmembersercankapucu30 May '12 - 21:41 
excellent work. thanks
QuestionI tried using it in ASP.NET application : not workingmemberderinpdavis28 May '12 - 18:29 
I tried using it in ASP.NET application : not working
AnswerSet AspCompat="true" for pagememberderinpdavis29 May '12 - 15:25 
Set AspCompat="true" for page, made working.
 
But it not working after hosting the app to server [Windows 2003].
 
Any idea?
QuestionWrite a MSGmembermiguel_10 May '12 - 11:23 
Hi,
I can write a *.msg with MAPI dll?.
SuggestionSmallish issue with the VB.Net waymemberVlaamseLeeuw9 May '12 - 23:15 
Don't forget the imports at the beginning:
 
Imports System
Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Collections.Generic
Imports System.Windows.Forms

QuestionCC / BCCmemberMember 80150826 Apr '12 - 5:21 
Your CC and BCC methods do not work properly. They add them to the TO section, not the respective CC / BCC areas.
AnswerRe: CC / BCCmemberla_morte10 May '12 - 3:38 
change those lines:
Public Function AddRecipientCC(ByVal email As String) As Boolean
           Return AddRecipient(email, howTo.MAPI_TO)
       End Function
 
       Public Function AddRecipientBCC(ByVal email As String) As Boolean
           Return AddRecipient(email, howTo.MAPI_TO)
       End Function
 

to
 
Public Function AddRecipientCC(ByVal email As String) As Boolean
           Return AddRecipient(email, howTo.MAPI_CC)
       End Function
 
       Public Function AddRecipientBCC(ByVal email As String) As Boolean
           Return AddRecipient(email, howTo.MAPI_BCC)
       End Function

QuestionSendMailDirectmemberDarrinLynn5 Apr '12 - 7:09 
Hi David,
 
Thanks for a very useful tool. I have one question when using the SendMailDirect method I get a security warning from outlook, can this be bypassed?
 
Thanks
Darrin
Question[STAThread] is required if running from Console Application Projectmembermarkmuetz3 Apr '12 - 1:22 
If you're trying to use the code in SendFileTo.cs in a Console Application Project, you have to add the STAThreadAttribute to the Main method:
[STAThread]
static void Main(string args[])
 
Otherwise you will get a "General MAPI failure [2]" back from the MAPISendMail method.
AnswerRe: [STAThread] is required if running from Console Application ProjectmemberMember 801508210 Apr '12 - 5:42 
Thanks. this saved my butt. I'd argue that the code shouldn't be using WinForms to handle the exceptions, but should be throwing actual exceptions.
AnswerRe: [STAThread] is required if running from Console Application ProjectmemberMember 145559227 Jul '12 - 3:38 
Thanks for the comment, that's why it didn't work Smile | :)
QuestionImagesmemberMike Angelastro27 Mar '12 - 17:32 
What about embedding images like a logo?
QuestionA couple of small errorsmemberMember 454455827 Dec '11 - 3:27 
Thank you very much for this one.
It works like a charm with Windows Live Mail.
Now users don't have to use "regsvr32" to make MSMAPI work
which can be a huge problem for some users.
 
I found a couple of bugs in both versions (C# and VB).
These functions should look like this (the VB version):
howTo.MAPI_TO should be changed like this:
 
  Public Function AddRecipientCC(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_CC)
        End Function
 
        Public Function AddRecipientBCC(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_BCC)
        End Function
 
And a question: How do you ask for a receipt?
 
Happy Christmas!
 
Peter
GeneralAmazingly helpful article!memberUCLAdam30 Nov '11 - 23:21 
Can't say thanks enough, saved me a massive headache! Great article.
QuestionIF OUTLOOK CLOSED DONT WORKmemberaski90013 Nov '11 - 12:04 
need help...!!!
AnswerRe: IF OUTLOOK CLOSED DONT WORKmemberdragon23815 Nov '11 - 2:44 
I'm using Windows 7 32bit and Microsoft Outlook 2007. It did actually work for me with outlook closed. Which email client and version are you using? Which O/S are you using?
GeneralRe: IF OUTLOOK CLOSED DONT WORKmembervenkatpv9 Jul '12 - 8:08 
SendMailPopup doesn't work if I have outlook opened. (I am using Win 7 32 bit with outlook 2010). How to fix it?
QuestionKeeping the signaturememberMember 41379017 Nov '11 - 2:23 
Hi!
 
Does anybody know how can I send the mail message but keeping the pre-defined signature of the e-mail client?
 
Thanks in advance!
AnswerRe: Keeping the signaturememberhem-insphire11 Apr '12 - 21:57 
Did you ever find this out? Problem I have is that the body of the email is also plain text so you can't even insert it after if there's graphics involved!
QuestionGetting problem in reading mails in outlook 2003membernetexpertMaster21 Oct '11 - 1:36 
Hi, article is great!
 
But i am experiencing problem in reading mails using MAPI32.dll, though it is working fine with outlook 2007. But in 2003 MAPIReadMail method giving me Error code 17. Please help me out.
jitenSharma

QuestionThanks man.. It saved me...memberMember 131563028 Aug '11 - 9:13 
Thanks man.. you rock
QuestionCancelled messages stay in outboxmemberhileyj7 Jul '11 - 7:29 
Hi,
Thanks for the example code, definitely made things a lot easier. I noticed using this method to send a message (outlook 2007 is my default client), that if I cancel the message before sending the email will stay in the outbox. Apparently it has to be manually deleted through the outlook UI. Any ideas on how to clear a cancelled message out? Is this an outlook specific thing perhaps? I tried looking through the simple MAPI and nothing seemed obvious regarding this behaviour.
AnswerRe: Cancelled messages stay in outboxmemberMember 80150826 Apr '12 - 5:56 
Are you using SendMailPopup() or SendMailDirect()? I haven't seen this. Outlook isn't going to put it in your outbox until you hit Send. Did you mean that you're seeing it in your draft box after cancelling?
GeneralThnx A LOT buddy.memberMember 459675714 Jun '11 - 0:23 
Your code help me lot thank you very much you rock... Smile | :)
QuestionLost mouse focusmemberPQSIK26 May '11 - 10:29 
Using the code works but I'm have a problem when outlook opens.
 
The mouse dose not work in outlook.
 
I have to do some action like click on another running program to give it focus,
then when I click back to outlook I can use the mouse
 
Anyone had this problem and know of a solution.
 
Thanks
pqsik
AnswerRe: Lost mouse focusmemberPQSIK31 May '11 - 8:20 
I found the problem was with krypton toolkit buttons.
 
I used a standard button and it worked.
 
Thanks
GeneralMy vote of 5memberthanchet11 May '11 - 18:20 
Excellent: Simple but very helpful
GeneralThanksmemberEric Ouellet4 Apr '11 - 7:38 
Thanks a lot,
 
It works great ! Smile | :)
GeneralProblem with SendPopup with difernet account privilegues.memberstalion764 Apr '11 - 1:03 
Hi,
 
Very nice article and excellent code. But I have one problem.
When I integrate this class in to my application it works in most cases.
 
It doesn't work in 2 cases:
1. Mapi class used in Application started as non admin and default mail client started as admin (run as administrator)
2. Mapi class used in Application started as admin and default mail client started as non admin.
 
When the application and default mail client are started as same type (admin or non admin) it works perfectly.
 
The system is :
Windows 7 x64,
Outlook 2010 x64
UAC on
 
If anyone have idea how to overcome this problem please help.
Thanks in advance!!
GeneralRe: Problem with SendPopup with difernet account privilegues.memberMember 475837610 Jul '11 - 8:42 
I am having the same issue. I can open email via process start but not through MAPI. I get error code 2.
GeneralRe: Problem with SendPopup with difernet account privilegues.memberbojingo11 Aug '11 - 9:40 
Anyone have a solution to this? I get error code 2 as well.
GeneralRe: Problem with SendPopup with difernet account privilegues.memberm.p.m23 Nov '11 - 5:41 
I am also seeing this. (Error code = 2) Any solution?
GeneralMy vote of 5memberstalion764 Apr '11 - 0:54 
It works fine. And nicely described.
GeneralMy vote of 5memberPeterLav1 Mar '11 - 22:24 
Thanks, that help me a lot and it's clearly explained...
GeneralDoes not works for WebformmemberSathish Kumar J31 Jan '11 - 3:45 
Hi All,
 
I tried with winform & it worked perfectly. When i tried to convert this in webform, it does not works. Any one have any idea to help me please ?
 
Regards,
Sathish
GeneralMy vote of 5memberEng. Mohammed El-Said19 Jan '11 - 12:45 
Works great
GeneralMy vote of 5memberJohnmMcG17 Jan '11 - 16:57 
Works perfectly.
GeneralMy vote of 5membereibbed16 Dec '10 - 9:43 
Worked excellent first time.
GeneralIt doesn´t if outlook is closed.memberbolis30 Nov '10 - 1:16 
I had tried several times it doesn´t works if outlook is closed, I have Outlook 2007 and Windows 7 32 bits system.
 
I hope someone can help me!
 
tkkss
 
Claudia
GeneralGreat work, thnx - extension for Thunderbirdmemberlangeru24 Nov '10 - 4:16 
		class Mozilla
		{
			private const string csMozillaNotFound = "mozilla not found";
			private static string sMozMapi;
 
			[DllImport("kernel32.dll")]
			public static extern IntPtr LoadLibrary(string dllToLoad);
 
			[DllImport("kernel32.dll")]
			public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
			
			[DllImport("kernel32.dll")]
			public static extern bool FreeLibrary(IntPtr hModule);
 
			[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
			private delegate int MAPISendMail(IntPtr sess, IntPtr hwnd, MapiMessage message, int flg, int rsv);
 
			public static bool IsInstalled
			{
				get
				{
					if (string.IsNullOrEmpty(sMozMapi))
					{
						string sPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + "\\Mozilla Thunderbird\\mozMapi32.dll";
 
						if (File.Exists(sPath))
							sMozMapi = sPath;
						else
							sMozMapi = csMozillaNotFound;
					}
					
					if (sMozMapi == csMozillaNotFound)
						return false;
					return true;
				}
			}
 
			public static int MozMAPISendMail(IntPtr sess, IntPtr hwnd, MapiMessage message, int flg, int rsv)
			{
				if (Mozilla.IsInstalled)
				{
					IntPtr pDll = LoadLibrary(sMozMapi);
 
					if (pDll == IntPtr.Zero)
						return 0;
 
					IntPtr pAddressOfFunctionToCall = GetProcAddress(pDll, "MAPISendMail");
					if (pAddressOfFunctionToCall == IntPtr.Zero)
						return 0;
 
					MAPISendMail mAPISendMail = (MAPISendMail)Marshal.GetDelegateForFunctionPointer(
																					pAddressOfFunctionToCall,
																					typeof(MAPISendMail));
 
					int res = mAPISendMail(sess, hwnd, message, flg, rsv);
					FreeLibrary(pDll);
				}
				return 0;
			}
		}
 
		uint 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 = (uint) MAPISendMail(new IntPtr(0), new IntPtr(0), msg, how, 0);
			if (m_lastError > 1)
			{
				if (Mozilla.IsInstalled)
					m_lastError = (uint)Mozilla.MozMAPISendMail(new IntPtr(0), new IntPtr(0), msg, how, 0);
				if (m_lastError > 1)
					MessageBox.Show("MAPISendMail failed! " + GetLastError());
			}
 
			Cleanup(ref msg);
			return m_lastError;
		}

GeneralThank youmemberMember 456324820 Oct '10 - 4:59 
Very nice code Smile | :)
GeneralMy vote of 5memberMember 456324820 Oct '10 - 4:58 
Thank you for your help! Best Regards , Gustavo de Argentina

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 20 Apr 2007
Article Copyright 2007 by David M Brooks
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid