C# 打开带有附件的默认邮件客户端
嗨,我正在开发一个WPF应用程序(使用c#) 我需要有一个功能,用户可以发送文件(音频文件)作为附件通过电子邮件。 我尝试使用C# 打开带有附件的默认邮件客户端,c#,wpf,email,C#,Wpf,Email,嗨,我正在开发一个WPF应用程序(使用c#) 我需要有一个功能,用户可以发送文件(音频文件)作为附件通过电子邮件。 我尝试使用Microsoft.Office.Interop.Outlook.Application名称空间,但如果客户端计算机上未安装Outlook,它将打开Outlook,并且无法工作 我尝试使用System.Net.Mail命名空间的SmtpClient()和MailMessage()类,但没有打开电子邮件客户端。 它通过预定义的服务器发送邮件(可能是个问题,因为我不知道客户端
Microsoft.Office.Interop.Outlook.Application
名称空间,但如果客户端计算机上未安装Outlook,它将打开Outlook,并且无法工作
我尝试使用System.Net.Mail
命名空间的SmtpClient()
和MailMessage()
类,但没有打开电子邮件客户端。
它通过预定义的服务器发送邮件(可能是个问题,因为我不知道客户端的默认电子邮件域是什么。它有我需要的所有东西,并且工作正常
但是他们在那里使用了DllImport属性,并且使用此方法可能会出现许多问题(据我所知)。我不知道托管和非托管代码,因此我无法理解问题所在。是否可以按照上面链接中的示例进行操作。如果不可以,原因是什么
您能否告知或提供有关如何解决我的问题的链接您是否尝试过使用带有适当命令行的
System.Diagnostics.Process.Start()
mailto:some.guy@someplace.com?subject=an email&body=see attachment&attachment="/files/audio/attachment.mp3"
&附件
开关用于指定文件名
好的,我正在努力完成这项工作,但据称这是可以做到的。我正在阅读,稍后会与您联系。您可以要求Windows shell打开mailto URL:
var url = "mailto:someone@somewhere.com";
Process.Start(url);
您需要使用System.Diagnostics
您可以设置消息的各个部分,如主题和正文,如中所述
不幸的是,mailto协议不支持附件,即使某些电子邮件客户端可能有处理附件的方法。我们可以利用大多数电子邮件客户端都支持要加载的.EML文件格式这一事实 因此,如果我们扩展System.Net.Mail.MailMessage类,使其可以作为.EML文件保存到文件系统中。 可以使用Process.Start(文件名)使用默认邮件客户端打开生成的文件 要使其正常工作,我们必须在.EML文件中添加一行,其中包含“X-Unsent:1”。该行告诉加载.EML文件的电子邮件客户端,邮件必须以“新邮件”模式显示 使用extension方法的“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 = "<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);
使用如下扩展方法:
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 = "<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);
var mailMessage=new mailMessage();
mailMessage.From=新邮件地址(“someone@yourdomain.com");
mailMessage.Subject=“此处的主题”;
mailMessage.IsBodyHtml=true;
mailMessage.Body=“我的HTML格式的正文”;
mailMessage.Attachments.Add(新附件(“C://Myfile.pdf”);
var filename=“C://Temp/mymessage.eml”;
//将邮件消息保存到文件系统
mailMessage.Save(文件名);
//打开在本地计算机上注册了默认关联应用程序的文件
Process.Start(文件名);
我使用了以下帮助器类
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;
}
参考:我无法让我的电子邮件客户端处理
附件
,正如我指出的,RFC 6068没有定义任何附件支持。我忘了提到这一点。我也尝试过使用mailto…方法,但它所做的是在我的浏览器中打开一个新选项卡。当从朋友计算机尝试它时r Outlook正在打开,但没有附件。@Raj123在将来,删除您已经尝试过的明显答案将是一个巨大的优势:D@Gudsor我尝试了mailto方法,但我觉得这种方法不可能实现附件。我尝试了您建议的方法,但正如我在浏览器中打开新选项卡之前所说的那样(我不知道mailto和我的浏览器之间有什么关系)。我正在浏览您提供的链接,但我认为我的计算机可能有一些故障,因为其他系统正在打开其默认邮件客户端。这不起作用,它会在以下行引发异常:sendMethod.Invoke(message,BindingFlags.Instance |……。我得到了与@Marjan相同的错误-但我尝试将其实现为一个“块”(而不是扩展System.Net.Mail.MailMessage
)。此解决方案的正确实现是什么?@derekantrican当您知道发件人地址时,此方法有效。必须在mailMessage.Save之前设置发件人。因此,使用此方法时,我们似乎应该首先从默认电子邮件客户端获取帐户。Windows 10 mail似乎不使用X-Unsent标头,只需执行以下操作将其设置为非传出电子邮件.eml文件不可编辑。如何使其可编辑?这种方式在我的环境中不起作用(W7,VS2013,从测试中执行):无错误(代码=0),没有打开的Outlook此处存在相同的问题,此代码不起作用。Win 10,VS2010,没有错误,没有打开任何内容。我们正在使用MAPI进行生产,我一点也不建议使用MAPI。它会导致HTML邮件出现问题,如果某个内容与实际不符,通常会抛出错误,使您搜索注册表修复程序,但这些修复程序很少起作用。我们正在尝试使用电子邮件现在是ML方法。CC和BCC似乎做了同样的事情。不幸的是,OP专门询问了附件。这不是OP的完美答案。但它做到了我所需要的。:)它只是在Chrome浏览器中打开一个空白页。如果有人在asp.net中需要它:重复: