Open default mail client along with a attachment

前端 未结 4 950
生来不讨喜
生来不讨喜 2020-11-27 18:10

Hi I am working on a WPF application (using c#).

I need to have a functionality where users can send files (audio files) as attachments via email. I tried using

相关标签:
4条回答
  • 2020-11-27 19:04

    Have you tried using System.Diagnostics.Process.Start() with an appropriate command line?

    mailto:some.guy@someplace.com?subject=an email&body=see attachment&attachment="/files/audio/attachment.mp3"
    

    The &attachment switch lets you specify a file name.

    Ok, I'm struggling to this working but allegedly it can be done. I'm currently reading through this monster and will get back to you.

    0 讨论(0)
  • 2020-11-27 19:06

    You can ask the Windows shell to open a mailto URL:

    var url = "mailto:someone@somewhere.com";
    Process.Start(url);
    

    You need to be using System.Diagnostics.

    You can set various parts of the message like subject and body as described in RFC 6068

    var url = "mailto:someone@somewhere.com?subject=Test&body=Hello";
    

    Unfortunately, the mailto protocol does not support attachments even though some e-mail clients may have a way of handling that.

    0 讨论(0)
  • 2020-11-27 19:08

    We can make use of the fact that most email clients support the .EML file format to be loaded.

    So if we Extend the System.Net.Mail.MailMessage Class in a way that it can be saved to the filesystem as an .EML file. The resulting file can be opened with the default mail client using Process.Start(filename)

    For this to work properly we have to add a line containing "X-Unsent: 1" to the .EML file. This line tells the email client loading the .EML file the message must be presented in "New message" mode.

    Use the "addUnsentHeader" bool parameter of the extension method to add this line to the .EML file

    The extension method looks like this:

    using System;
    using System.IO;
    using System.Net.Mail;
    using System.Reflection;
    
    namespace Fsolutions.Fbase.Common.Mail
    {
        public static class MailUtility
        {
            //Extension method for MailMessage to save to a file on disk
            public static void Save(this MailMessage message, string filename, bool addUnsentHeader = true)
            {
                using (var filestream = File.Open(filename, FileMode.Create))
                {
                    if (addUnsentHeader)
                    {
                        var binaryWriter = new BinaryWriter(filestream);
                        //Write the Unsent header to the file so the mail client knows this mail must be presented in "New message" mode
                        binaryWriter.Write(System.Text.Encoding.UTF8.GetBytes("X-Unsent: 1" + Environment.NewLine));
                    }
    
                    var assembly = typeof(SmtpClient).Assembly;
                    var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
    
                    // Get reflection info for MailWriter contructor
                    var mailWriterContructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
    
                    // Construct MailWriter object with our FileStream
                    var mailWriter = mailWriterContructor.Invoke(new object[] { filestream });
    
                    // Get reflection info for Send() method on MailMessage
                    var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
    
                    sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { mailWriter, true, true }, null);
    
                    // Finally get reflection info for Close() method on our MailWriter
                    var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
    
                    // Call close method
                    closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);
                }
            }
        }
    }
    

    Use the extension method like this:

            var mailMessage = new MailMessage();
            mailMessage.From = new MailAddress("someone@yourdomain.com");
            mailMessage.Subject = "Your subject here";
            mailMessage.IsBodyHtml = true;
            mailMessage.Body = "<span style='font-size: 12pt; color: red;'>My HTML formatted body</span>";
    
            mailMessage.Attachments.Add(new Attachment("C://Myfile.pdf"));
    
            var filename = "C://Temp/mymessage.eml";
    
            //save the MailMessage to the filesystem
            mailMessage.Save(filename);
    
            //Open the file with the default associated application registered on the local machine
            Process.Start(filename);
    
    0 讨论(0)
  • 2020-11-27 19:13

    I used the following helper class.

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

    Use the MAPI class as below.

    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");
    

    Reference: Code Project

    0 讨论(0)
提交回复
热议问题