Problem with default email client

Eduardo Gomez 3,416 Reputation points
2023-02-01T21:49:49.9366667+00:00

I am trying to send an email using MAPI, this will use my default email app. My potential users need to be able to send emails using their default client.

#region SESSION

        public bool Logon(IntPtr hwnd) {
            winhandle = hwnd;
            error = MAPILogon(hwnd, null, null, 0, 0, ref session);
            if (error != 0)
                error = MAPILogon(hwnd, null, null, MapiLogonUI, 0, ref session);
            return error == 0;
        }

        public void Reset() {
            findseed = null;
            origin = new MapiRecipDesc();
            recpts.Clear();
            attachs.Clear();
            lastMsg = null;
        }

        public void Logoff() {
            if (session != IntPtr.Zero) {
                error = MAPILogoff(session, winhandle, 0, 0);
                session = IntPtr.Zero;
            }
        }


        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        private static extern int MAPILogon(IntPtr hwnd, string prf, string pw,
                                                int flg, int rsv, ref IntPtr sess);
        [DllImport("MAPI32.DLL")]
        private static extern int MAPILogoff(IntPtr sess, IntPtr hwnd,
                                                int flg, int rsv);

        private const int MapiLogonUI = 0x00000001;
        private const int MapiPasswordUI = 0x00020000;
        private const int MapiNewSession = 0x00000002;
        private const int MapiForceDownload = 0x00001000;
        private const int MapiExtendedUI = 0x00000020;


        private IntPtr session = IntPtr.Zero;
        private IntPtr winhandle = IntPtr.Zero;
        #endregion

        #region SENDING

        public bool Send(string sub, string txt) {
            lastMsg = new MapiMessage {
                subject = sub,
                noteText = txt,

                // set pointers
                originator = AllocOrigin()
            };
            lastMsg.recips = AllocRecips(out lastMsg.recipCount);
            lastMsg.files = AllocAttachs(out lastMsg.fileCount);

            error = MAPISendMail(session, winhandle, lastMsg, 0, 0);
            Dealloc();
            Reset();
            return error == 0;
        }

        public void AddRecip(string name, string addr, bool cc) {
            MapiRecipDesc dest = new MapiRecipDesc();
            if (cc)
                dest.recipClass = MapiCC;
            else
                dest.recipClass = MapiTO;
            dest.name = name;
            dest.address = addr;
            recpts.Add(dest);
        }

        public void SetSender(string sname, string saddr) {
            origin.name = sname;
            origin.address = saddr;
        }

        public void Attach(string filepath) {
            attachs.Add(filepath);
        }

        private IntPtr AllocOrigin() {
            origin.recipClass = MapiORIG;
            Type rtype = typeof(MapiRecipDesc);
            int rsize = Marshal.SizeOf(rtype);
            IntPtr ptro = Marshal.AllocHGlobal(rsize);
            Marshal.StructureToPtr(origin, ptro, false);
            return ptro;
        }

        private IntPtr AllocRecips(out int recipCount) {
            recipCount = 0;
            if (recpts.Count == 0)
                return IntPtr.Zero;

            Type rtype = typeof(MapiRecipDesc);
            int rsize = Marshal.SizeOf(rtype);
            IntPtr ptrr = Marshal.AllocHGlobal(recpts.Count * rsize);

            long runptr = (long)ptrr;
            for (int i = 0; i < recpts.Count; i++) {
                Marshal.StructureToPtr(recpts[i] as MapiRecipDesc, (IntPtr)runptr, false);
                runptr += rsize;
            }

            recipCount = recpts.Count;
            return ptrr;
        }

        private IntPtr AllocAttachs(out int fileCount) {
            fileCount = 0;
            if (attachs == null)
                return IntPtr.Zero;
            if ((attachs.Count <= 0) || (attachs.Count > 100))
                return IntPtr.Zero;

            Type atype = typeof(MapiFileDesc);
            int asize = Marshal.SizeOf(atype);
            IntPtr ptra = Marshal.AllocHGlobal(attachs.Count * asize);

            MapiFileDesc mfd = new MapiFileDesc();
            mfd.position = -1;
            int runptr = (int)ptra;
            for (int i = 0; i < attachs.Count; i++) {
                string path = attachs[i] as string;
                mfd.name = Path.GetFileName(path);
                mfd.path = path;
                Marshal.StructureToPtr(mfd, (IntPtr)runptr, false);
                runptr += asize;
            }

            fileCount = attachs.Count;
            return ptra;
        }

        private void Dealloc() {
            Type rtype = typeof(MapiRecipDesc);
            int rsize = Marshal.SizeOf(rtype);

            if (lastMsg.originator != IntPtr.Zero) {
                Marshal.DestroyStructure(lastMsg.originator, rtype);
                Marshal.FreeHGlobal(lastMsg.originator);
            }

            if (lastMsg.recips != IntPtr.Zero) {
                long runptr = (long)lastMsg.recips;
                for (int i = 0; i < lastMsg.recipCount; i++) {
                    Marshal.DestroyStructure((IntPtr)runptr, rtype);
                    runptr += rsize;
                }
                Marshal.FreeHGlobal(lastMsg.recips);
            }

            if (lastMsg.files != IntPtr.Zero) {
                Type ftype = typeof(MapiFileDesc);
                int fsize = Marshal.SizeOf(ftype);

                long runptr = (long)lastMsg.files;
                for (int i = 0; i < lastMsg.fileCount; i++) {
                    Marshal.DestroyStructure((IntPtr)runptr, ftype);
                    runptr += fsize;
                }
                Marshal.FreeHGlobal(lastMsg.files);
            }
        }

        private const int MapiORIG = 0;
        private const int MapiTO = 1;
        private const int MapiCC = 2;
        private const int MapiBCC = 3;

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

        private MapiRecipDesc origin = new();
        private ArrayList recpts = new();
        private ArrayList attachs = new();
        #endregion

        #region FINDING

        public bool Next(ref MailEnvelop env) {
            error = MAPIFindNext(session, winhandle, null, findseed,
                                    MapiLongMsgID, 0, lastMsgID);
            if (error != 0)
                return false;
            findseed = lastMsgID.ToString();

            IntPtr ptrmsg = IntPtr.Zero;
            error = MAPIReadMail(session, winhandle, findseed,
                                MapiEnvOnly | MapiPeek | MapiSuprAttach, 0, ref ptrmsg);
            if ((error != 0) || (ptrmsg == IntPtr.Zero))
                return false;

            lastMsg = new MapiMessage();
            Marshal.PtrToStructure(ptrmsg, lastMsg);
            MapiRecipDesc orig = new MapiRecipDesc();
            if (lastMsg.originator != IntPtr.Zero)
                Marshal.PtrToStructure(lastMsg.originator, orig);

            env.id = findseed;
            env.date = DateTime.ParseExact(lastMsg.dateReceived, "yyyy/MM/dd HH:mm", DateTimeFormatInfo.InvariantInfo);
            env.subject = lastMsg.subject;
            env.from = orig.name;
            env.unread = (lastMsg.flags & MapiUnread) != 0;
            env.atts = lastMsg.fileCount;

            error = MAPIFreeBuffer(ptrmsg);
            return error == 0;
        }


        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        private static extern int MAPIFindNext(IntPtr sess, IntPtr hwnd, string typ,
                                                string seed, int flg, int rsv, StringBuilder id);

        private const int MapiUnreadOnly = 0x00000020;
        private const int MapiGuaranteeFiFo = 0x00000100;
        private const int MapiLongMsgID = 0x00004000;

        private StringBuilder lastMsgID = new StringBuilder(600);
        private string findseed = null;
        #endregion

        #region READING


        public string Read(string id, out MailAttach[] aat) {
            aat = null;
            IntPtr ptrmsg = IntPtr.Zero;
            error = MAPIReadMail(session, winhandle, id,
                                    MapiPeek | MapiSuprAttach, 0, ref ptrmsg);
            if ((error != 0) || (ptrmsg == IntPtr.Zero))
                return null;

            lastMsg = new MapiMessage();
            Marshal.PtrToStructure(ptrmsg, lastMsg);

            if ((lastMsg.fileCount > 0) && (lastMsg.fileCount < 100) && (lastMsg.files != IntPtr.Zero))
                GetAttachNames(out aat);

            MAPIFreeBuffer(ptrmsg);
            return lastMsg.noteText;
        }

        public bool Delete(string id) {
            error = MAPIDeleteMail(session, winhandle, id, 0, 0);
            return error == 0;
        }

        public bool SaveAttachm(string id, string name, string savepath) {
            IntPtr ptrmsg = IntPtr.Zero;
            error = MAPIReadMail(session, winhandle, id,
                                    MapiPeek, 0, ref ptrmsg);
            if ((error != 0) || (ptrmsg == IntPtr.Zero))
                return false;

            lastMsg = new MapiMessage();
            Marshal.PtrToStructure(ptrmsg, lastMsg);
            bool f = false;
            if ((lastMsg.fileCount > 0) && (lastMsg.fileCount < 100) && (lastMsg.files != IntPtr.Zero))
                f = SaveAttachByName(name, savepath);
            MAPIFreeBuffer(ptrmsg);
            return f;
        }


        private void GetAttachNames(out MailAttach[] aat) {
            aat = new MailAttach[lastMsg.fileCount];
            Type fdtype = typeof(MapiFileDesc);
            int fdsize = Marshal.SizeOf(fdtype);
            MapiFileDesc fdtmp = new MapiFileDesc();
            int runptr = (int)lastMsg.files;
            for (int i = 0; i < lastMsg.fileCount; i++) {
                Marshal.PtrToStructure((IntPtr)runptr, fdtmp);
                runptr += fdsize;
                aat[i] = new MailAttach();
                if (fdtmp.flags == 0) {
                    aat[i].position = fdtmp.position;
                    aat[i].name = fdtmp.name;
                    aat[i].path = fdtmp.path;
                }
            }
        }


        private bool SaveAttachByName(string name, string savepath) {
            bool f = true;
            Type fdtype = typeof(MapiFileDesc);
            int fdsize = Marshal.SizeOf(fdtype);
            MapiFileDesc fdtmp = new MapiFileDesc();
            int runptr = (int)lastMsg.files;
            for (int i = 0; i < lastMsg.fileCount; i++) {
                Marshal.PtrToStructure((IntPtr)runptr, fdtmp);
                runptr += fdsize;
                if (fdtmp.flags != 0)
                    continue;
                if (fdtmp.name == null)
                    continue;

                try {
                    if (name == fdtmp.name) {
                        if (File.Exists(savepath))
                            File.Delete(savepath);
                        File.Move(fdtmp.path, savepath);
                    }
                } catch (Exception) { f = false; error = 13; }

                try {
                    File.Delete(fdtmp.path);
                } catch (Exception) { }
            }
            return f;
        }


        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        private static extern int MAPIReadMail(IntPtr sess, IntPtr hwnd, string id,
                                                int flg, int rsv, ref IntPtr ptrmsg);

        [DllImport("MAPI32.DLL")]
        private static extern int MAPIFreeBuffer(IntPtr ptr);

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        private static extern int MAPIDeleteMail(IntPtr sess, IntPtr hwnd, string id,
                                                int flg, int rsv);

        private const int MapiPeek = 0x00000080;
        private const int MapiSuprAttach = 0x00000800;
        private const int MapiEnvOnly = 0x00000040;
        private const int MapiBodyAsFile = 0x00000200;

        private const int MapiUnread = 0x00000001;
        private const int MapiReceiptReq = 0x00000002;
        private const int MapiSent = 0x00000004;

        private MapiMessage lastMsg = null;
        #endregion

        #region ADDRESS

        public bool SingleAddress(string label, out string name, out string addr) {
            name = null;
            addr = null;
            int newrec = 0;
            IntPtr ptrnew = IntPtr.Zero;
            error = MAPIAddress(session, winhandle, null, 1, label, 0, IntPtr.Zero,
                                    0, 0, ref newrec, ref ptrnew);
            if ((error != 0) || (newrec < 1) || (ptrnew == IntPtr.Zero))
                return false;

            MapiRecipDesc recip = new MapiRecipDesc();
            Marshal.PtrToStructure(ptrnew, recip);
            name = recip.name;
            addr = recip.address;

            MAPIFreeBuffer(ptrnew);
            return true;
        }


        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        private static extern int MAPIAddress(IntPtr sess, IntPtr hwnd, string caption,
                                                int editfld, string labels, int recipcount, IntPtr ptrrecips,
                                                int flg, int rsv, ref int newrec, ref IntPtr ptrnew);
        #endregion

        #region ERRORS

        public string Error() {
            if (error <= 26)
                return errors[error];
            return "?unknown? [" + error.ToString() + "]";
        }

        private int error = 0;

        private 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]"
        };
        #endregion

    }

    [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;       // MapiRecipDesc* [1]
        public int recipCount;
        public IntPtr recips;           // MapiRecipDesc* [n]
        public int fileCount;
        public IntPtr files;            // MapiFileDesc*  [n]
    }

    [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;          // void*
    }

    [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;
    }

    public class MailEnvelop {
        public string id;
        public DateTime date;
        public string from;
        public string subject;
        public bool unread;
        public int atts;
    }

    public class MailAttach {
        public int position;
        public string path;
        public string name;
    }

I am using Windows 11, so my default client is the Mail app, (I have outlook installed, but I haven't configured it)

User's image

I am using it here and I get this error

            Mapi ma = new();
            ma.Logon(IntPtr.Zero);
            ma.AddRecip("anybody@anywhere.org", null, false);
            ma.Send("Subject", "Mail text here");
            ma.Attach(file.FilePath);
            ma.Logoff();

User's image

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,686 questions
{count} votes

Accepted answer
  1. Olaf Helper 41,411 Reputation points
    2023-02-03T06:57:07.6333333+00:00

    so my default client is the Mail app,

    The Mail App has no MAPI ActiveX API (one from old Windows world), but Outlook has; that's the reason. MAPI is more then out-dated.

    If you (would) develop in C++ NET, you can use SmtpClient Class instead.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Eduardo Gomez 3,416 Reputation points
    2023-02-03T17:44:59.6233333+00:00

    I fixed it, using the daraTranfer

    0 comments No comments