.NET 自从2.0开始,大大提升了 Mail.SmtpClient 的功能,对于发邮件,可谓游刃有余了。但是,美中不足的是没有提供保存邮件内容为eml文件的功能。
实际上,SmtpClient 和 MailMessage 已经实现了这个功能,只是这个功能是 NonPublic 的,对于空间外,不可见而已。
利用 Reflector 反编译一下 System.Net.Mail.SmtpClient 可以看到:
在 Send(MailMessage) 方法中,在MAIL被发送之前,是调用了一个 MailWriter fileMailWriter = this.GetFileMailWriter(this.PickupDirectoryLocation);
我们顺藤摸瓜,继续定位 GetFileMailWriter 这个方法
上面的代码中,赫然醒目的显示着 .eml ,看了里面的逻辑,我们其实就清楚了,SmtpClient.Send 之前,也是先生成了一个临时的eml文件,然后再发送这个文件出去的。
其中的关键就在 new MailWriter(new FileStream(str2, FileMode.CreateNew)) 这里。
我们接下来定位到我们的核心 MailWriter :
从上面可以看到,MailWriter 是一个 internal 的 class,所以我们在普通的调用Mail.SmtpClient 等的命名空间下,是看不到的,这时我们就需要用到反射(Reflection) 了。
下面给出完整的实现代码:
using System;
using ADODB;
using CDO;
using System.Net.Mail;
using System.IO;
using System.Globalization;
using System.Reflection;
/// <summary>
/// 将MailMessage保存为eml文件
/// </summary>
/// <param name="msg">待保存的具有内容的MailMessage</param>
/// <param name="emlFileAbsolutePath">保存后的eml文件的路径</param>
static void SaveToEml(MailMessage msg, string emlFileAbsolutePath)
{
const BindingFlags flags = BindingFlags.Instance │ BindingFlags.NonPublic │ BindingFlags.FlattenHierarchy;
using (MemoryStream ms = new MemoryStream())
{
Assembly assembly = typeof(System.Net.Mail.SmtpClient).Assembly;
Type tMailWriter = assembly.GetType("System.Net.Mail.MailWriter");
object mailWriter = Activator.CreateInstance(tMailWriter, flags, null, new object[] { ms }, CultureInfo.InvariantCulture);
msg.GetType().GetMethod("Send", flags).Invoke(msg, new object[] { mailWriter, true });
File.WriteAllText(emlFileAbsolutePath, System.Text.Encoding.Default.GetString(ms.ToArray()), System.Text.Encoding.Default);
}
}
使用方法:
MailMessage msg = new MailMessage();
msg.Subject = "你好,我是点晴";
msg.From = new MailAddress("cs@clicksun.cn");
msg.To.Add("service@clicksun.cn");
msg.Body = "欢迎访问点晴官网:";
SaveToEml(msg, @"d:\test.eml");
好了 ,完结了,祝大家好运吧!