Handling Email Blasts with ColdFusion Part 1

ColdFusion has a lot of built in functionality that makes it easy to create an email blast for a newsletter, order confirmation, or other type of dynamic email generation. Following is some information on how you can use CF for sending dynamic emails. In this first part, we'll discuss some general principles. The article assumes that you have used <cfmail> before.

ColdFusion 6.1

CF has always had somewhat limited functionality for emails, although just about anything could be done with a little effort. All that changed with ColdFusion MX 6.1. Using 6.1, you have many more options for creating emails, and much more functionality at the server level to handle things like multiple email servers, bounced messages, and number of outgoing threads. These settings can be tweaked depending on the level of functionality that your mail server has. With a high-quality mail server, you can send 1,000,000 messages/hour with CF MX 6.1.

Following are some of the settings in the CF Administrator that you should be aware of. These are available in ColdFusion MX Server Enterprise. You will find the settings in the Mail tab of the CF Administrator:

Mail Server Settings

These are general settings for your mail server.

Mail Spool Settings

These relate specifically to the mail spooler, and could make the difference in speed as well as delivery success rate.

The <cfmail> tag

Every email you send in ColdFusion will use the <cfmail> tag, although there are alternatives as well. The <cfmail> tag has many attributes that are useful when creating an email blast. The <cfmail> tag has the following attributes (* denotes required attribute):

<cfmail
*to = "recipient"
*from = "sender"
cc = "copy_to"
bcc = "blind_copy_to"
*subject = "msg_subject"
replyto = "reply_to_addr"
failto = "fail_message_addr"
username = "user name"
password = "password"
wraptext = "column number"
charset = "character encoding"
type = "msg_type"
mimeattach = "path"
query = "query_name"
group = "query_column"
groupcasesensitive = "yes" or "no"
startrow = "query_row"
maxrows = "max_msgs"
server = "serverspecs"
port = "port_id"
mailerid = "headerid"
timeout = "seconds"
spoolenable = "yes" or "no">

I'm not going to go through each attribute, as you can find that information in the ColdFusion documentation, but following are some of the parts of an email message and how they relate to the <cfmail> tag.

From field

This is the address the message comes from, and is supplied to the from attribute of the <cfmail> tag. It can be an e-mail address that is hard-coded, or it can be taken from a database as a variable and matched to the recipient. All e-mails need a From field and should be a valid client e-mail address. Also note that a from field can contain a ?nice? name along with an email address, in the format of:

?John Jehosephat? <jjehosephat@jehosephatlodge.com>

Reply-to header

This is usually the same as the From field, but it can be different, as in a generic company mailbox. For many cases, you will have a nice name in the From field, but have a special box to handle replies so that the person who is sending the message does not get bombarded with autoresponders when the email is sent. The reply-to header is added when you specify the replyto attribute of the <cfmail> tag.

Return-path header

This is where the "bad" or "erroneous" e-mail addresses get bounced to. You should set up a separate email box to handle bounces, so that the bad emails do not bounce back to the person's email box who is in the From or Reply-to field. The Return-path header is added when you specify the failto attribute. If you don't specify this, the mail will bounce back to the person specified in the from attribute.

Subject field

All e-mails need a subject field. In general, this should be 45 characters or less and not include special characters or formatting.

Mail server

In many cases, you will not need to supply this in the <cfmail> tag, as long as there is a mail server defined in the CF Administrator. If it is not, or if you want to override that setting, use the server attribute.

Wraptext

You can use the wraptext attribute to specify a line length for your email, although in actual practice you are better off creating your emails with line lengths already set. This way, you can design your emails and place line breaks in logical places.

Query and Group

We'll discuss these later in the article. These are useful for email blasts, although you can also use a <cfloop> around your <cfmail> tag instead, without losing any speed or functionality.

Types of Emails

Following are some of the ways you can send out an email:

HTML

The majority of people can see an HTML format, but someone with an old e-mail reader might see the HTML tags. It's best to send out an HTML/text multipart version. If you specify type="html" in your <cfmail> tag, an HTML-only email will be sent.

TEXT

This version will look good on all standard e-mail readers, but advanced features are disabled, such as images, bold, italics, underlining, short links, etc. AOL users might not be able to click on links, also. If you do not specify a type attribute, or specify type="text", a text email will be sent.

HTML/text Multi-part

Users will automatically get the text or HTML version depending on their e-mail reader. This is the best way to send a message if you want to use HTML in your message.

HTML/text Multi-part with a separate version for AOL Users.

