A Lesson in SMTP

Formatting Mail Messages with Plain Text, HTML, Attachments, and more…

ASP.NET Under the Hood

LANGUAGES: VB.NET | C#

ASP.NET VERSIONS: 2.0

 

A Lesson in SMTP

Formatting Mail Messages with Plain Text, HTML, Attachments, and more

 

By Michele Leroux Bustamante

 

Greetings ASP.NET architects and developers! I hope you enjoy this second installment of the ASP.NET Under the Hood column. I invite you to send your questions and requests to [email protected] let me unravel some mysteries for you!

 

Q. I need to send formatted HTML e-mails with one or more attachments from my ASP.NET 2.0 application, as well as supply a plain-text version for users who use text-based mail clients. Do you have any advice on how to do this with System.Net.Mail? Accomplishing the same with System.Web.Mail seemed overly complex. What other things should I know about sending e-mail programmatically?

 

A. A few years ago I remember building a newsletter engine with the mail functionality provided by System.Web.Mail only to find that I had to dig into the MIME specification to manually generate multipart/alternative messages. The good news is that System.Net.Mail completely surpasses the functionality provided previously in System.Web.Mail, so you don t have to build a custom SMTP client with sockets and learn more than you really wanted to know about the MIME standard just to send attachments and dual formatted e-mail.

 

In fact, functionality formerly provided by System.Web.Mail in .NET 1.x is now obsolete. .NET 2.0 introduces a good amount of new functionality in the System.Net.Mail namespace, including:

  • A better object model for formatting HTML e-mail, providing e-mail alternatives, and adding MIME-encoded attachments.
  • Support for asynchronous calls.
  • The ability to easily send SMTP server credentials without hacking field values.

 

Now, let s get back to the specific question.

 

Sending Plain-text E-mail

It s easy enough to send a simple e-mail using the SmtpClient type; just create an instance of the type, set the Host property, and call Send, as shown here:

 

SmtpClient smtp = new SmtpClient();

smtp.Host = www.mysmtpserver.com ;

smtp.Send([email protected], [email protected],

 "Plain Text Email",

"This e-mail is just a bunch of plain text, no formatting ");

 

In this example, Send passes parameters indicating the sender s address, the recipient s address, the subject, and the actual text content of the e-mail. This generates a simple, plain-text e-mail without attachments, without specifying credentials, and without any extended recipient lists. The resulting SMTP message looks something like this:

 

mime-version: 1.0

From: [email protected]

to: [email protected]

date: 16 Jan 2006 02:08:09 -0800

subject: Plain Text Email

content-type: text/plain; charset=us-ascii

content-transfer-encoding: quoted-printable

This e-mail is just a bunch of plain text,

no formatting

 

Message headers are automatically generated from the parameters passed, or they carry default values. Note that the Content-Type defaults to text/plain; charset=us-ascii because we are sending a simple character stream following the headers.

 

Sending HTML-formatted E-mail

SmtpClient also provides another method signature for Send that lets you supply a more tailored MailMessage type. This gives you additional control over the message details. Figure 1 shows an example that sends an HTML-formatted message.

 

MailMessage msg = new MailMessage();

msg.From = new MailAddress("[email protected]",

"Michele Leroux Bustamante");

msg.To.Add("[email protected]");

msg.Subject = "HTML Formatted Email";

msg.IsBodyHtml = true;

msg.Body = "<b>Coolness!</b> This email is

<i>much</i> more interesting.";

msg.CC.Add("[email protected]");

msg.Bcc.Add("[email protected]");

SmtpClient smtp = new SmtpClient();

smtp.Host = "www.mysmtpserver.com"

smtp.Send(msg);

Figure 1: Sending an HTML-formatted message.

 

You can see from the example in Figure 1 that the MailMessage class exposes a rich object model for building the message. In particular, providing a friendly name for the From address will help you avoid landing in spam folders! Setting IsBodyHtml to true also causes the Content-Type to default to text/html .

 

Adding Attachments to E-mail

Adding attachments is also easy using the Attachments property of MailMessage (see Figure 2).

 

MailMessage msg = new MailMessage();

msg.From = new MailAddress("[email protected]", "Michele Leroux Bustamante");

msg.To.Add("[email protected]");

msg.Subject = "HTML with Attachments";

msg.IsBodyHtml = true;

msg.Body = "<b>Coolness!</b> This email is <i>much</i> more interesting.";

Attachment att = new Attachment("data.zip",

MediaTypeNames.Application.Octet);

msg.Attachments.Add(att);

SmtpClient smtp = new SmtpClient();

smtp.Host = "www.mysmtpserver.com"

smtp.Send(msg);

Figure 2: Using the Attachments property of MailMessage.

 

This was also possible with System.Web.Mail, but finally media type names are much easier to specify (and find!). The new MediaTypeNames type saves you from scouring the Web for a reminder of the valid media types for various attachments.

 

Supporting Multiple E-mail Clients

This is where things used to get interesting with the deprecated System.Web.Mail object model. Previously, it was not possible to generate HTML e-mail that also supplies a plain text version for text-based mail clients. Before, you had to dig in and generate the MIME-encoded message yourself!

 

