【问题标题】:Opening default e-mail program with attachment (C#)打开带有附件的默认电子邮件程序 (C#)
【发布时间】:2011-07-19 19:32:38
【问题描述】:

我正在寻找一种方法来打开用户的默认电子邮件程序以编写新电子邮件并从 C# 应用程序中指定附件。现在,我可以开始一封电子邮件并指定收件人、主题、正文等,但我找不到任何方法来指定附件。

System.Diagnostics.Process.Start(@"mailto:me@mydomain.com&subject=Hi&body=%0D%0DSent from my Kinect");

这对于基本电子邮件非常有用,但无法添加附件。关于背景知识,我的老板想使用语音命令从 Kinect 获取快照,然后通过电子邮件将其发送给某人。

查看“标题相似的问题”,我发现this,这可能是错误的语言,但它让我认为至少有一种方法可以使用Microsoft Outlook。这是我工作中的大多数人都在使用的,但我真的希望能够与任何邮件客户端一起使用。

我不想只通过 C# 发送电子邮件,因为我希望用户能够在发送之前在他们的邮件客户端中编辑电子邮件。

那么,问题来了:有没有办法在打开用户的默认电子邮件程序时指定附件?如果没有,我在哪里可以找到有关使用 C# 在 Microsoft Outlook 中创建带有附件的电子邮件的资源?

【问题讨论】:

    标签: c# email interop


    【解决方案1】:

    我已使用代码here 打开带有附件的用户默认电子邮件客户端。

    // Below is the source code and simple test class for creating and displaying emails. 
    // It uses the MAPI API and is therefore not subject to the same restrictions as 
    // the "mailto" shell extension.
    // 
    // Using the MapiMailMessage you can set the title, subject, recipients and attach files. 
    // Then show the resulting email to the user, ready from them to send. This class is very 
    // useful for supporting applications and enriching addins.
    // 
    // Note, that the class is a port from a VB version I had and although it does have 
    // comments, it is not up to my usual standard. I will be revisiting this and tidying 
    // it up shortly.
    
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Threading;
    
    #region Test Class
    
    public class TestMapiMessageClass
    {
        /// <summary>
        /// Test method to create and show an email
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            MapiMailMessage message = new MapiMailMessage("Test Message", "Test Body");
            message.Recipients.Add("Test@Test.com");
            message.Files.Add(@"C:\del.txt");
            message.ShowDialog();
            Console.ReadLine();
        }
    }
    #endregion Test Class
    
    #region Public MapiMailMessage Class
    
    /// <summary>
    /// Represents an email message to be sent through MAPI.
    /// </summary>
    public class MapiMailMessage
    {
        #region Private MapiFileDescriptor Class
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        private class MapiFileDescriptor
        {
            public int reserved = 0;
            public int flags = 0;
            public int position = 0;
            public string path = null;
            public string name = null;
            public IntPtr type = IntPtr.Zero;
        }
    
        #endregion Private MapiFileDescriptor Class
    
        #region Enums
    
        /// <summary>
        /// Specifies the valid RecipientTypes for a Recipient.
        /// </summary>
        public enum RecipientType : int
        {
            /// <summary>
            /// Recipient will be in the TO list.
            /// </summary>
            To = 1,
    
            /// <summary>
            /// Recipient will be in the CC list.
            /// </summary>
            CC = 2,
    
            /// <summary>
            /// Recipient will be in the BCC list.
            /// </summary>
            BCC = 3
        };
    
        #endregion Enums
    
        #region Member Variables
    
        private string _subject;
        private string _body;
        private RecipientCollection _recipientCollection;
        private ArrayList _files;
        private ManualResetEvent _manualResetEvent;
    
        #endregion Member Variables
    
        #region Constructors
    
        /// <summary>
        /// Creates a blank mail message.
        /// </summary>
        public MapiMailMessage()
        {
            _files = new ArrayList();
            _recipientCollection = new RecipientCollection();
            _manualResetEvent = new ManualResetEvent(false);
        }
    
        /// <summary>
        /// Creates a new mail message with the specified subject.
        /// </summary>
        public MapiMailMessage(string subject)
            : this()
        {
            _subject = subject;
        }
    
        /// <summary>
        /// Creates a new mail message with the specified subject and body.
        /// </summary>
        public MapiMailMessage(string subject, string body)
            : this()
        {
            _subject = subject;
            _body = body;
        }
    
        #endregion Constructors
    
        #region Public Properties
    
        /// <summary>
        /// Gets or sets the subject of this mail message.
        /// </summary>
        public string Subject
        {
            get { return _subject; }
            set { _subject = value; }
        }
    
        /// <summary>
        /// Gets or sets the body of this mail message.
        /// </summary>
        public string Body
        {
            get { return _body; }
            set { _body = value; }
        }
    
        /// <summary>
        /// Gets the recipient list for this mail message.
        /// </summary>
        public RecipientCollection Recipients
        {
            get { return _recipientCollection; }
        }
    
        /// <summary>
        /// Gets the file list for this mail message.
        /// </summary>
        public ArrayList Files
        {
            get { return _files; }
        }
    
        #endregion Public Properties
    
        #region Public Methods
    
        /// <summary>
        /// Displays the mail message dialog asynchronously.
        /// </summary>
        public void ShowDialog()
        {
            // Create the mail message in an STA thread
            Thread t = new Thread(new ThreadStart(_ShowMail));
            t.IsBackground = true;
            t.ApartmentState = ApartmentState.STA;
            t.Start();
    
            // only return when the new thread has built it's interop representation
            _manualResetEvent.WaitOne();
            _manualResetEvent.Reset();
        }
    
        #endregion Public Methods
    
        #region Private Methods
    
        /// <summary>
        /// Sends the mail message.
        /// </summary>
        private void _ShowMail(object ignore)
        {
            MAPIHelperInterop.MapiMessage message = new MAPIHelperInterop.MapiMessage();
    
            using (RecipientCollection.InteropRecipientCollection interopRecipients
                        = _recipientCollection.GetInteropRepresentation())
            {
    
                message.Subject = _subject;
                message.NoteText = _body;
    
                message.Recipients = interopRecipients.Handle;
                message.RecipientCount = _recipientCollection.Count;
    
                // Check if we need to add attachments
                if (_files.Count > 0)
                {
                    // Add attachments
                    message.Files = _AllocAttachments(out message.FileCount);
                }
    
                // Signal the creating thread (make the remaining code async)
                _manualResetEvent.Set();
    
                const int MAPI_DIALOG = 0x8;
                //const int MAPI_LOGON_UI = 0x1;
                const int SUCCESS_SUCCESS = 0;
                int error = MAPIHelperInterop.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, MAPI_DIALOG, 0);
    
                if (_files.Count > 0)
                {
                    // Deallocate the files
                    _DeallocFiles(message);
                }
    
                // Check for error
                if (error != SUCCESS_SUCCESS)
                {
                    _LogErrorMapi(error);
                }
            }
        }
    
        /// <summary>
        /// Deallocates the files in a message.
        /// </summary>
        /// <param name="message">The message to deallocate the files from.</param>
        private void _DeallocFiles(MAPIHelperInterop.MapiMessage message)
        {
            if (message.Files != IntPtr.Zero)
            {
                Type fileDescType = typeof(MapiFileDescriptor);
                int fsize = Marshal.SizeOf(fileDescType);
    
                // Get the ptr to the files
                int runptr = (int)message.Files;
                // Release each file
                for (int i = 0; i < message.FileCount; i++)
                {
                    Marshal.DestroyStructure((IntPtr)runptr, fileDescType);
                    runptr += fsize;
                }
                // Release the file
                Marshal.FreeHGlobal(message.Files);
            }
        }
    
        /// <summary>
        /// Allocates the file attachments
        /// </summary>
        /// <param name="fileCount"></param>
        /// <returns></returns>
        private IntPtr _AllocAttachments(out int fileCount)
        {
            fileCount = 0;
            if (_files == null)
            {
                return IntPtr.Zero;
            }
            if ((_files.Count <= 0) || (_files.Count > 100))
            {
                return IntPtr.Zero;
            }
    
            Type atype = typeof(MapiFileDescriptor);
            int asize = Marshal.SizeOf(atype);
            IntPtr ptra = Marshal.AllocHGlobal(_files.Count * asize);
    
            MapiFileDescriptor mfd = new MapiFileDescriptor();
            mfd.position = -1;
            int runptr = (int)ptra;
            for (int i = 0; i < _files.Count; i++)
            {
                string path = _files[i] as string;
                mfd.name = Path.GetFileName(path);
                mfd.path = path;
                Marshal.StructureToPtr(mfd, (IntPtr)runptr, false);
                runptr += asize;
            }
    
            fileCount = _files.Count;
            return ptra;
        }
    
        /// <summary>
        /// Sends the mail message.
        /// </summary>
        private void _ShowMail()
        {
            _ShowMail(null);
        }
    
    
        /// <summary>
        /// Logs any Mapi errors.
        /// </summary>
        private void _LogErrorMapi(int errorCode)
        {
            const int MAPI_USER_ABORT = 1;
            const int MAPI_E_FAILURE = 2;
            const int MAPI_E_LOGIN_FAILURE = 3;
            const int MAPI_E_DISK_FULL = 4;
            const int MAPI_E_INSUFFICIENT_MEMORY = 5;
            const int MAPI_E_BLK_TOO_SMALL = 6;
            const int MAPI_E_TOO_MANY_SESSIONS = 8;
            const int MAPI_E_TOO_MANY_FILES = 9;
            const int MAPI_E_TOO_MANY_RECIPIENTS = 10;
            const int MAPI_E_ATTACHMENT_NOT_FOUND = 11;
            const int MAPI_E_ATTACHMENT_OPEN_FAILURE = 12;
            const int MAPI_E_ATTACHMENT_WRITE_FAILURE = 13;
            const int MAPI_E_UNKNOWN_RECIPIENT = 14;
            const int MAPI_E_BAD_RECIPTYPE = 15;
            const int MAPI_E_NO_MESSAGES = 16;
            const int MAPI_E_INVALID_MESSAGE = 17;
            const int MAPI_E_TEXT_TOO_LARGE = 18;
            const int MAPI_E_INVALID_SESSION = 19;
            const int MAPI_E_TYPE_NOT_SUPPORTED = 20;
            const int MAPI_E_AMBIGUOUS_RECIPIENT = 21;
            const int MAPI_E_MESSAGE_IN_USE = 22;
            const int MAPI_E_NETWORK_FAILURE = 23;
            const int MAPI_E_INVALID_EDITFIELDS = 24;
            const int MAPI_E_INVALID_RECIPS = 25;
            const int MAPI_E_NOT_SUPPORTED = 26;
            const int MAPI_E_NO_LIBRARY = 999;
            const int MAPI_E_INVALID_PARAMETER = 998;
    
            string error = string.Empty;
            switch (errorCode)
            {
                case MAPI_USER_ABORT:
                    error = "User Aborted.";
                    break;
                case MAPI_E_FAILURE:
                    error = "MAPI Failure.";
                    break;
                case MAPI_E_LOGIN_FAILURE:
                    error = "Login Failure.";
                    break;
                case MAPI_E_DISK_FULL:
                    error = "MAPI Disk full.";
                    break;
                case MAPI_E_INSUFFICIENT_MEMORY:
                    error = "MAPI Insufficient memory.";
                    break;
                case MAPI_E_BLK_TOO_SMALL:
                    error = "MAPI Block too small.";
                    break;
                case MAPI_E_TOO_MANY_SESSIONS:
                    error = "MAPI Too many sessions.";
                    break;
                case MAPI_E_TOO_MANY_FILES:
                    error = "MAPI too many files.";
                    break;
                case MAPI_E_TOO_MANY_RECIPIENTS:
                    error = "MAPI too many recipients.";
                    break;
                case MAPI_E_ATTACHMENT_NOT_FOUND:
                    error = "MAPI Attachment not found.";
                    break;
                case MAPI_E_ATTACHMENT_OPEN_FAILURE:
                    error = "MAPI Attachment open failure.";
                    break;
                case MAPI_E_ATTACHMENT_WRITE_FAILURE:
                    error = "MAPI Attachment Write Failure.";
                    break;
                case MAPI_E_UNKNOWN_RECIPIENT:
                    error = "MAPI Unknown recipient.";
                    break;
                case MAPI_E_BAD_RECIPTYPE:
                    error = "MAPI Bad recipient type.";
                    break;
                case MAPI_E_NO_MESSAGES:
                    error = "MAPI No messages.";
                    break;
                case MAPI_E_INVALID_MESSAGE:
                    error = "MAPI Invalid message.";
                    break;
                case MAPI_E_TEXT_TOO_LARGE:
                    error = "MAPI Text too large.";
                    break;
                case MAPI_E_INVALID_SESSION:
                    error = "MAPI Invalid session.";
                    break;
                case MAPI_E_TYPE_NOT_SUPPORTED:
                    error = "MAPI Type not supported.";
                    break;
                case MAPI_E_AMBIGUOUS_RECIPIENT:
                    error = "MAPI Ambiguous recipient.";
                    break;
                case MAPI_E_MESSAGE_IN_USE:
                    error = "MAPI Message in use.";
                    break;
                case MAPI_E_NETWORK_FAILURE:
                    error = "MAPI Network failure.";
                    break;
                case MAPI_E_INVALID_EDITFIELDS:
                    error = "MAPI Invalid edit fields.";
                    break;
                case MAPI_E_INVALID_RECIPS:
                    error = "MAPI Invalid Recipients.";
                    break;
                case MAPI_E_NOT_SUPPORTED:
                    error = "MAPI Not supported.";
                    break;
                case MAPI_E_NO_LIBRARY:
                    error = "MAPI No Library.";
                    break;
                case MAPI_E_INVALID_PARAMETER:
                    error = "MAPI Invalid parameter.";
                    break;
            }
    
            Debug.WriteLine("Error sending MAPI Email. Error: " + error + " (code = " + errorCode + ").");
        }
        #endregion Private Methods
    
        #region Private MAPIHelperInterop Class
    
        /// <summary>
        /// Internal class for calling MAPI APIs
        /// </summary>
        internal class MAPIHelperInterop
        {
            #region Constructors
    
            /// <summary>
            /// Private constructor.
            /// </summary>
            private MAPIHelperInterop()
            {
                // Intenationally blank
            }
    
            #endregion Constructors
    
            #region Constants
    
            public const int MAPI_LOGON_UI = 0x1;
    
            #endregion Constants
    
            #region APIs
    
            [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
            public static extern int MAPILogon(IntPtr hwnd, string prf, string pw, int flg, int rsv, ref IntPtr sess);
    
            #endregion APIs
    
            #region Structs
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
                public class MapiMessage
            {
                public int Reserved = 0;
                public string Subject = null;
                public string NoteText = null;
                public string MessageType = null;
                public string DateReceived = null;
                public string ConversationID = null;
                public int Flags = 0;
                public IntPtr Originator = IntPtr.Zero;
                public int RecipientCount = 0;
                public IntPtr Recipients = IntPtr.Zero;
                public int FileCount = 0;
                public IntPtr Files = IntPtr.Zero;
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
                public class MapiRecipDesc
            {
                public int Reserved = 0;
                public int RecipientClass = 0;
                public string Name = null;
                public string Address = null;
                public int eIDSize = 0;
                public IntPtr EntryID = IntPtr.Zero;
            }
    
            [DllImport("MAPI32.DLL")]
            public static extern int MAPISendMail(IntPtr session, IntPtr hwnd, MapiMessage message, int flg, int rsv);
    
            #endregion Structs
        }
    
        #endregion Private MAPIHelperInterop Class
    }
    
    #endregion Public MapiMailMessage Class
    
    #region Public Recipient Class
    
    /// <summary>
    /// Represents a Recipient for a MapiMailMessage.
    /// </summary>
    public class Recipient
    {
        #region Public Properties
    
        /// <summary>
        /// The email address of this recipient.
        /// </summary>
        public string Address = null;
    
        /// <summary>
        /// The display name of this recipient.
        /// </summary>
        public string DisplayName = null;
    
        /// <summary>
        /// How the recipient will receive this message (To, CC, BCC).
        /// </summary>
        public MapiMailMessage.RecipientType RecipientType = MapiMailMessage.RecipientType.To;
    
        #endregion Public Properties
    
        #region Constructors
    
        /// <summary>
        /// Creates a new recipient with the specified address.
        /// </summary>
        public Recipient(string address)
        {
            Address = address;
        }
    
        /// <summary>
        /// Creates a new recipient with the specified address and display name.
        /// </summary>
        public Recipient(string address, string displayName)
        {
            Address = address;
            DisplayName = displayName;
        }
    
        /// <summary>
        /// Creates a new recipient with the specified address and recipient type.
        /// </summary>
        public Recipient(string address, MapiMailMessage.RecipientType recipientType)
        {
            Address = address;
            RecipientType = recipientType;
        }
    
        /// <summary>
        /// Creates a new recipient with the specified address, display name and recipient type.
        /// </summary>
        public Recipient(string address, string displayName, MapiMailMessage.RecipientType recipientType)
        {
            Address = address;
            DisplayName = displayName;
            RecipientType = recipientType;
        }
    
        #endregion Constructors
    
        #region Internal Methods
    
        /// <summary>
        /// Returns an interop representation of a recepient.
        /// </summary>
        /// <returns></returns>
        internal MapiMailMessage.MAPIHelperInterop.MapiRecipDesc GetInteropRepresentation()
        {
            MapiMailMessage.MAPIHelperInterop.MapiRecipDesc interop = new MapiMailMessage.MAPIHelperInterop.MapiRecipDesc();
    
            if (DisplayName == null)
            {
                interop.Name = Address;
            }
            else
            {
                interop.Name = DisplayName;
                interop.Address = Address;
            }
    
            interop.RecipientClass = (int)RecipientType;
    
            return interop;
        }
    
        #endregion Internal Methods
    }
    
    #endregion Public Recipient Class
    
    #region Public RecipientCollection Class
    
    /// <summary>
    /// Represents a colleciton of recipients for a mail message.
    /// </summary>
    public class RecipientCollection : CollectionBase
    {
        /// <summary>
        /// Adds the specified recipient to this collection.
        /// </summary>
        public void Add(Recipient value)
        {
            List.Add(value);
        }
    
        /// <summary>
        /// Adds a new recipient with the specified address to this collection.
        /// </summary>
        public void Add(string address)
        {
            this.Add(new Recipient(address));
        }
    
        /// <summary>
        /// Adds a new recipient with the specified address and display name to this collection.
        /// </summary>
        public void Add(string address, string displayName)
        {
            this.Add(new Recipient(address, displayName));
        }
    
        /// <summary>
        /// Adds a new recipient with the specified address and recipient type to this collection.
        /// </summary>
        public void Add(string address, MapiMailMessage.RecipientType recipientType)
        {
            this.Add(new Recipient(address, recipientType));
        }
    
        /// <summary>
        /// Adds a new recipient with the specified address, display name and recipient type to this collection.
        /// </summary>
        public void Add(string address, string displayName, MapiMailMessage.RecipientType recipientType)
        {
            this.Add(new Recipient(address, displayName, recipientType));
        }
    
        /// <summary>
        /// Returns the recipient stored in this collection at the specified index.
        /// </summary>
        public Recipient this[int index]
        {
            get
            {
                return (Recipient)List[index];
            }
        }
    
        internal InteropRecipientCollection GetInteropRepresentation()
        {
            return new InteropRecipientCollection(this);
        }
    
        /// <summary>
        /// Struct which contains an interop representation of a colleciton of recipients.
        /// </summary>
        internal struct InteropRecipientCollection : IDisposable
        {
            #region Member Variables
    
            private IntPtr _handle;
            private int _count;
    
            #endregion Member Variables
    
            #region Constructors
    
            /// <summary>
            /// Default constructor for creating InteropRecipientCollection.
            /// </summary>
            /// <param name="outer"></param>
            public InteropRecipientCollection(RecipientCollection outer)
            {
                _count = outer.Count;
    
                if (_count == 0)
                {
                    _handle = IntPtr.Zero;
                    return;
                }
    
                // allocate enough memory to hold all recipients
                int size = Marshal.SizeOf(typeof(MapiMailMessage.MAPIHelperInterop.MapiRecipDesc));
                _handle = Marshal.AllocHGlobal(_count * size);
    
                // place all interop recipients into the memory just allocated
                int ptr = (int)_handle;
                foreach (Recipient native in outer)
                {
                    MapiMailMessage.MAPIHelperInterop.MapiRecipDesc interop = native.GetInteropRepresentation();
    
                    // stick it in the memory block
                    Marshal.StructureToPtr(interop, (IntPtr)ptr, false);
                    ptr += size;
                }
            }
    
            #endregion Costructors
    
            #region Public Properties
    
            public IntPtr Handle
            {
                get { return _handle; }
            }
    
            #endregion Public Properties
    
            #region Public Methods
    
            /// <summary>
            /// Disposes of resources.
            /// </summary>
            public void Dispose()
            {
                if (_handle != IntPtr.Zero)
                {
                    Type type = typeof(MapiMailMessage.MAPIHelperInterop.MapiRecipDesc);
                    int size = Marshal.SizeOf(type);
    
                    // destroy all the structures in the memory area
                    int ptr = (int)_handle;
                    for (int i = 0; i < _count; i++)
                    {
                        Marshal.DestroyStructure((IntPtr)ptr, type);
                        ptr += size;
                    }
    
                    // free the memory
                    Marshal.FreeHGlobal(_handle);
    
                    _handle = IntPtr.Zero;
                    _count = 0;
                }
            }
    
            #endregion Public Methods
        }
    }
    
    #endregion Public RecipientCollection Class
    

    【讨论】:

    • 太棒了,我会试一试。谢谢。
    • @beater 不幸的是,链接似乎已失效-您能提供更新吗?
    • 经过多年的出色工作,这刚刚停止工作。它会在 ShowDialog() 方法期间崩溃。有什么想法吗?
    • 我刚刚开始工作。有几个 int 实例会导致溢出。我将这些更改为 Int64 似乎已经解决了它
    【解决方案2】:

    我认为您不能完全按照您的需要去做,从安全问题到通过需要用户名/密码的客户端自动邮寄附件,再到在您试图应对时无法发送密钥等诸多问题任意数量的电子邮件客户端。

    不过,正如您所知,您可以使用 C# 发送带有附件的电子邮件。如何创建一封发送给用户的电子邮件,用户可以通过自己的编辑进行转发?

    【讨论】:

    • 替代方案的好主意,一定会牢记这一点,以防我无法按照我想要的方式工作。
    【解决方案3】:

    无法使用mailto: url 处理程序指定附件。

    【讨论】:

    • 我知道,我正在寻找可以使用附件的替代方案。
    猜你喜欢
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-02
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    相关资源
    最近更新 更多