2016-12-02 9 views
1

因爲任何與之合作的人都知道,要通過帶有附件的Amazon SES C#SDK發送電子郵件,您必須使用SendRawEmail函數(其中非常臭)。爲此,您要麼手動編碼MIME郵件,要麼將其轉換爲MemoryStream。這一切工作正常,但我遇到了一個問題。經過多次挖掘,我已經能夠找到問題並複製它,並且它似乎是SMTP點填充的副產品。使用C#SDK時使用亞馬遜SES,附件和點填充技術的雙期問題

問題是,在某些情況下,當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: [email protected] 
X-Receiver: [email protected] 
MIME-Version: 1.0 
From: [email protected] 
To: [email protected] 
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到另一個郵件提供者。

回答

0

事實證明這是AWS方面的一個問題,但他們不會很快(甚至根本不會)解決問題。我張貼的問題到GitHub庫作爲可以在這裏看到:

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

因爲我已經加入到MimeKit我們的應用程序,以取代通過反射默轉換。新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; 
}