One of the most commonly used ColdFusion tags may also be one of the most misused. I say this because of the ColdFusion code that I've seen in production. It appears that a large number people think that all you need to do is open the CFMail tag and type in a to address the from address a subject and then close the tag. And then stuff your email message between the opening and closing tags. People do it this way as this is how they are shown, see the examples below.

view plain print about
1Adobe LiveDocs CF7,8,9:
2
3<cfmail to = "#form.mailto#"
4from = "#form.mailFrom#"
5subject = "#form.subject#">

6This message was sent by an automatic mailer built with cfmail:
7= = = = = = = = = = = = = = = = = = = = = = = = = = =
8#form.body#
9</cfmail>
10
11Common blog example found via a typical Google search:
12
13<cfmail
14to = "name@yourdomain.com"
15from = "name@yourdomain.com"
16subject = "Example of CFMail Tag using Coldfusion 5.0"
17server = "mail.yourdomain.com">

18Email Message
19</cfmail>

While both examples are technically correct and will send an email from your ColdFusion server they all lack what most people are trying to achieve in sending HTML formatted/pretty email messages and messages with attachments. There are precise ways in which the RFC (RFC-822) standard for sending e-mails dictates that these are to be done and ColdFusion allows you to follow the standard exactly. You just need to know how. I am not going to bore you with the RFC standard details, however if you are suffering from insomnia feel free to read them. What I will show you is how to send an HTML formatted email with the proper email message parts and optional file attachments so that it will safely pass most if not all SPAM filter tests and will render properly in mail clients.

The above code would generate email that looked like this when you examine the raw email source.

view plain print about
1Return-Path: <some_address@somedomain.com>
2Delivered-To: myaddress@mydomain.com
3X-Spam-Checker-Version: SpamAssassin 3.2.4 (2008-01-01) on
4    mail.mymailserver.com
5X-Spam-Level: **
6X-Spam-Status: No, score=2.8 required=5.0 tests=HTML_MESSAGE,
7    HTML_MIME_NO_HTML_TAG,MIME_HTML_ONLY,RDNS_NONE autolearn=no version=3.2.4
8Message-ID: <1331187905.1191260207349870.JavaMail.root@mail.mymailserver.com>
9Date: Mon, 7 Dec 2009 11:35:39 -0600 (CST)
10From: John Doe <some_address@somedomain.com>
11Reply-To: some_address@somedomain.com
12To: myaddress@mydomain.com
13Subject: Hows life
14MIME-Version: 1.0
15Content-Type: text/html; charset=UTF-8
16Content-Transfer-Encoding: 7bit
17
18John Doe,<br><br>
19
20Just wondering how things are going.

Looks good, right? However, there are some issues. There are HTML tags in the body of the message, but there is no text portion of the message. If you notice the header information you will see an item for X-Spam-Status and this indicates a score of 2.8. This score was not high enough yet to dictate that this was SPAM according to this SPAM servers rules (on other email servers it might get flagged as SPAM), but you will notice that the items it flagged were almost all HTML related items such as HTML only. In order to reduce the SPAM score you need to properly format your email messages. Typically what I see with HTML formatted messages is that people set the CFMail 'type' attribute to HTML and then between the opening and closing tags they insert their HTML formatted email message. This also may technically be correct, however, it does have some drawbacks in that most if not all SPAM detection software throws a flag when it sees HTML only messages and no text part of the message.

Below is an example of how I usually send an HTML formatted email in ColdFusion.

view plain print about
1<cfmail to="#form.mailto#" from="#form.mailFrom#" subject="#form.subject#" type="html">
2<cfmailpart type="text/plain" charset="utf-8">#textMessage(mailmessage)#</cfmailpart>
3<cfmailpart type="text/html" charset="utf-8">#mailmessage#</cfmailpart>
4</cfmail>

You should note a few differences right away. First I'm using the CFMailPart tag and secondly I specified a the 'type' attribute for the CFMail tag and set that to 'HTML'. Setting the type to HTML means the email will contain text and HTML. The CFMailPart tag creates the proper email message parts according to the RFC standard. The first one has the text part of the message and the second one has the HTML part of the message. This will create an email message that has a source that looks like this.

view plain print about
1Return-Path: <some_address@somedomain.com>
2Delivered-To: myaddress@mydomain.com
3X-Spam-Checker-Version: SpamAssassin 3.2.4 (2008-01-01) on
4    mail.mymailserver.com
5X-Spam-Status: No, score=0.1 required=5.0 tests=HTML_MESSAGE,RDNS_NONE
6    autolearn=no version=3.2.4
7Message-ID: <1288896933.2111267119954547.JavaMail.root@mail.mymailserver.com>
8Date: Thu, 25 Feb 2010 11:45:44 -0600 (CST)
9From: John Doe <some_address@somedomain.com>
10Reply-To: some_address@somedomain.com
11To: myaddress@mydomain.com
12Subject: Hows life
13MIME-Version: 1.0
14Content-Type: multipart/alternative;
15    boundary="----=_Part_5_687894178.1267119944234"
16
17------=_Part_5_687894178.1267119944234
18Content-Type: text/plain; charset=utf-8
19Content-Transfer-Encoding: 7bit
20
21John Doe
22
23How's Life?
24
25------=_Part_5_687894178.1267119944234
26Content-Type: text/html; charset=utf-8
27Content-Transfer-Encoding: 7bit
28
29John Doe<br><br>How's Life?
30
31------=_Part_5_687894178.1267119944234--

