Although the vast majority of email users prefer their messages in HTML format, a few die-hards out there still prefer plain text. My wife is one of those people. In certain circumstances, a plain-text bias is perfectly understandable. For example, in Susie’s case, she has to respond to a lot of contact form messages that we get from our various web sites. If she replies to an HTML message that has no plain text component, her email program doesn’t include the original message body, mainly because she has her program configured to use plain text mode when composing messages.
Sending your messages in both HTML and plain text format has good business arguments going for it. For one thing, it is a simple courtesy to your recipients. For another, your messages may receive a higher spam index if you send them in HTML format only. That alone is reason enough to consider sending "multi-part" messages with both formats.
A Sample SendMultiPartMessage Method
Fortunately, sending multi-part messages with Microsoft .NET is fairly easy, once you figure out how it is done. This article presents a technique I developed recently for our Self-Publishers Online Conference web site, which has to send several varieties of email. Since my wife receives the emailed contact forms from the site, she requested that the messages include plain text.
I encapsulated the core logic for sending a multi-part message into a static method of a utility class in my project. Here’s what the method looks like:
public static void SendMultiPartMessage( SmtpClient smtp, String sender, String recipients, String subject, String textBody, String htmlBody) { // Create an SmtpClient instance if needed: if (smtp == null) { smtp = new SmtpClient( WebConfigurationManager.AppSettings["SMTPServerAddress"]); } // Initialize the message with the plain text body: MailMessage msg = new MailMessage( sender, recipients, subject, textBody); // Convert the html body to a memory stream: Byte[] bytes = System.Text.Encoding.UTF8.GetBytes(htmlBody); MemoryStream htmlStream = new MemoryStream(bytes); // Add the HTML body to the message: AlternateView htmlView = new AlternateView( htmlStream, MediaTypeNames.Text.Html); msg.AlternateViews.Add(htmlView); // Ship it! smtp.Send(msg); htmlView.Dispose(); htmlStream.Dispose(); }
To get the code to work, you’ll also need the following using statements in your class:
using System.IO; using System.Net.Mime; using System.Net.Mail;
Create an SmtpClient Instance
The method sends email using the System.Net.Mail.SmtpClient class. The method lets you pass a pre-configured SmtpClient instance as a parameter, or it will create a new instance for you if you pass null. It gets the email server IP address or domain name from an application setting named "SMTPServerAddress."
Initialize a MailMessage Instance
Next, the method allocates an instance of the System.Net.Mail.MailMessage class. It initializes the MailMessage instance with the sender and recipient email addresses, the message subject, and the plain text body. Incidentally, the default message body format is plain text.
You can specify multiple recipient email addresses if you want to do so. Just pass a comma-delimited string of email addresses to the method, which is a format supported by the MailMessage class.
Attach the HTML Message Body
The next part is where things get interesting, and where I had to spend the bulk of my time researching the right technique. Unfortunately, the Visual Studio documentation gives you bad information on the subject, as I’ll explain in a moment.
To create a multi-part message, you attach "alternate views" to your email message. Alternate views are a special kind of attachment, but you work with them through AlternateViews collection.
The Visual Studio documentation for the AlternateView class would have you believe that you can just pass the HTML body to the constructor, but that is not true. The constructors that take a string parameter expect the string to contain a file path. If you pass your HTML body directly to the constructor, you get the following error:
Illegal characters in path.
Now, if your HTML message body were located in a file, you could pass the file name to the AlternateView constructor and everything would be fine. However, I’m getting the message text from a String parameter.
If you can’t use the String-based constructors, what do you do instead? Well, you have two options. First, certain overloads of the AlternateView constructor accept a Stream. Since the HTML body comes into the SendMultiPartMessage method as a String parameter, you have to convert the string to a stream of some kind. Since all of the work is taking place in memory, it made sense for me to use a MemoryStream object.
The method accomplishes this feat with two simple lines, which could even be collapsed into a single line:
// Convert the html body to a memory stream: Byte[] bytes = System.Text.Encoding.UTF8.GetBytes(htmlBody); MemoryStream htmlStream = new MemoryStream(bytes);
These lines initialize a MemoryStream object with a byte array containing the HTML message body. I used UTF8 encoding, which is common for HTML files.
Once you have a MemoryStream, you can allocate and attach the HTML alternate view:
// Add the HTML body to the message: AlternateView htmlView = new AlternateView( htmlStream, MediaTypeNames.Text.Html); msg.AlternateViews.Add(htmlView);
Your second (and easier) choice is to use a static method on the AlternateView class that does some of this work for you [thanks to Peter Andersson for suggesting this alternative]:
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString( htmlBody, System.Text.Encoding.UTF8, MediaTypeNames.Text.Html));
All you need to do from there is send the message!
Customizing the Method
The SendMultiPartMessage method is not meant to be the end-all and be-all of utility routines. You’d obviously need to tweak it for your application’s needs, particularly if you want to use the technique from a Windows Forms program or for other encoding formats.
My main goal with this article was to demonstrate the technique for creating multi-part emails using the .NET MailMessage class. Feel free to use the feedback link at the bottom of this page to let me know what you thought of it.