Send html email message and plainText as alternative - c#

using (MailMessage message = new MailMessage()) // using System.Net.Mail;
{
string mailFrom = "sender#email.si";
string smtpServer = "smtp.server.net";
message.From = new MailAddress(mailFrom);
message.To.Add("xxx#gmail.com");
message.Subject = "subject";
message.SubjectEncoding = Encoding.UTF8;
message.IsBodyHtml = true;
message.Body = "<h1>VODA</h1>";
message.BodyEncoding = Encoding.UTF8;
AlternateView plainView = AlternateView.CreateAlternateViewFromString("test content", Encoding.UTF8, "text/plain");
message.AlternateViews.Add(plainView);
SmtpClient smtpClient = new SmtpClient(smtpServer);
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = new System.Net.NetworkCredential("user", "pass");
smtpClient.EnableSsl = true;
smtpClient.Port = 587;
smtpClient.Send(message);
}
When looking what was received at gmail I see next:
Subject: subject
Content-Type: multipart/alternative; boundary=--boundary_0_989afdbb-5fe4-4155-ba59-3d5ffdbb909e
Message-Id: <20161208131903.36280C956C#in-1.mail.xxx.net>
----boundary_0_989afdbb-5fe4-4155-ba59-3d5ffdbb909e
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: base64
PGgxPlZPREE8L2gxPg==
----boundary_0_989afdbb-5fe4-4155-ba59-3d5ffdbb909e
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: base64
dGVzdCBjb250ZW50
----boundary_0_989afdbb-5fe4-4155-ba59-3d5ffdbb909e--
Why System.Net.Mail.MailMessage doesn't set text/html contect type?
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: base64
PGgxPlZPREE8L2gxPg==
Is there any additional MailMessage property I missed?

When you are using AlternateViews the Body is expected to be text/plain and the AlternateViews to deliver different content types. From the documentation (https://msdn.microsoft.com/en-us/library/system.net.mail.mailmessage.alternateviews.aspx):
To add an alternate view to a MailMessage object, create an Attachment for the view, and then add it to the collection returned by AlternateViews. Use the Body property to specify the text version and use the AlternateViews collection to specify views with other MIME types.

Answer is written in this post: GMail displays plain text email instead HTML
Try switching the order of the parts of the message, putting the HTML part after the plain-text part. It might work :).
NOTE: I cannot remember now where I read this (or if I for sure even did), but the reason switching might help is because I think the preferred part of the message may be the last part.
Update: I found a place where it says that parts in a multipart MIME message should be in order of increasing preference -- here, in section 7.2.3, starting with the third to last paragraph.
After adding text/html after text/plain gmail shows html content. Microsoft Exchange although does show html version of the message and it doesn't mind the order in which version are added.
AlternateView plainView = AlternateView.CreateAlternateViewFromString("test content", Encoding.UTF8, "text/plain");
message.AlternateViews.Add(plainView);
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlContent, Encoding.UTF8, "text/html");
message.AlternateViews.Add(htmlView);

Related

C# mailing with BCC to PHP ready mail server using Custom Headers

