【发布时间】:2011-11-22 20:20:39
【问题描述】:
是否有任何简单的方法可以将 System.Net.Mail.MailMessage 对象转换为原始邮件消息文本,例如在记事本中打开 eml 文件时。
【问题讨论】:
是否有任何简单的方法可以将 System.Net.Mail.MailMessage 对象转换为原始邮件消息文本,例如在记事本中打开 eml 文件时。
【问题讨论】:
byte[] allBytes = new byte[attachment.ContentStream.Length];
int bytesRead = attachment.ContentStream.Read(allBytes, 0, (int)attachment.ContentStream.Length);
Encoding encoding = Encoding.UTF8;
String contenidoCorreo = encoding.GetString(allBytes);
【讨论】:
我在MimeKit 中实现了逻辑,允许您将 System.Net.Mail.MailMessage 转换为MimeKit.MimeMessage。完成后,您可以简单地将消息写入流:
var message = (MimeMessage) CreateSystemNetMailMessage ();
using (var stream = File.Create ("C:\\message.eml"))
message.WriteTo (stream);
这不需要反映到内部方法中,这意味着它不依赖于运行时,使其比迄今为止给出的其他答案更具可移植性。
【讨论】:
这是相同的解决方案,但作为MailMessage 的扩展方法。
通过在静态上下文中抓取ConstructorInfo 和MethodInfo 成员一次,可以最大限度地减少一些反射开销。
/// <summary>
/// Uses reflection to get the raw content out of a MailMessage.
/// </summary>
public static class MailMessageExtensions
{
private static readonly BindingFlags Flags = BindingFlags.Instance | BindingFlags.NonPublic;
private static readonly Type MailWriter = typeof(SmtpClient).Assembly.GetType("System.Net.Mail.MailWriter");
private static readonly ConstructorInfo MailWriterConstructor = MailWriter.GetConstructor(Flags, null, new[] { typeof(Stream) }, null);
private static readonly MethodInfo CloseMethod = MailWriter.GetMethod("Close", Flags);
private static readonly MethodInfo SendMethod = typeof(MailMessage).GetMethod("Send", Flags);
/// <summary>
/// A little hack to determine the number of parameters that we
/// need to pass to the SaveMethod.
/// </summary>
private static readonly bool IsRunningInDotNetFourPointFive = SendMethod.GetParameters().Length == 3;
/// <summary>
/// The raw contents of this MailMessage as a MemoryStream.
/// </summary>
/// <param name="self">The caller.</param>
/// <returns>A MemoryStream with the raw contents of this MailMessage.</returns>
public static MemoryStream RawMessage(this MailMessage self)
{
var result = new MemoryStream();
var mailWriter = MailWriterConstructor.Invoke(new object[] { result });
SendMethod.Invoke(self, Flags, null, IsRunningInDotNetFourPointFive ? new[] { mailWriter, true, true } : new[] { mailWriter, true }, null);
result = new MemoryStream(result.ToArray());
CloseMethod.Invoke(mailWriter, Flags, null, new object[] { }, null);
return result;
}
}
获取底层MemoryStream:
var email = new MailMessage();
using (var m = email.RawMessage()) {
// do something with the raw message
}
【讨论】:
Send 的附加参数)?在调用CloseMethod之前,我不得不将result的内容复制到另一个MemoryStream,因为当前的实现实际上会关闭底层流。
我见过的代码依赖于反射。我改编了网上找到的示例来创建这个方法:
private static MemoryStream ConvertMailMessageToMemoryStream(MailMessage message)
{
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
Assembly assembly = typeof(SmtpClient).Assembly;
MemoryStream stream = new MemoryStream();
Type mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
ConstructorInfo mailWriterContructor = mailWriterType.GetConstructor(flags, null, new[] { typeof(Stream) }, null);
object mailWriter = mailWriterContructor.Invoke(new object[] { stream });
MethodInfo sendMethod = typeof(MailMessage).GetMethod("Send", flags);
sendMethod.Invoke(message, flags, null, new[] { mailWriter, true }, null);
MethodInfo closeMethod = mailWriter.GetType().GetMethod("Close", flags);
closeMethod.Invoke(mailWriter, flags, null, new object[] { }, null);
return stream;
}
然后您可以将MemoryStream 转换为字符串或您需要的任何内容。
更新:.NET 4.5 中的方法签名已更改,这破坏了上述内容: Getting System.Net.Mail.MailMessage as a MemoryStream in .NET 4.5 beta
【讨论】: