使用C#SDK时,使用Amazon SES,附件和点填充的双周期问题

时间:2016-12-02 17:11:47

标签: c# amazon-web-services amazon-ses mailmessage

任何使用它的人都知道,要通过带有附件的Amazon SES C#SDK发送电子邮件,您必须使用SendRawEmail功能(非常臭)。为此,您可以手动编写MIME邮件代码,或者将System.Net.Mail.MailMessage对象转换为MemoryStream。这一切都很好,但我遇到了一个问题。经过多次挖掘,我已经能够找到问题并复制它,它似乎是SMTP点填充的副产品。

问题在于,在某些情况下,当MailMessage转换为原始MIME消息时,如果消息正文中的句点被包装到原始消息中的行的开头,那么它是 - 塞满(正确的我假设)。但是,它似乎没有在SDK内部或SES方面处理,因为电子邮件通过双倍期间。这可以通过以下示例控制台应用程序代码复制...

static void Main(string[] args)
{
    var to = new List<string> { _toAddress };
    var subject = "TEST MESSAGE";
    var message = $"This is a carefully crafted HTML email message body such that you should see a single period right here ->. However, you'll see <strong>two periods</strong> in the email instead of one period like originally given in the code.";

    var body = $"<br />Hello,<br /><br />{message}<br /><br />Sincerely,<br /><br />Your Tester";

    var result = SendEmail(to, subject, body, null, isHtml: true);
    Console.WriteLine(result ? "Successfully sent message" : "Failed to send message");

    if (Debugger.IsAttached)
    {
        Console.WriteLine("Press any key to continue...");
        Console.ReadLine();
    }
}

private static bool SendEmail(List<string> to, string subject, string body, List<string> attachmentFilePaths = null, bool isHtml = false)
{
    var message = new MailMessage
    {
        From = new MailAddress(_fromAddress),
        Subject = subject,
        Body = body,
        IsBodyHtml = isHtml
    };

    foreach (var address in to)
    {
        message.To.Add(address.Trim());
    }

    if (attachmentFilePaths?.Any() == true)
    {
        foreach (var filePath in attachmentFilePaths)
        {
            message.Attachments.Add(new Attachment(filePath));
        }
    }

    try
    {
        var creds = new BasicAWSCredentials(_SESAccessKey, _SESSecretKey);
        using (var client = new AmazonSimpleEmailServiceClient(creds, RegionEndpoint.USEast1))
        {
            var request = new SendRawEmailRequest { RawMessage = new RawMessage { Data = ConvertMailMessageToMemoryStream(message) } };
            Console.WriteLine($"RawMessage.Data...\r\n\r\n{Encoding.ASCII.GetString(request.RawMessage.Data.ToArray())}");

            client.SendRawEmail(request);
            return true;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"AmazonSESHelper.SendEmail => Exception: {ex.Message}");
    }

    return false;
}

// Have to do this reflection crap in order to send attachments to the SES API
// From http://stackoverflow.com/questions/29532152/create-mime-mail-with-attachment-for-aws-ses-c-sharp/29533336#29533336
private static MemoryStream ConvertMailMessageToMemoryStream(MailMessage message)
{
    var stream = new MemoryStream();
    var assembly = typeof(SmtpClient).Assembly;
    var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");

    var mailWriterConstructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
    var mailWriter = mailWriterConstructor.Invoke(new object[] { stream });

    var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
    sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true, true }, null);

    var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
    closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);

    return stream;
}

输出的原始MIME消息是......

X-Sender: noreply@bar.com
X-Receiver: foo@bar.com
MIME-Version: 1.0
From: noreply@bar.com
To: foo@bar.com
Date: 2 Dec 2016 11:45:36 -0500
Subject: TEST MESSAGE
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: quoted-printable

<br />Hello,<br /><br />This is a carefully crafted HTML email me=
ssage body such that you should see a single period right here ->=
.. However, you'll see <strong>two periods</strong> in the email i=
nstead of one period like originally given in the code.<br /><br =
/>Sincerely,<br /><br />Your Tester

你可以看到点填充(再次,假设每个SMTP是正确的),但是在发送后它没有完成,因为我收到电子邮件时可以看到......

enter image description here

如果我添加@jstedfast MimeKit(这很棒)我可以使用它,但在我们所有的应用程序中添加了另一个依赖项,这不是我最喜欢的事情。在此之前,我想把它扔出去看看是否有任何我想念的东西。如果没有,那么很高兴看到SES承认这是一个问题并修复它。否则,我必须决定另一个库依赖项或从SES跳转到另一个邮件提供商。

2 个答案:

答案 0 :(得分:0)

事实证明,这是AWS方面的一个问题,但它们不会很快(甚至根本不会)解决。我在GitHub回购中发布了一个问题,如下所示:

https://github.com/aws/aws-sdk-net/issues/501

我已经在MimeKit中添加了我们的应用程序,以通过反射替换转换为mime。新的ConvertMailMessageToMemoryStream是:

private static MemoryStream ConvertMailMessageToMemoryStream(MailMessage message)
{
    var stream = new MemoryStream();
    var mimeMessage = MimeMessage.CreateFromMailMessage(message);
    mimeMessage.Prepare(EncodingConstraint.None);
    mimeMessage.WriteTo(stream);
    return stream;
}

答案 1 :(得分:0)

我遇到了同样的问题,但是能够通过将MailMessage主体编码设置为UTF-8来修复它,然后再作为RawEmail发送

mail.BodyEncoding = System.Text.Encoding.UTF8;

(见System.Net.Mail creating invalid emails and eml files? Inserting extra dots in host names