Got an issue about C# mailing.
According to rfc format has no problem when BCC added to the custom header!
However according to MSDN BCC info that is added to custom header will be deleted!
So in this particular situation I have to send an email trough C# code to a server that accepts BCC info in the custom header only...
How can I achive that? So far what I've tried is below;
// Mail Configurations
MailMessage mail = new MailMessage();
mail.DeliveryNotificationOptions = DeliveryNotificationOptions.None;
mail.Priority = MailPriority.Normal;
mail.BodyEncoding = System.Text.Encoding.UTF8;
mail.HeadersEncoding = System.Text.Encoding.UTF8;
mail.SubjectEncoding = System.Text.Encoding.UTF8;
mail.BodyTransferEncoding = System.Net.Mime.TransferEncoding.Base64;
mail.From = new MailAddress(FROM, FROM, System.Text.Encoding.UTF8); // From
mail.To.Add(new MailAddress(TO, TO, System.Text.Encoding.UTF8)); // EmailTo
// mail.CC.Add(new MailAddress(CC, CC, System.Text.Encoding.UTF8)); // CC
// mail.Bcc.Add(new MailAddress(BCC, BCC, System.Text.Encoding.UTF8)); // BCC
mail.Headers.Add("BCC", BCC); // BCC 2nd method adding in headers as PHP does
mail.Subject = Subject;
mail.IsBodyHtml = true;
mail.Body = "<div>Hello World!<div>";
mail.Attachments.Add(new Attachment(FileName));
// SMTP Configurations
SmtpClient SmtpServer = new SmtpClient(SMTP, PORT);
SmtpServer.UseDefaultCredentials = false;
SmtpServer.DeliveryFormat = SmtpDeliveryFormat.International;
SmtpServer.DeliveryMethod = SmtpDeliveryMethod.Network;
SmtpServer.EnableSsl = true;
SmtpServer.Credentials = new NetworkCredential(SMTPUser, SMTPPass);
// Send Mail
SmtpServer.Send(mail);
// Clear All
mail.To.Clear();
mail.Bcc.Clear();
mail.Headers.Clear();
mail.Attachments.Clear();
Edit: Depending on the comments I've also tried MailKit library.
It had no effect on BCC the code I've used is;
// Mail
var message = new MimeMessage();
message.From.Add(new MailboxAddress(System.Text.Encoding.UTF8, FROMName, FROM));
message.To.Add(new MailboxAddress(System.Text.Encoding.UTF8, TO, TO));
message.Cc.Add(new MailboxAddress(System.Text.Encoding.UTF8, CC, CC));
message.Bcc.Add(new MailboxAddress(System.Text.Encoding.UTF8, BCC, BCC));
message.Subject = Subject;
message.Priority = MessagePriority.Normal;
message.Importance = MessageImportance.Normal;
message.XPriority = XMessagePriority.Normal;
// With Body Builder
var builder = new BodyBuilder();
builder.HtmlBody = "<div> Hello World! </div>"; // Set the html version of the message text
builder.Attachments.Add(FileName); // We may also want to attach some files
message.Body = builder.ToMessageBody(); // Now we just need to set the message body and we're done
// SMTP connect
using (var client = new MailKit.Net.Smtp.SmtpClient())
{
client.Connect(SMTP, SMTPPort, false);
// Note: only needed if the SMTP server requires authentication
client.Authenticate(SMTPUser, SMTPPass);
client.Send(message);
client.Disconnect(true);
}
I'm not sure if I'm following along correctly, but it sounds like you need to send a message where the raw Bcc: header is sent in the headers to the SMTP server?
This is highly non-standard and very suspect since the whole point of the Bcc: header is that it gets stripped at send time because recipients in the Bcc: header field are meant to be BLIND Carbon Copy recipients (aka, hidden to everyone who receives the message).
That said... if you REALLY REALLY do need to include the Bcc: header in the message data that gets uploaded to the SMTP server, then you can do this:
var options = FormatOptions.Default.Clone ();
options.HiddenHeaders.Add (HeaderId.ContentLength);
options.HiddenHeaders.Remove (HeaderId.ResentBcc);
options.HiddenHeaders.Remove (HeaderId.Bcc);
options.NewLineFormat = NewLineFormat.Dos;
client.Send (options, message);
Note: Currently the Resent-Bcc and Bcc headers are not hidden in the default FormatOptions, I just added those .Remove() calls to illustrate how to control which headers get hidden vs not.
The SmtpClient.Send() methods that do not take a FormatOptions argument use an internal FormatOptions that add the Bcc, Resent-Bcc, and Content-Length headers to the hidden list.

Adding Content-Description to email in .NET

I'm trying to set a MIME Content-Description field in an email. I set the Content-Type and the Content-Tranfer-Encoding using an AlternateView, but I can find no way to add Content-Description.
What I can do is set Content-Description using a custom header, but this appears to insert a single Content-Description for the entire email, rather than for the MIME object.
using( MailMessage mailMessage = new MailMessage() )
{
mailMessage.From = new MailAddress( _configuration.FromAddress );
mailMessage.BodyEncoding = Encoding.UTF8;
mailMessage.To.Add( to );
mailMessage.Subject = subject;
// add the MIME data
var irisB2View = AlternateView.CreateAlternateViewFromString( body );
irisB2View.ContentType = new ContentType( "Application/EDI-consent" ); // Content-Type
irisB2View.TransferEncoding = TransferEncoding.Base64; // Content-Tranfer-Encoding
mailMessage.AlternateViews.Add( irisB2View );
// this adds Content-Description, but it appears before the MIME data
mailMessage.Headers.Add( "Content-Description", "IRIS/B2/Z" );
client.Send( mailMessage );
}
This results in an email of the form below, with Content-Description before the MIME object:
Content-Description: IRIS/B2/Z
MIME-Version: 1.0
From: xxxxxx#xxxxxx.xx
To: xxxxxx#xxxxxx.xx
Date: 28 Sep 2018 13:49:51 +0200
Subject: subject
Content-Type: Application/EDI-consent
Content-Transfer-Encoding: base64
Does anybody know how I can manage to get the Content-Description into the MIME content?
Equally, the mail has no boundaries (I only have one MIME object), so does it actually matter that the Content-Description is before the MIME object?
Thanks in advance.
RFC 2045 specifies that in a single part message the MIME header fields are used in the context of a regular RFC 822 header. RFC 822 does not impose a sequence on header fields. Therefore the placement of the Content-Description field does not matter.

mimekit outlook show text as attachment

