最近因故需要用.Net(C#)将邮件信息保存为本地eml文件,看起来是个费劲的活:首先得读懂MIME协议(RFC 2045~2049),然后写代码。还好,以前有朋友也有过这样的需求,并有现成解决方案,呵呵:System.Net.Mail命名空间里已经实现了MailWriter,只不知道为啥没有公开而已。
用Xenocode Fox 2007(Community Edition)加载System.dll,找到System.Net.Mail.SmtpClient类,可看到其Send(MailMessage)方法中有这么两句代码:
MailWriter writer;
writer = GetFileMailWriter(PickupDirectoryLocation);
我们来看看GetFileMailWriter方法:
internal MailWriter GetFileMailWriter (string pickupDirectory)
{
string path;
...do
{
Guid guid1 = Guid.NewGuid();
string path2 = guid1.ToString() + ".eml";
path = Path.Combine(pickupDirectory, path2);
}
while (File.Exists(path));
return new MailWriter(new FileStream(path, FileMode.CreateNew));
}
再往深里看便可知:MailWriter直接将MailMessage内容写成了“.eml”文件,而且是按MIME协议写入的,Yeah!
那接下来要做的就是用上MailWriter这个内部(internal)类,当然这是很简单的事:
public static byte[] MailMessageToArray(MailMessage msg)
{
const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
using (var ms = new MemoryStream())
{
var assembly = typeof (System.Net.Mail.SmtpClient).Assembly;
var writerType = assembly.GetType("System.Net.Mail.MailWriter");
var writer = Activator.CreateInstance(writerType, flags, null, new object[] {ms},
CultureInfo.InvariantCulture);
msg.GetType().GetMethod("Send", flags).Invoke(msg, new[] {writer, true});
return ms.ToArray();
}
}
如果我们使用的是C#3.0以后的版本,还可以为MailMessage添加扩展方法,这样使用起来更为自然。代码如下:
//定义扩展方法
public static class MailMessageExtend
{
public static byte[] ToArray(this MailMessage msg)
{
const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
using (var ms = new MemoryStream())
{
var assembly = typeof(System.Net.Mail.SmtpClient).Assembly;
var writerType = assembly.GetType("System.Net.Mail.MailWriter");
var writer = Activator.CreateInstance(writerType, flags, null, new object[] { ms },
CultureInfo.InvariantCulture);
msg.GetType().GetMethod("Send", flags).Invoke(msg, new[] { writer, true });
return ms.ToArray();
}
}}
//调用
private void button1_Click(object sender, EventArgs e)
{
var msg = new MailMessage();
...
var content = msg.ToArray();
...
}