private static void SaveMono(MailMessage message, Stream outputStream)
{
// On Mono the implementation is different, and in some ways even worse than the MS implementation
// so we have to use reflection to replicate the important bits of the SendToFile method
using (var sw = new StreamWriter(outputStream))
using (var client = new SmtpClient())
{
var smtpClientType = typeof(SmtpClient);
var streamField = smtpClientType.GetField("writer", BindingFlags.Instance | BindingFlags.NonPublic);
var boundaryIndexField = smtpClientType.GetField("boundaryIndex", BindingFlags.Instance | BindingFlags.NonPublic);
var sendHeaderMethod = smtpClientType.GetMethod("SendHeader", BindingFlags.Instance | BindingFlags.NonPublic);
var encodeAddressMethod = smtpClientType.GetMethod("EncodeAddress", BindingFlags.Static | BindingFlags.NonPublic);
var encodeAddressesMethod = smtpClientType.GetMethod("EncodeAddresses", BindingFlags.Static | BindingFlags.NonPublic);
var encodeSubjectRFC2047Method = smtpClientType.GetMethod("EncodeSubjectRFC2047", BindingFlags.Instance | BindingFlags.NonPublic);
var addPriorityHeaderMethod = smtpClientType.GetMethod("AddPriorityHeader", BindingFlags.Instance | BindingFlags.NonPublic);
var sendWithoutAttachmentsMethod = smtpClientType.GetMethod("SendWithoutAttachments", BindingFlags.Instance | BindingFlags.NonPublic);
var sendWithAttachmentsMethod = smtpClientType.GetMethod("SendWithAttachments", BindingFlags.Instance | BindingFlags.NonPublic);
streamField.SetValue(client, sw);
sendHeaderMethod.Invoke(
client,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[]
{
HeaderName.Date,
DateTime.Now.ToString("ddd, dd MMM yyyy HH':'mm':'ss zzz", DateTimeFormatInfo.InvariantInfo)
},
null);
var from = encodeAddressMethod.Invoke(null, BindingFlags.Static | BindingFlags.NonPublic, null,
new[] { message.From }, null);
var to = encodeAddressesMethod.Invoke(null, BindingFlags.Static | BindingFlags.NonPublic, null,
new[] { message.To }, null);
sendHeaderMethod.Invoke(
client,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { HeaderName.From, @from },
null);
sendHeaderMethod.Invoke(
client,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { HeaderName.To, to },
null);
if (message.CC.Count > 0)
{
var cc = encodeAddressesMethod.Invoke(null, BindingFlags.Static | BindingFlags.NonPublic, null,
new[] { message.CC }, null);
sendHeaderMethod.Invoke(
client,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { HeaderName.Cc, cc },
null);
}
//TODO: Should probably do BCC here too but mono source code doesn't for some reason? Maybe a bug in mono?
var subject = encodeSubjectRFC2047Method.Invoke(client,
BindingFlags.Instance | BindingFlags.NonPublic, null,
new[] { message }, null);
sendHeaderMethod.Invoke(
client,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { HeaderName.Subject, subject },
null);
foreach (var headerName in message.Headers.AllKeys)
{
sendHeaderMethod.Invoke(
client,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { headerName, message.Headers[headerName] },
null);
}
addPriorityHeaderMethod.Invoke(
client,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { message },
null);
boundaryIndexField.SetValue(client, 0);
if (message.Attachments.Count > 0)
{
sendWithAttachmentsMethod.Invoke(client, BindingFlags.Instance | BindingFlags.NonPublic, null,
new[] { message }, null);
}
else
{
sendWithoutAttachmentsMethod.Invoke(client, BindingFlags.Instance | BindingFlags.NonPublic, null,
new object[] { message, null, false }, null);
}
sw.Flush();
}
}