I have a word document and using Aspose.Word to perform a mail merge and save the result to a memory stream as mhtml (part of my code):
Aspose.Words.Document doc = new Aspose.Words.Document(documentDirectory + countryLetterName);
doc.MailMerge.Execute(tempTable2);
MemoryStream outStream = new MemoryStream();
doc.Save(outStream, Aspose.Words.SaveFormat.Mhtml);
Then I use MimeKit (latest version from NuGet) to send my message:
outStream.Position = 0;
MimeMessage messageMimeKit = MimeMessage.Load(outStream);
messageMimeKit.From.Add(new MailboxAddress("<sender name>", "<sender email"));
messageMimeKit.To.Add(new MailboxAddress("<recipient name>", "<recipient email>"));
messageMimeKit.Subject = "my subject";
using (var client = new MailKit.Net.Smtp.SmtpClient())
{
client.Connect(<smtp server>, <smtp port>, true);
client.Authenticate("xxxx", "pwd");
client.Send(messageMimeKit);
client.Disconnect(true);
}
When opening the received email in my mail web client, I see the text (with image) and the image as attachment.
When opening the received email in Outlook (2016), the mail body is empty and I have two attachments, 1 with the text and 1 with the image.
Looking at the mht contents itself, it looks like:
MIME-Version: 1.0
Content-Type: multipart/related;
type="text/html";
boundary="=boundary.Aspose.Words=--"
This is a multi-part message in MIME format.
--=boundary.Aspose.Words=--
Content-Disposition: inline;
filename="document.html"
Content-Type: text/html;
charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Location: document.html
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html; charset=
=3Dutf-8" /><meta http-equiv=3D"Content-Style-Type" content=3D"text/css" />=
<meta name=3D"generator" content=3D"Aspose.Words for .NET 14.1.0.0" /><titl=
e></title></head><body>
*****body removed *****
</body></html>
--=boundary.Aspose.Words=--
Content-Disposition: inline;
filename="image.001.jpeg"
Content-Type: image/jpeg
Content-Transfer-Encoding: base64
Content-Location: image.001.jpeg
****image content remove****
--=boundary.Aspose.Words=----
Is there some formatting or so I have to do to get this correctly shown in Outlook? Or is it caused by the "3D"-keywords found, like content=3D"xxxx", style=3D"xxxx"?
Thanks in advance.
Edward
The =3D bits are the quoted-printable encoding of the = character. Since the headers properly declare the Content-Transfer-Encoding to be quoted-printable, that's not the problem.
Here are some suggestions on trying to massage the content into something that will work in Outlook (Outlook is very finicky):
MimeMessage messageMimeKit = MimeMessage.Load(outStream);
messageMimeKit.From.Add(new MailboxAddress("<sender name>", "<sender email"));
messageMimeKit.To.Add(new MailboxAddress("<recipient name>", "<recipient email>"));
messageMimeKit.Subject = "my subject";
var related = (MultipartRelated) messageMimeKit.Body;
var body = (MimePart) related[0];
// It's possible that the filename on the HTML body is confusing Outlook.
body.FileName = null;
// It's also possible that the Content-Location is confusing Outlook
body.ContentLocation = null;

Programmatically-generated, digitally signed email appears correct in Outlook, but not in Gmail

I'm using C#, .NET 4.0 to send a digitally-signed email, like so:
private void SendMailMessage(string emailTo)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(fromAddress);
message.To.Add(new MailAddress(emailTo));
message.Subject = "Regarding your lottery winnings";
message.IsBodyHtml = false;
string body = "Content-Type: text/plain;charset=\"iso-8859-1\"\nContent-Transfer-Encoding: quoted-printable\n\nThe URL to your secret is: " + url + "\nIt can only be viewed once.";
byte[] messageBytes = Encoding.ASCII.GetBytes(body);
ContentInfo content = new ContentInfo(messageBytes);
SignedCms signedCms = new SignedCms(content, false);
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, emailCert);
signedCms.ComputeSignature(Signer);
byte[] signedBytes = signedCms.Encode();
MemoryStream ms = new MemoryStream(signedBytes);
AlternateView av = new AlternateView(ms, "application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
message.AlternateViews.Add(av);
SmtpClient client = new SmtpClient(smtpServer, int.Parse(smtpServerPort));
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Send(message);
message.Dispose();
client = null;
}
Notice that message.Body is left blank, and only the AlternateView is added to the email. When I send this email and view it in Outlook, it shows up perfectly, with a certificate icon on the email message, and the S/MIME Outlook extensions validate the signature successfully and automatically.
Aces.
(If I add anything to message.Body, it breaks. Outlook no longer recognizes it as a signed email and I only see the message.Body text, not the AlternateView.)
But if I send this email to a Gmail address, for instance, it shows up as a blank email with smime.p7m as an attachment, and inside it I see the text of the email, but it's surrounded by what looks like a ton of binary gibberish.
Is there a way to make this digitally signed email compatible with both an Outlook client and a Gmail web client?
When outlook generates a signed email it adds an alternate view with the signed message, another alternate view with the html version and then another alternate view with a plain text version. I think if you also do this then it will work in most all email clients.
there is a plain text alternate view that is not signed
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
there is an html version that is not signed
Content-Type: text/html;
charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
There is a signed alternate view
Content-Type: application/pkcs7-signature;
name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="smime.p7s"

