Converting MailMessage to Stream removes Bcc

1.7k views Asked by At

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?

2

There are 2 answers

2
rossipedia On BEST ANSWER

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
}
1
extremeandy On

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