How to Send Rich Email Messages
Combining HTML, MIME, and SMTP
January 26, 2003
I've always found that with scripting I can develop powerful tools and enhancements to provide functionality tailored to my customers' needs. For example, I recently created scripts that populated an Exchange Server 5.5 directory with PIN codes for Research In Motion's (RIM's) BlackBerry wireless devices. When I create a script that performs such a process, I like to have the script generate and email a progress report to the systems administrators. That way, they know that the process is working as expected and, more important, they're alerted when a problem occurs.
Using a script to generate and email a report is easy enough, but I've found that when the report is large, systems administrators can sometimes miss an error. You can avoid this problem by making errors stand out from the success information in the report. The best way that I've found to do this is to send the report in a rich format, such as HTML. I typically use the combination of HTML, MIME, and SMTP to send rich messages. When I refer to a rich message, I'm not referring to Rich Text Format (RTF). I'm using the term rich in a more generic sense to mean messages that contain color, images, different fonts, and different font sizes.
As Figure 1, page 2, shows, rich messages consist of HTML tags that draw the lines, change the text's color, make the text boldface, and so on. The recipients of rich messages need an email client that can handle HTML- and MIME-encoded messages, but these days, most email clients (including Outlook and Outlook Express) have this capability. Because Outlook and most other modern email clients can understand and render HTML tags, you can create messages that contain more than just simple text. Depending on your goal, the messages can become quite sophisticated and powerful.
HTML alone isn't enough to send rich messages. An HTML file is a simple text file that contains tags that specify formatting instructions. For example, the and tags specify the formatting instructions of boldface on and boldface off, respectively. If an HTML file contains the phrase Report Status, your browser would render the phrase as Report Status.
If you simply placed the HTML code in Figure 1 into an email message and sent it, the receiving email clients would display it just as you typed it instead of displaying an HTML-rendered version. To tell the email clients to render the text as HTML, you need to use MIME. MIME is a set of definitions that tell email clients how to encode and decode nonplaintext content so that the email client can use SMTP to transmit the email.
SMTP and MIME 101
SMTP divides each message into two parts: a header and a body as defined by Internet Engineering Task Force (IETF) Request for Comments (RFC) 821 and RFC 822, respectively. MIME expands each part to provide enhanced capabilities.
The basic SMTP header contains tags, such as From, To, Date, and Subject. MIME-encoded messages have additional header tags: MIME-Version, Content-Type, and possibly Content-Transfer-Encoding. When a MIME-capable email client sees these tags in the message header, the client knows that it needs to take special action on the text that's in the message body. Figure 2 shows a MIME-encoded SMTP message in which I've boldfaced the MIME tags. The top seven lines make up the message header; the remaining lines are the message body. A blank line always separates the message header and message body.
The header's MIME-Version tag is self-explanatory. Currently, MIME 1.0 is the only version in use. The Content-Type tag describes what type of data the message body contains. The content type is a compound definition that has a primary type and a subtype. The primary type specifies a class, such as application, audio, or image. The subtype stipulates a specific format within that class. A few examples of the many possible primary type/subtype combinations are text/plain, audio/mpeg, audio/wav, application/msword, and image/gif.
The most-used Content-Type tags are multipart/alternative and multipart/mixed. When you use either one, the Content-Type tag has an associated component called the boundary designation. I explain the boundary designation in more detail later. For now, all you need to know is that a boundary separates the different parts in a multipart message body.
You use the multipart/alternative content type to specify that the message body contains several iterations of the same data, with each iteration presenting the data a different way. The sample message in Figure 2 uses this content type to first present the data as plaintext (text/plain), then as HTML (text/html). You use multipart/alternative when you need to send your message to various recipients whose email clients might not all have the same capabilities. By providing the text in a variety of formats, you let the email client use the richest format possible while still letting your message reach as many recipients as possible.
You use the multipart/mixed content type when you want to use different data in different formats in the same message. For example, you use this content type if you want to attach a Microsoft Word document and a Microsoft PowerPoint presentation to the same message.
When you use the multipart class, the message body contains several body parts, or entities. The Content-Type tag's boundary designation identifies where one entity begins and another ends. In the sample message in Figure 2, the boundary string is defined as "——=_NextPart_000_0000_01C284A7.B8F453A0". This boundary string is fairly complex, but the string can also be as simple as "the_boundary", as long as the string is unique within the data that makes up the message body. Two hyphen characters followed by the boundary string then define the boundaries of each entity within the message body. The final boundary string also includes two trailing hyphens. The trailing hyphens are included so that the email client knows it has reached the end of the MIME section.
A multipart message body usually contains a preamble and one or more body parts. The preamble is a plaintext statement that's included just in case an email client that isn't MIME-capable receives the message. This text usually includes a sentence or two that lets the recipients know why they have received this seemingly scrambled message. In this case, the preamble is This is a multi-part message in MIME format. Your email client may not be able to understand MIME. If a MIME-capable email client receives the message, it ignores the preamble and decodes the MIME body parts.
Each body part contains Content-Type and Content-Transfer-Encoding tags followed by the encoded data. The Content-Type tag in each body part performs the same function as the Content-Type tag in the message header, but the content type applies only to the data contained within the body part's boundaries. The Content-Transfer-Encoding tag specifies the type of decoding algorithm the email client uses to convert the encoded data back to its original form.
The valid values for the Content-Transfer-Encoding tag are 7bit, 8bit, base64, binary, and quoted-printable. The value you use depends mostly on the format of the original data, and all types result in plain-ASCII text that you can transmit with SMTP. For example, for a .wav file, you'd use base64 or binary because the .wav file's original data is in binary format. You'd use 7bit when the original data consists of only the first 127 ASCII characters. When the original data consists of the first 127 ASCII characters and some special characters, you'd use quoted-printable because it not only keeps the original data close to the original human-readable format but also includes special characters in hexadecimal notation. To understand all the nuances of when to use each Content-Transfer-Encoding tag, the best resource is RFC 2045 (http://www.ietf.org/rfc/rfc2045.txt) and RFC 2046 (http://www.ietf.org/rfc/rfc2046.txt). These two documents are part of the RFC series (RFC 2045 through RFC 2049) that defines MIME.
Scripting Rich Messages
In a Microsoft environment, the easiest way to send an email message from a script is to use one of the Collaboration Data Objects (CDO) libraries that are available as DLLs. As Table 1 shows, different generations of CDO work with different systems. The mechanism you use to deliver a message depends on which library you use. The cdo.dll library uses Messaging API (MAPI) to directly connect to an email server and send a message to an Exchange mailbox. (Note that for this library, I use the DLL's filename to avoid confusion with the generic usage of the term CDO. For all the other CDO libraries, I use their common names.) The Collaboration Data Objects for Windows NT Server (CDONTS) library writes an RFC 821 or RFC 822 formatted file into a pickup directory that either the Microsoft IIS SMTP service or the Exchange 5.5 Internet Mail Service (IMS) monitors. When one of these services sees a file in its pickup directory, it reads the file and uses the SMTP protocol to send the message to the recipients. The CDO for Windows 2000 (CDOSYS) library can write to a pickup directory but also provides direct access to the SMTP protocol. The CDO for Exchange 2000 Server (CDOEX) library can use any of these mechanisms.
When you use cdo.dll, you're limited to sending messages in plaintext, so I won't discuss how to use that library. Unlike cdo.dll, CDONTS, CDOSYS, and CDOEX provide the functionality you need to generate rich messages, so let's look at how you can use these libraries in a script.
Using CDONTS
With CDONTS, you can write a script that places a rich email message in a pickup directory. For example, the VBScript code in Listing 1, page 4, uses CDONTS to generate a message that has two lines, the second line of which generates blue boldfaced type when the recipient views it.
Let's walk through this code so that you understand how it works. To begin, look at the code at callout B in Listing 1. This code creates a NewMail object, which you can use to create and send an email message. You use this object's properties to set the message's various components. For example, you use the From, To, and Subject properties to specify the message's sender, recipients, and Subject line, respectively. Setting the BodyFormat and MailFormat properties controls the type of encoding to use. The valid values are 0 to specify MIME and 1 to specify plaintext. To send a rich message, you must set both properties to 0.
You use the Body property to assign the email message's body text. In this case, the sBodyText variable contains that text. To generate a rich message, you need to insert HTML tags into the body text, as callout A in Listing 1 shows. The
tag tells the email client to insert a line break after the first sentence, which splits the text into two lines. The tag bolds the second line, and the tag changes that line's text color to blue and increases its text size.
Finally, you use the NewMail object's Send method to send the email message. Because you've set the BodyFormat and MailFormat properties to 0, CDONTS takes care of the MIME encoding (e.g., creating Content-Type tags and boundary strings). CDONTS then writes a file containing the MIME message into the pickup directory for SMTP delivery. For example, if you run this code on an Exchange 5.5 server, CDONTS writes a file that has an .eml extension to the exchsrvrimcdatapickup directory. You can view this file's MIME encoding if you stop the IMS briefly and use Notepad to examine the file. (I used this process to capture the sample MIME-encoded message in Figure 2.)
Using CDOSYS and CDOEX
CDOSYS and CDOEX provide much of the same functionality as CDONTS. However, CDOSYS and CDOEX give you more options for sending email messages than CDONTS. For example, when you execute CDONTS's Send method, the library writes the message to the server's local pickup directory, which restricts the library's use to servers that have Exchange 5.5 or IIS loaded. CDOSYS and CDOEX let you not only send a message to the local pickup directory but also connect to a remote SMTP service to deliver the message. Because CDOSYS is installed on all Win2K systems (including Win2K Professional), you can send SMTP messages from systems that don't have Exchange 5.5 or IIS installed.
To connect to a remote SMTP service, you need to create and configure the Configuration and Message objects in either the CDOSYS or CDOEX library. The Configuration object has many options, or fields, that you can set, but only two are required: sendusing and smtpserver. As callout A in Listing 2 shows, when you set these two fields in your script, you must use the fields' full names, which look like URLs and therefore are confusing. When I first saw the http:// in these fields' names, I wondered whether the library was going to make an HTTP call to Microsoft to get some type of configuration information, but that's not the case. Apparently, the idea behind naming the property this way was to let a user simply click the property name to obtain details about that property from Microsoft Web servers, but that idea never became a reality.
The sendusing field uses numeric values to define the mechanism the library should use to deliver the message. When you set sendusing to 1, the library uses the local pickup directory, just as CDONTS does. When you set sendusing to 2, the library uses the SMTP protocol to connect to an SMTP server, which the smtpserver field defines. In Listing 2, the sendusing and smtpserver fields are telling the library that you want to use the SMTP protocol to connect to the smtp.demo.com server, which will transport the message.
You use the Fields collection to access the Configuration object's settings, which include sendusing and smtpserver. To retrieve or set a field in the collection, you use the Item property. To save the configuration you've created, you call the Fields collection's Update method.
Next, you use the Configuration object as a parameter to set the Message object's configuration. By doing so, you let the library handle all the tedious tasks involved with opening a TCP/IP port and using it for SMTP communications. You then set the Message object's properties to specify the email message's various components, as callout B in Listing 2 shows. The Message object's From, To, and Subject properties work the same way as the NewMail object's From, To, and Subject properties. However, when you use the Message object, you don't need to set any formatting properties. Instead, CDOSYS and CDOEX provide two body properties: TextBody and HTMLBody. When you place the message's body text in HTMLBody, the library assumes that you're sending a rich message and that it must be MIME encoded. When you place the body text into TextBody, the library assumes you're sending a plaintext message. After you set the HTMLBody property to the sBodyText variable, you once again use the Send method to start the delivery process—only this time the library connects to a remote SMTP server to deliver the message.
For more information about how to use the powerful CDOSYS and CDOEX libraries, you can turn to the Microsoft Developer Network (MSDN) and Microsoft TechNet. To get you started, I've provided several helpful references in the Web-exclusive box "CDO Email-Related Learning Resources" (http://www.exchangeadmin.com, InstantDoc ID 37538).
Some Special Situations
All the examples that I've given so far have assumed that you're working on a server that has one of the MIME-capable CDO libraries loaded. When you use one of these libraries to send messages, the library writes the proper SMTP header information and performs the MIME encoding. In some situations, you might not have a MIME-capable CDO library available. For example, you won't have one available if you're using an NT 4.0 server that doesn't have IIS loaded. In that case, you can still easily access Exchange's ability to send rich messages by writing files directly to Exchange's pickup directory. Although this task might sound complicated, it isn't. You need to build the RFC 821 and RFC 822 components of the message yourself and add the appropriate MIME tags and boundary markers. You also need to make sure that any filenames that you write to the pickup directory are unique. All these tasks are achievable by following the rules specified in the RFCs.
If you have applied or are thinking of applying Exchange 2000 Service Pack 3 (SP3) on a system in which you're using a CDO library, you might need to use a more tailored approach to sending rich email messages. In Exchange 2000 SP3, Microsoft tightened permissions by removing the Everyone group's read access to the IIS metabase. The metabase contains configuration information, including information about which directory to use as the pickup directory. When you configure your script to send a message to the pickup directory, the CDO library reads the metabase to know where to write the files. If your script isn't running under the security context of an account with read access to the metabase, your script will generate an error. For details about the problem and possible solutions, see the Microsoft article "PRB: Microsoft Exchange 2000 Server Service Pack 3 Security Modification and CDOEX/CDOSYS" (http://support.microsoft.com/?kbid=324037).
Try the Trio
Combining SMTP, MIME, and HTML can add new power and effectiveness to the email messages that you send with scripts. You can take advantage of these three powerful tools, no matter which language you use to write your scripts. If you want to try implementing some of the concepts I've described, read RFC 2045 and pay close attention to the discussions about content types, boundary strings, and encoding. You should also take a look at the references I've listed in "CDO Email-Related Learning Resources." These references include scripts that you can run. If the scripts send messages by way of the pickup directory, you can then stop your IMS or SMTP virtual server and examine the files in that directory. Soon, you'll be on your way to creating and sending rich, useful messages.
CDO Email-Related Learning Resources |
---|
CDONTS"NewMail Object (CDONTS Library)"http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdo/html/_denali_newmail_object_cdonts_library_.aspCDOSYS and CDOEX"About CDO for Windows 2000"http://msdn.microsoft.com/library/en-us/cdosys/html/_cdosys_about_cdo_for_windows_2000.asp"HOWTO: Send HTML Formatted Mail Using CDO for Windows 2000 and a Remote SMTP Service"http://support.microsoft.com/?kbid=286431"HOWTO: Send HTML Formatted Mail Using CDO for Windows 2000 and the Local Pickup Directory"http://support.microsoft.com/?kbid=286430"http://schemas.microsoft.com/cdo/configuration/ Namespace" http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_schema_configuration.asp"IMessage Interface"http://msdn.microsoft.com/library/en-us/cdosys/html/_cdosys_imessage_interface.asp |
About the Author
You May Also Like