Older AOL mail clients interpret the text and HTML differently so that a separate version would "look" better for AOL customers. If they aren't separated, different versions of AOL will see different things. They might see the text version with links disabled, or they might see only some of the HTML. Because of this, you can create completely different versions for AOL users.

Bounces

An e-mail bounce is an e-mail that was sent out and comes back as undeliverable for whatever reason. When this happens, the server should make several attempts to send the message. This can usually be configured at the server level. Typically, you'll want to try once per hour for up to 12 or 24 hours. If the e-mail still fails to reach the recipient after those attempts, it "bounces back".

An e-mail can bounce for a variety of reasons, including heavy Internet traffic and a mail server being down for a few hours. There are many other reasons for bounces. Bounces are classified as ?Hard bounce? if the mail server of the recipient has never accepted the message. Reasons for this could include:

Bounces are classified as ?Soft bounce? if the e-mail is recognized by the recipient's mail server but is returned to the sender. Reasons for this include:

For these reasons, a bounced message is not considered to be non-valid e-mail address until the bounce occurs repeatedly over the course of several e-mails. However, in actual practice, a very small percentage of these bounced e-mail addresses are actually valid email addresses.

Remove Me

All e-mails should have a "REMOVE ME" option to opt-out of the mailing. If you are sending an email for a client who does not need an opt-out, such as a customer communication that is covered under the agreement that a person signed when they became a customer, you should still include a link to the privacy policy of the site, or a link to the agreement they signed when they made a purchase or otherwise provided their email address.

Setting Up the HTML Version

The HTML version of the document requires skill in HTML coding to be able to create a valid document. Bad HTML coding will give you a bad email and may cause the end-user to have errors in reading the email. All tags should conform to W3C specs. Font tags should be kept to a minimum. The best way to format your email is to create a text-only version first, drop it into the design view of Dreamweaver or Homesite, and then add CSS styles to the text. This is easily performed in Dreamweaver.

CSS styles should be placed inline within your html tags or within a <style> block within the <body> of the email. If you include a <style> block in the <head> of the email, as you would typically do on a web page, many web-based email clients will strip out all styles.

Setting Up an AOL Version

AOL 5.0 and earlier has it's own special HTML format that doesn't conform to any HTML standards. AOL 6.0 has a much better compatibility to standard HTML, but if you want to make sure that emails work with older AOL browsers, such as AOL 4.0 or AOL 5.0, include a separate AOL version. Always test the AOL emails with one of these older programs.

Note: Macintosh OS 9 users will have AOL 5 or earlier.

AOL emails recognize the following HTML tags:

BREAK:
  <br>
FONT:
  <font>
BOLD:
  <b>
ITALICS:
  <i>
UNDERLINE:
  <u>
SUBSCRIPT:
  <sub>
SUPERSCRIPT:
  <sup>
BIG:
  <big>
SMALL:
  <small>
HEADER:
  <h1>, <h2>, <h3>
PARAGRAPH:
  <p>
BODY:
  <body>
HYPERLINK:
  <a href=?yourlink?>yourtext</a>
CENTER:
  <center>
STRONG:
  <strong>

For that reason, it is advisable to set up the AOL version separately from the HTML version, and in many cases it is easier to use the text version as a starting point than the HTML version. Also, note that you can't use non-breaking spaces or other special html characters (&nbsp; &amp; &quot;)

CSS can't be used with these older AOL versions either, so you should use old-style <font> tags when making fonts.

The content-type header used in an AOL mail can be text/html or text/x-aol. They will both work. If you use no headers, text will be assumed and the links may not work properly. This can be set in the type attribute of the <cfmail> tag, or in a <cfmailpart> tag.

Note also that images can't be used in AOL emails.

Setting Up a Text Version

The text version of the email is the easiest part of the process, as you can use Notepad to format the text. Several things need to be done, however:

The hyperlinks should be fully qualified. In other words, don't use www.sitename.com -- use http://www.sitename.com instead.

Any click thru links or other long links will have to be fully coded with no special ?hidden? link. If the link is too long, it may fall on two lines and be broken as a link for the end user. One way to avoid this in many email clients is to put a <> around the link, as in this link:

<http://www.mycoolsite.com/articles/clickthrough/mypage.jsp?blah=w2348dc78
34kjv878shvln34s9cl34jlknmldvjhl23kmnlmvl>

Typically, an email client will break up the text at 68, 72, or some other predefined count of characters.

Data Structures for Email Blasts

Standard Data:

Used in marketing or informational emails. Typically the result of a query like this:

SELECT First, Last, Company, Email
FROM Customers