Now, with the SmtpClient type, you can add alternative message views with the code shown in Figure 3.

 

MailMessage msg = new MailMessage();

set other properties

string s = "This e-mail is just a bunch of plain text, no formatting ";

byte[] text = Encoding.ASCII.GetBytes(s);

msg.AlternateViews.Add(new AlternateView(new MemoryStream(text),

"text/plain"));

msg.AlternateViews.Add(new AlternateView( htmlemail.html ,

"text/html"));

Figure 3: Add alternative message views using the SmtpClient type.

 

Notice that each alternative specifies its own Content-Type in the AlternativeView constructor? That s because each message part will be separated by MIME-encoded boundaries (see the sidebar A Lesson in MIME on page XX) and will describe its own format. The overall message will be sent as multipart/mixed or multipart/alternative using the former if there are attachments included. Confused? Well, don t worry ... what s nice is that now you shouldn t really need to care about the details of MIME encoding you can be off and running with just a few lines of code!

 

Additional Resources

For more details on SMTP, visit http://www.ietf.org/rfc/rfc0821.txt. For more details on MIME, visit http://www.ietf.org/rfc/rfc1521.txt?number=1521.

 

If you have additional questions or comments regarding this column, or any other ASP.NET topics, please drop me a line at [email protected]. Thanks for reading!

 

C# and VB.NET code examples are available for download.

 

Michele Leroux Bustamante is Chief Architect at IDesign Inc., Microsoft Regional Director for San Diego, Microsoft MVP for XML Web services, and a BEA Technical Director. At IDesign Michele provides training, mentoring, and high-end architecture consulting services, specializing in scalable and secure .NET architecture design, globalization, Web services, and interoperability with Java platforms. She is a board member for the International Association of Software Architects (IASA), a frequent conference presenter, conference chair of SD s Web Services track, and a frequently published author. She is currently writing a book for O Reilly on the Windows Communication Foundation. Reach her at http://www.idesign.net or http://www.dasblonde.net.

 

A Lesson in MIME

Multipurpose Internet Mail Extensions, or MIME, specifies a standard format for encapsulating multiple pieces of data into a single Internet message. E-mail clients rely on MIME headers to display messages correctly. Plain-text messages are sent with the content type text/plain, and clients simply display the body of the message. HTML messages can be sent with a content type of text/html, which tells clients to respect HTML markup in the message body. When attachments are part of the message, plain-text and HTML messages use the content type multipart/mixed.

 

Multipart content type indicates that the message includes one or more different parts separated by a unique string boundary. A multipart message stream consists first of headers, followed by a carriage return and linefeed <CRLF>, and the content enclosed in an opening and closing boundary. The boundary is indicated in the Content-Type header, and e-mail clients expect the boundary string to appear prefixed with two hyphens (--) at the beginning of the entire message content, and between each message part in the content. A closing boundary must appear at the end of the message to indicate the final message part has been read. This closing boundary includes a double-hyphen prefix and suffix. The following listing gives you an idea how that looks:

 

Content-Type: multipart/mixed; boundary=mime_boundary1

--mime_boundary1

Content-Type: text/plain; charset=us-ascii

Content-Transfer-Encoding: 7bit

[text part]

--mime_boundary1

Content-Type: application/octet-stream

Content-Disposition: attachment; filename= data.zip

Content-Transfer-Encoding: base64

[binary part]

--mime_boundary1--

 

This listing illustrates sending a multipart/mixed message that contains two parts: the plain-text message and a zipped file attachment. The boundary string is mime_boundary1 in this example, but can be any unique string value. Headers are placed within each message part, following the separation boundary, to specify things such as content type and transfer encoding. In the above listing, the first part represents the content of the message; the second part is a binary attachment. Content type application/octet-stream is a generic sub type that indicates the data can be loaded by an application, but the sender is not specifying which application (such as Excel, Word, or PowerPoint). This allows the e-mail client to use the recommended filename indicated in the Content-Disposition header, to launch the correct application when the attachment is launched. Content-Disposition header also provides a means for the sender to indicate the file type, and a suggested archival name for the message part.

 

When you specify alternate versions of the message, the SmtpClient generates two versions of the message. The following code adds a plain-text and HTML version of the message:

 

mime-version: 1.0

From: [email protected]

to: [email protected]

date: 16 Jan 2006 02:08:09 -0800

subject: Multi-format EMail

content-type: multipart/alternative; boundary=mime_boundary1

--mime_boundary1

Content-Type: text/plain; charset=us-ascii

This e-mail is just a bunch of plain text,

no formatting

--mime_boundary1

Content-Type: text/html

<b>Coolness!</b> This email is <i>much</i> more interesting.

--mime_boundary1--

 

As you can see, multipart/alternative is packaged similarly to multipart/mixed, except that each message part is interpreted as a different version of the same data. Content type helps distinguish the difference between them, and e-mail clients usually try to use the last message part that they support. So, if the mail client supports HTML, the second message part is displayed; if not, the first part is displayed. This is why order is important.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish