【问题标题】:Convert MailMessage to Raw text将 MailMessage 转换为原始文本
【发布时间】:2011-11-22 20:20:39
【问题描述】:

是否有任何简单的方法可以将 System.Net.Mail.MailMessage 对象转换为原始邮件消息文本,例如在记事本中打开 eml 文件时。

【问题讨论】:

    标签: c# .net


    【解决方案1】:
    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);
    

    【讨论】:

    • 我不确定这个答案是否真的添加了任何没有解释的东西。
    【解决方案2】:

    我在MimeKit 中实现了逻辑,允许您将 System.Net.Mail.MailMessage 转换为MimeKit.MimeMessage。完成后,您可以简单地将消息写入流:

    var message = (MimeMessage) CreateSystemNetMailMessage ();
    using (var stream = File.Create ("C:\\message.eml"))
        message.WriteTo (stream);
    

    这不需要反映到内部方法中,这意味着它不依赖于运行时,使其比迄今为止给出的其他答案更具可移植性。

    【讨论】:

    • 我注意到反射方法没有让我的 SubjectEncoding (UTF8) 正确地通过 Amazon SES 发送。 Mimekit 可以。谢谢!
    • 太棒了!很高兴 MimeKit 有帮助!
    • 看起来你是just mapping by hand,可以这么说吧?并不是说这非常糟糕或破坏交易,但如果我没有错过任何东西,理论上它是有损的。 (??) (现在正在尝试将我的代码调整到 MonoMac,并且即将放弃并自己手动进行映射。)
    • 是的,它只是手工映射,但它应该是完整的。显然,映射作为长期解决方案并不理想,因此我建议使用 MimeKit 构建消息作为长期解决方案,但如果您在短期内增量移植 SNMail 代码,映射方法很有用。 .. 如果这有意义的话。
    • 哦,如果您需要 SMTP,我有一个名为 MailKit 的库,它在 MimeKit 之上添加了 SMTP、POP3 和 IMAP 支持。
    【解决方案3】:

    这是相同的解决方案,但作为MailMessage 的扩展方法。

    通过在静态上下文中抓取ConstructorInfoMethodInfo 成员一次,可以最大限度地减少一些反射开销。

    /// <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
    }
    

    【讨论】:

    • 这在您的 PC 上的 .NET 4.5 中是否有效(使用 Send 的附加参数)?在调用CloseMethod之前,我不得不将result的内容复制到另一个MemoryStream,因为当前的实现实际上会关闭底层流。
    • 这适用于 .NET 4.0——我还没有在 4.5 中尝试过。我很乐意将您的更新包含在我的回答中(当然,也感谢您)。
    • 是的,它应该像那样工作,但我还添加了对 .NET 4.5 的检查。如果您同意,我可以用有效的方法更新答案?
    • 仅供参考,我注意到 Send 方法实际上去除了 BCC,因为它正在准备发送。如果您只是要将其传递给 Amazon SES 或其他类型的服务,那不是您想要的。我最终只是手动创建了 MIME 字符串。
    • @allonhadaya,似乎答案没有返回非 ASCII 字符的 MIME encoded-word syntax
    【解决方案4】:

    我见过的代码依赖于反射。我改编了网上找到的示例来创建这个方法:

        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

    【讨论】:

      猜你喜欢
      • 2017-07-04
      • 1970-01-01
      • 1970-01-01
      • 2010-11-03
      • 1970-01-01
      • 2011-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多