This type of data is the easiest to use in ColdFusion when sending email. Simply create a <cfquery> tag with your query, then use the <cfmail> tag with a query attribute:

<cfquery name=?rsEmail? datasource=?myDSN?>
SELECT First, Last, Company, Email
FROM Customers
</cfquery>
<cfmail subject=?Your information?
to=?#rsEmail.email#?
from=?admin@communitymx.com?
query=?rsEmail?>

Hello #rsEmail.First# #rsEmail.Last#:

Here is the information you requested:

<cfinclude template="information.txt">
</cfmail>

Relational Data

This is the type of data structure used in most databases, like Access, SQL Server, etc. When the data is stored this way, it is typically supplied to an email from a query that joins multiple tables, like this:

SELECT c.ContactName, c.EmailAddress,
o.OrderID, OD.ProductID,
P.ProductName, P.UnitPrice
FROM Customers c
  INNER JOIN Orders o
    ON c.CustomerID = O.CustomerID
  INNER JOIN OrderDetail od
    ON o.OrderID = od.OrderID
  INNER JOIN Products p
    ON od.ProductID = P.ProductID
ORDER BY c.EmailAddress

Relational data gives you the opportunity to supply the line items in the email using a group attribute of <cfquery>. The way to use group is to first order your results by the email address, and then use a <cfoutput> around the line items in your email:

<cfquery name="rsEmail" datasource="myDatasource">
SELECT c.ContactName, c.EmailAddress,
o.OrderID, OD.ProductID,
P.ProductName, P.UnitPrice
FROM Customers c
INNER JOIN Orders o
ON c.CustomerID = O.CustomerID
INNER JOIN OrderDetail od
ON o.OrderID = od.OrderID
INNER JOIN Products p
ON od.ProductID = P.ProductID
ORDER BY c.EmailAddress
</cfquery>
<cfmail subject=?Your order?
to=?#rsEmail.email#?
from=?admin@communitymx.com?
query=?rsEmail?
group=?email?>
Hello #rsEmail.ContactName#:

Here is your order for order id #rsEmail.OrderID#:

<cfoutput>
ProdID: #rsEmail.ProductID# #rsEmail.ProductName#: #DollarFormat(rsEmail.UnitPrice)#</cfoutput>

Thank you for your order,

Community MX
</cfmail>

Using the <cfoutput> within the <cfmail> tag with a group attribute is just like putting a second loop inside the email. The email would look like this:

Hello Binky Tooskinny:

Here is your order for order id 10625:

ProdID: 14 Tofu : $23.25
ProdID: 19 Teatime Chocolate Biscuits: $9.20

Thank you for your order,
Community MX

Transactional Data:

Often used in line item billing, statements, and notices. It is sometimes supplied as a text file in sequential order. Standard software packages don't support it, and standard queries don't work as well.

Can be supplied to the email with a query like:

SELECT t.col001, t.col002, col003, col004, col005,
(SELECT col005 from TransactionalTable
where col002 = t.col002 and col001 = '10') as email
FROM TransactionalTable t
ORDER BY email, col001

Import the data to a database giving the data a line number (an autonumber or identity column). Then, create a column on the fly to act as the glue to hold the data into groups. In this case, using the email address makes the most sense. Note that customer information is in the ?10? lines, whereas the line item information is in the ?20? lines. This also makes it difficult to use the group attribute as we have done with the relational data, because we don't want to group the header line in the output of line items. To simplify the process, we'll put a second query inside the first query using a query of query . These types of queries are super fast because they exist entirely in memory.

<cfquery name="rsEmail" datasource="test">
SELECT t.col001, t.col002, col003, col004, col005,
(SELECT col005 from TransactionalTable
where col002 = t.col002 and col001 = '10') as email
FROM TransactionalTable t
ORDER BY email, col001
</cfquery>

<cfmail subject="Your list of responsibilties"
to="#rsEmail.email#"
from="admin@communitymx.com"
query="rsEmail"
group="email">
Hello #rsEmail.col003# #rsEmail.col004#:

Here is your list of responsibilities:
<cfquery name="rsLineItems" dbtype="query">
SELECT * FROM rsEmail
WHERE email = '#rsEmail.email#'
AND col001 = '20'
</cfquery>
<cfloop query="rsLineItems">
#rsLineItems.col003# </cfloop>

Thanks!
Community MX
</cfmail>

Conclusion

In this part, we've looked at some of the general considerations for sending email blasts with ColdFusion, although the principles can be applied to other languages as well. In the next part, we'll look at several techniques to use to simplify the sending of email blasts.