Attachment order sent by SmtpClient is incorrect when using 'Name' property

Can anyone recreate this issue? It seems to me like a quite serious bug in SmtpClient (.NET 4.0) but I can't believe no one has seen this before and Google doesn't seem to show anyone seeing a similar issue.
When sending an email with more than 1 attachment and the 'Attachment.Name' property is used, the attachments will have the incorrect names (e.g. 2 attachments will have their names swapped). The work around (and actually probably the correct property to set) is to use ContentDisposition.FileName. But I would be very interested if this happens for everyone. Can anyone recreate this issue? It seems to me like a quite serious bug in SmtpClient (.NET 4.0) but I can't believe no one has seen this before and Google doesn't seem to show anyone seeing a similar issue. You'll need to create a couple of zip files in c:\tmp\emailin\
var zipCt = new ContentType { MediaType = MediaTypeNames.Application.Zip };
var attachmentA = new Attachment(#"c:\tmp\emailin\a.zip", zipCt);
attachmentA.ContentDisposition.FileName = "a.zip";
attachmentA.Name = "a.zip";
var attachmentB = new Attachment(#"c:\tmp\emailin\b.zip", zipCt);
attachmentB.ContentDisposition.FileName = "b.zip";
attachmentB.Name = "b.zip";
var msg = new MailMessage("testfrom#example.com", "testto#example.com")
{
Body = "body",
Subject = "subject"
};
msg.Attachments.Add(attachmentA);
msg.Attachments.Add(attachmentB);
using (var smtp = new SmtpClient())
{
smtp.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
smtp.PickupDirectoryLocation = #"c:\tmp\emailout\";
smtp.Send(msg);
}
If you now look at the eml file in c:\tmp\emailout\ you will see something like
X-Sender: testfrom#example.com
X-Receiver: testto#example.com
MIME-Version: 1.0
From: testfrom#example.com
To: testto#example.com
Date: 11 Apr 2012 12:36:48 +0100
Subject: subject
Content-Type: multipart/mixed; boundary=--boundary_0_1b7bb1ee-ba28-4258-b662-554adb7ff81a
----boundary_0_1b7bb1ee-ba28-4258-b662-554adb7ff81a
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
body
----boundary_0_1b7bb1ee-ba28-4258-b662-554adb7ff81a
Content-Type: application/zip; name=b.zip
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=a.zip
UEsDBAoAAAAAAG5ki0AAAAAAAAAAAAAAAAAFAAAAYS50eHRQSwECPwAKAAAAAABu
ZItAAAAAAAAAAAAAAAAABQAkAAAAAAAAACAAAAAAAAAAYS50eHQKACAAAAAAAAEA
GADa2JQw1xfNAdrYlDDXF80B2tiUMNcXzQFQSwUGAAAAAAEAAQBXAAAAIwAAAAAA
----boundary_0_1b7bb1ee-ba28-4258-b662-554adb7ff81a
Content-Type: application/zip; name=a.zip
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=b.zip
UEsDBAoAAAAAAHZki0AAAAAAAAAAAAAAAAAFAAAAYi50eHRQSwECPwAKAAAAAAB2
ZItAAAAAAAAAAAAAAAAABQAkAAAAAAAAACAAAAAAAAAAYi50eHQKACAAAAAAAAEA
GAD67/k51xfNAfrv+TnXF80B2tiUMNcXzQFQSwUGAAAAAAEAAQBXAAAAIwAAAAAA
----boundary_0_1b7bb1ee-ba28-4258-b662-554adb7ff81a--
Note how the Content-Type: and Content-Disposition: file names do not match for each attachment.
Am I doing something wrong? Is this a bug that I should log with MS?
This is because you require a new instance of ContentType for each attachment.
var zipCt = new ContentType { MediaType = MediaTypeNames.Application.Zip };
var zipCt2 = new ContentType { MediaType = MediaTypeNames.Application.Zip };
var attachmentA = new Attachment(#"c:\tmp\emailin\a.zip", zipCt);
attachmentA.ContentDisposition.FileName = "a.zip";
attachmentA.Name = "a.zip";
var attachmentB = new Attachment(#"c:\tmp\emailin\b.zip", zipCt2);
attachmentB.ContentDisposition.FileName = "b.zip";
attachmentB.Name = "b.zip";
Should fix your issue.

Categories