1

Using this SO post (Convert MailMessage to Raw text), we were able to get the MailMessage as a stream. However, the Bcc is removed. Both To and CC still work, but not Bcc.

Why would it be removed, and how can it be kept in?

Community
  • 1
  • 1
scojomodena
  • 842
  • 1
  • 14
  • 24
  • I did the above code in C#. Please see my post at http://stackoverflow.com/questions/38794401/aws-ses-sendrawemailasync-not-entertaining-bcc – Satinder Sidhu Aug 07 '16 at 04:58

2 Answers2

2

Pretty sure the BCC field never gets sent along with the message.

The BCC field is used to send "Blind Carbon Copies" to recipients. From WikiPedia:

In the context of correspondence, blind carbon copy (abbreviated Bcc:) allows the sender of a message to conceal the person entered in the Bcc: field from the other recipients.

If the recipients in the BCC field were actually contained in the raw SMTP text of the email, then this guarantee could not be enforced.

The method you linked to in your question is more than likely used by SmtpClient to prepare the message for transmission. As such, it would have to ignore the BCC field in order to maintain the expected behavior.

To actually keep it in, you would have to manually insert it into the output text:

var email = new MailMessage();
using (var reader = new StreamReader(email.RawMessage())) 
using (var writer = new StringWriter()) {
    while(true) {
        var line = reader.ReadLine();
        if (line == null) break; // EOF

        if (line != "") { 
            // Header line
            writer.WriteLine(line);
            continue;
        }

        // End of headers, insert bcc, read body, then bail
        writer.WriteLine("Bcc: " + email.Bcc.ToString()); // or however you want to format it
        writer.WriteLine("");
        writer.Write(reader.ReadToEnd());
        break;
    }

    var messageText = writer.ToString();
    // Do something with message text which now has Bcc: header
}
rossipedia
  • 56,800
  • 10
  • 90
  • 93
  • Now that you mention it, that does sort of make sense. The SmtpClient.Send() method is going to strip out the BCC. We are sending this to Amazon SES via the SendRawEmail() method. Instead, I guess I'll just manually create the MIME message string, create the stream, and be done. Just to clarify, If you send the BCC to SES, it DOES do it properly. – scojomodena Dec 13 '13 at 18:47
  • 1
    Probably because it uses the BCC in the actual SMTP envelope (which isn't part of the message headers/body), during the `RCPT TO: ` interchange. – rossipedia Dec 13 '13 at 18:50
2

Here's my VB.NET rehash of RawMessage() which includes BCC in the headers. Based on someone else's rehash of the original SO link: http://colinmackay.co.uk/2011/11/10/sending-more-than-a-basic-email-with-amazon-ses

Public Class BuildRawMailHelper
    Private Const nonPublicInstance As BindingFlags = BindingFlags.Instance Or BindingFlags.NonPublic

    Private Shared ReadOnly _mailWriterContructor As ConstructorInfo
    Private Shared ReadOnly _sendMethod As MethodInfo
    Private Shared ReadOnly _closeMethod As MethodInfo
    Private Shared ReadOnly _writeHeadersMethod As MethodInfo

    Shared Sub New()
        Dim systemAssembly As Assembly = GetType(SmtpClient).Assembly
        Dim mailWriterType As Type = systemAssembly.[GetType]("System.Net.Mail.MailWriter")

        _mailWriterContructor = mailWriterType.GetConstructor(nonPublicInstance, Nothing, {GetType(Stream)}, Nothing)

        _sendMethod = GetType(MailMessage).GetMethod("Send", nonPublicInstance)

        _closeMethod = mailWriterType.GetMethod("Close", nonPublicInstance)

        _writeHeadersMethod = mailWriterType.GetMethod("WriteHeaders", nonPublicInstance)
    End Sub

    Public Shared Function ConvertMailMessageToMemoryStream(message As MailMessage) As MemoryStream
        Using memoryStream As New MemoryStream()
            Dim mailWriter As Object = _mailWriterContructor.Invoke(New Object() {memoryStream})

            ' BCC is not output in headers by Send method, so we add it in manually
            If message.Bcc.Any Then
                Dim bccHeaders As New NameValueCollection()
                bccHeaders.Add("BCC", String.Join(", ", message.Bcc.Select(Function(x) x.ToString())))
                _writeHeadersMethod.Invoke(mailWriter, nonPublicInstance, Nothing, {bccHeaders, False}, Nothing)
            End If

            ' See http://stackoverflow.com/questions/9595440/getting-system-net-mail-mailmessage-as-a-memorystream-in-net-4-5-beta
            _sendMethod.Invoke(message, nonPublicInstance, Nothing, {mailWriter, True, True}, Nothing)

            _closeMethod.Invoke(mailWriter, nonPublicInstance, Nothing, {}, Nothing)

            Return memoryStream
        End Using
    End Function
End Class
extremeandy
  • 503
  • 3
  • 13