打开默认邮件客户端以及附件

嗨,我正在使用WPF应用程序(使用c#)。

我需要有一个function,用户可以通过电子邮件将文件(音频文件)作为附件发送。 我尝试使用Microsoft.Office.Interop.Outlook.Application命名空间但它打开outlook并且如果未在客户端的计算机上安装outlook,则无法工作。

我尝试使用System.Net.Mail命名空间的SmtpClient()MailMessage()类,但它没有打开电子邮件客户端。 它通过预定义的服务器发送邮件(可能是一个问题,因为我不知道我的客户端的默认电子邮件域是什么。这个链接有我需要的所有东西,它的工作正常。

但是在那里他们使用了DllImport属性,并且使用这种方法可能会产生许多问题(根据我的理解)。 我不知道托管和非托管代码,所以我无法理解问题所在。 可以按照上面的链接中的示例进行操作。 如果不是为什么?

你能说出或提供如何处理我的问题的链接

我们可以利用大多数电子邮件客户端支持要加载的.EML文件格式这一事实。

因此,如果我们以一种可以作为.EML文件保存到文件系统的方式扩展System.Net.Mail.MailMessage类。 可以使用Process.Start(filename)使用默认邮件客户端打开生成的文件

为了使其正常工作,我们必须在.EML文件中添加一行包含“X-Unsent:1”的行。 此行告诉电子邮件客户端加载.EML文件,消息必须以“新消息”模式显示。

使用扩展方法的“addUnsentHeader”bool参数将此行添加到.EML文件中

扩展方法如下所示:

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

使用这样的扩展方法:

  var mailMessage = new MailMessage(); mailMessage.From = new MailAddress("someone@yourdomain.com"); mailMessage.Subject = "Your subject here"; mailMessage.IsBodyHtml = true; mailMessage.Body = "My HTML formatted body"; 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); 

您是否尝试过使用具有适当命令行的System.Diagnostics.Process.Start()

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

&attachment开关允许您指定文件名。

好吧,我正在努力工作,但据称可以做到。 我正在阅读这个怪物,并会回复你。

您可以要求Windows shell打开mailto URL:

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

您需要using System.Diagnostics

您可以按照RFC 6068中的描述设置消息的各个部分,如主题和正文

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

不幸的是,即使某些电子邮件客户端可能有办法处理它,mailto协议也不支持附件。

我使用了以下助手类。

 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 m_recipients = new List(); List m_attachments = new List(); 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; } 

使用MAPI类如下所示。

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

参考: 代码项目