You should notice that the message body is in there twice, once as text and once as HTML. What this does is tells the email client there are two parts to this email and to display the email part that the client is configured to handle. Most email clients these days are HTML capable, but there are still those that only use text email clients or have their client set to text mode for security reasons. Creating email this way allows your message to be viewed by everyone no matter what their email client is doing. You should also notice that this message has a SPAM score of .1 meaning that it should pass most if not all SPAM filters on the internet.

So that looks good, but how did I create the text part of the message? The CFMailPart tag for setting the text message calls the 'textMessage()' function. This is not part of ColdFusion, this is one of my little CFGems that I take with me everywhere. Feel free to take it and use it yourself. The code is shown below.

view plain print about
1<cffunction name="textMessage" access="public" returntype="string" hint="Converts an html email message into a nicely formatted with line breaks plain text message">
2    <cfargument name="string" required="true" type="string">
3    <cfscript>
4        var pattern = "<br>";
5        var CRLF = chr(13) & chr(10);
6        var message = ReplaceNoCase(arguments.string, pattern, CRLF , "ALL");
7        pattern = "<[^>]*>";
8    
</cfscript>
9    <cfreturn REReplaceNoCase(message, pattern, "" , "ALL")>
10</cffunction>

This code is pretty simple, first it replaces all <BR> tags with the proper line break characters, then it uses a Regular Expression to remove all the remaining HTML tags. It's not too complex, but it does fail with certain things like highly complex tabular layouts or if someone is using random '<' or '>' symbols in their email. So far those items have not been an issue and with millions of emails sent I'll stick with what I've been using. Sometimes you will be asked to create a highly stylized email and the only solution to the text portion is to hand code the text portion also.

To build the HTML body of my email message I use CFSaveContent. This tag saves everything you generate inside of it to a variable. One thing to remember is that is saves everything literally including tabs, spaces, carriage returns etc. If you are generating an email using a fair amount of conditionals and queries or loops you may want to condense the code once you are done with the final version.

view plain print about
1<cfsavecontent variable="mailmessage">
2Dear Joe Doe,<br>
3<br>
4Thank you for registering with our site.<br>
5<br>
6You can log into your Profile at any time by pointing your web browser to:<br>
7<a href="http://www.mysite.com/profile/">http://www.mysite.com/profile/</a><br>
8<br>
9Your User name is: <cfoutput>#username#</cfoutput><br>
10<br>
11When you registered you indicated you wanted to receive these newsletters by email:<br>
12<cfoutput query="subscriptions">
13    <ul>
14        <li>#newsletter_name#<br></li>
15    </ul>
16</cfoutput>
17<br>
18Thank you for using our fine site,<br>
19<br>
20Mysite.com Management<br>
21<br>
22<cfoutput><a href="http://www.mysite.com/profile/unsubscribe/#username#">Click here to unsubscribe from future emails</a></cfoutput>
23</cfsavecontent>

You can get as creative as you like with your email just remember that all the white space is also saved literally. You may want to condense the final code to prevent unwanted white space in the text portion of the email as shown below. The textMessage() function will replace the <br> with text carriage returns so you will still get a nice looking text message.

view plain print about
1<cfsavecontent variable="mailmessage">Dear Joe Doe,<br><br>Thank you for registering with our site.<br><br>You can log into your Profile at any time by pointing your web browser to:<br><a href="http://www.mysite.com/profile/">http://www.mysite.com/profile/</a><br><br>Your User name is: <cfoutput>#username#</cfoutput><br><br>When you registered you indicated you wanted to receive these newsletters by email:<br><cfoutput query="subscriptions"><ul><li>#newsletter_name#<br></li></ul></cfoutput><br>Thank you for using our fine site,<br><br>Mysite.com Management<br><br><cfoutput><a href="http://www.mysite.com/profile/unsubscribe/#username#">Click here to unsubscribe from future emails</a></cfoutput></cfsavecontent>

Remember to test your email in as many email clients and webmail clients as you can. This will help ensure that your users get the see the message you intended them to see.

Email Attachments

So what about email attachments? There is a tag for that called CFMailParam. This tag lets you specify the file attachment for an email. See the example below.

view plain print about
1<cfmail to="#form.mailto#" from="#form.mailFrom#" subject="#form.subject#" type="html">
2<cfmailparam file="/document/path/mypdf.pdf" contentID="#createUUID()#" disposition="attachment" type="application/PDF">
3<cfmailpart type="text/plain" charset="utf-8">#textmessage(mailmessage)#</cfmailpart>
4<cfmailpart type="text/html" charset="utf-8">#mailmessage#</cfmailpart>
5</cfmail>

The value for the file attachment needs to be the physical path to the file on the server. The attributes disposition, type and contentID are used to specify the file is an attachment or to be viewed inline, the mime type of the attachment and a UUID for the attachment.

This is all there is to it. When you're done creating the email you should have a very nicely formatted HTML email with the proper text portion of the message and optional attachments that passes most if not all SPAM tests and displays correctly for your users.

I hope this helps you create better emails using ColdFusion.

UPDATE: The code for adding an email attachment has a bug. Do not use contentId unless you know you absolutely need to. See this blog post for details.

*Note: When I write little tools like this I'm usually writing it because there is something I absolutely need to see in order to complete another project. These little tools are not written as projects themselves and therefore may not be very pretty or as full featured as something that I was writing as a complete project. I just needed to get some code running that gave me back the data I needed to see. There are no warranties or promises. If you find is useful then great. If not, oh well. I know the code works on CF10 at the moment. I can not be certain if it still works on other versions of ColdFusion. * Any code posted may not be totally secure or production ready. Use at your own risk. ** Unless otherwise noted, this code shall be deemed Public Domain.