【问题标题】:C# MailMessage to stream - encoding issueC# MailMessage 流式传输 - 编码问题
【发布时间】:2014-11-25 01:53:53
【问题描述】:

我正在使用 Amazon SES SendRawEmail API,因此我需要一个 MailMessage 作为 Memorystream。

我在 stackoverflow 上找到了多个 MailMessage to MemoryStream 问题的答案。

解决方案 1: 使用私有方法会导致电子邮件部分编码错误: https://stackoverflow.com/a/8826833

解决方案 2: 使用此解决方案没有编码问题,您将其发送到拾取目录,然后将其读回: https://stackoverflow.com/a/14350088

我非常不喜欢我需要写入一个临时文件才能使其正常工作的事实。 有谁知道纯 MemoryStream 解决方案如何弄乱一些编码。

我正在测试的邮件是这样的:

var mailMessage = new MailMessage();
mailMessage.Subject = "HEADER WITH SPECIAL ÆØÅ";
mailMessage.Body = "TEST";

Attachment att = new Attachment(@"C:\AttachmentWithSpecial ÆØÅ.pdf");
mailMessage.Attachments.Add(att);
mailMessage.From = new MailAddress("test@test.com", "NameÆØÅ");
mailMessage.To.Add(new MailAddress("test@test.com", "NameÆØÅ"));

总结一下:

  • 如果我使用标准 SMTP 发送此消息,它看起来不错。
  • 如果我使用 SendRawEmail 发送它,如果我使用解决方案 2 生成内存流看起来不错
  • 如果我使用 SendRawEmail 发送它,如果我使用解决方案 1 生成内存流,则会出现编码问题。

由于编码问题,我的意思是“ø”显示为

【问题讨论】:

  • 为什么不使用 SendEmail 代替? SES 允许您撰写电子邮件,并且确实支持编码。
  • 据我所知,它不支持附件。 ?
  • 哦,是的,您尝试过使用 StringWriter 吗? Memory Stream 可能会忽略编码,因为它使用字节作为存储。
  • 您能否提供不涉及 Amazon API 的最小示例?就像生成的示例一样,有两个不同的内存流,其中一个是正确的(对于SendRawEmail),另一个不是。

标签: c# .net amazon-web-services


【解决方案1】:

不幸的是,MailMessage 对象有问题并且界面很差。

好消息是 .NET 4.5 在 Send() 中使用 allowUnicode 标志部分修复了它(不幸的是,Send 方法仍然是私有的)

以下是修改后的“解决方案1”。 它以与“解决方案 2”相同的方式对主题进行编码。 仅限 .NET Framework 4.5。

private static MemoryStream ConvertMailMessageToMemoryStream(MailMessage message)
{
    Assembly systemAssembly = typeof(SmtpClient).Assembly;
    Type mailWriterType = systemAssembly.GetType("System.Net.Mail.MailWriter");
    const BindingFlags nonPublicInstance = BindingFlags.Instance | BindingFlags.NonPublic;
    ConstructorInfo mailWriterContructor = mailWriterType.GetConstructor(nonPublicInstance, null, new[]  typeof(Stream) }, null);

    MethodInfo sendMethod = typeof(MailMessage).GetMethod("Send", nonPublicInstance);
    MethodInfo closeMethod = mailWriterType.GetMethod("Close", nonPublicInstance);
    using (MemoryStream memoryStream = new MemoryStream())
    {
        object mailWriter = mailWriterContructor.Invoke(new object[] { memoryStream });
        //AssertHelper.IsTrue(sendMethod.GetParameters().Length > 2, ".NET framework must be 4.5 or higher in order to properly encode email subject.");
        sendMethod.Invoke(message, nonPublicInstance, null,
            new[] { mailWriter, true, false },
            null);
        closeMethod.Invoke(mailWriter, nonPublicInstance, null, new object[] { }, null);
        return memoryStream;
    }
}

【讨论】:

    【解决方案2】:

    您是否尝试明确指定主题/正文和邮件地址的编码?

    我猜想当 .NET 将邮件写入文件夹时,它可以以某种方式定义正确的编码(或者文件阅读器可能会以某种方式找到正确的编码来转换数据)。在内存中,所有内容都采用默认编码,这对您不起作用。

    【讨论】:

    • 是的,我试过了,但是 .NET 我实际上非常聪明地在必要时将这些设置为 UTF-8。在邮件地址的构造函数中,您会发现: this.displayNameEncoding = displayNameEncoding ?? Encoding.GetEncoding("utf-8");这意味着如果您不定义编码,它将默认为 UTF-8。在主题和正文的集合中,他们有代码测试字符串是否仅包含 ascii,否则它将尝试自行猜测编码。所以如果你做 mail.Subject = "æøå";然后检查 mail.SubjectEncoding 它是否正确已经是 UTF-8
    【解决方案3】:
    message.BodyEncoding = message.SubjectEncoding = message.HeadersEncoding = Encoding.UTF8;
    

    【讨论】:

      猜你喜欢
      • 2011-01-25
      • 1970-01-01
      • 2016-05-03
      • 2019-05-19
      • 2016-03-24
      • 1970-01-01
      • 1970-01-01
      • 2013-04-08
      • 1970-01-01
      相关资源
      最近更新 更多