Should I Write HTML or Plain Text Emails?

Posted on July 4, 2008 at 12:36 AM in ColdFusion

One of the questions I have always asked myself when writing an application that sends out emails (most applications do) is: "should I write HTML or plain text emails?" As you know, most but not all email clients support HTML emails, and still other users disable HTML emails for one reason or another.

"Yeah," you say, "that's why ColdFusion has the 'type' attribute on the <cfmail> tag." And you are absolutely correct in saying so. But that doesn't solve the problem of how to write the email in your code; it only solves the problem of how to send the email.

The Problem: 2 Emails or Garbled Display

You see, if you write the email using (x)HTML and then send it in plain text, the recipient ends up with a horribly garbled email message filled with markup meant for display that they have to try and read around. Many people will simply give a quick click of the delete button rather than try and decipher what they're supposed to read vs. what's supposed to make it look pretty (but fails miserably in doing so in instances like this).

Years ago I actually went so far as to write an HTML *and* a plain text version, and then use a <cfif> to determine which one to send to that particular recipient. After a short time of doing that, I said "screw that" and just wrote an HTML version. Luckily I have been in a position where 99+% of my users actually view their email as HTML, so I could get away with it. Well, I am now working on a project where it is anticipated that there will be a fairly equal split between HTML and plain text recipients. So, once again, I was faced with that age-old question: HTML or plain text?

The Goal

Simply stated, the goal is to write one single email message, and have it nicely formatted and readable by both HTML-enabled email clients and plain text only email clients.

The Solution: setBodyAsText()

In my databases, I have a bit (boolean) column on the email address table named 'acceptHTML'. If set to true, then all emails sent by the application to that address will be sent as HTML. If set to false, then they get sent as plain text. As mentioned previously, this is handled nicely by the 'type' attribute on the <cfmail> tag. The other half of the equation is the setBodyAsText() method in my EmailService:

  1. <cffunction name="setBodyAsText"
  2. hint="I format the email body as plain text for sending to email addresses that do not support HTML"
  3. returntype="void"
  4. output="no"
  5. access="private">
  6. <cfargument name="email"
  7. hint="The email object"
  8. required="yes"
  9. type="any" />
  10. <cfscript>
  11. var body = email.getBody();
  12. body = reReplace(body, "</p>[^<]*<p>", chr(13), "all");
  13. body = replace(body, "<hr />", repeatString("=", 70), "all");
  14. body = reReplace(body, "#chr(9)#|<(/)*[^>]*>", "", "all");
  15. email.setBody(body);
  16. </cfscript>
  17. </cffunction>

What does this code do? Let's break it down real quick:

Line 6: Pass in our Email object
Line 12: Set a local variable to the value of getBody()
Line 13: Replace a closing paragraph tag followed by an opening paragraph tag with a carriage return
Line 14: Replace a horizontal rule with a string of equal signs, forming a plain text horizontal rule
Line 15: Replace tabs and any other HTML tags with an empty string
Line 16: Set the new, plain text body back to the Email object

That's it. Problem solved. I now have one single email message written - in (x)HTML - and can quickly and efficiently send it either as HTML or plain text.

"Hey, Quack, I don't even know what an 'EmailService' is. Can't I just use setBodyAsText() as a UDF in my application?"

Sure, a slight modification and you're golden.

  1. <cffunction name="setBodyAsText"
  2. hint="I format the email body as plain text for sending to email addresses that do not support HTML"
  3. returntype="string"
  4. output="no"
  5. access="private">
  6. <cfargument name="body"
  7. hint="The email body"
  8. required="yes"
  9. type="string" />
  10. <cfscript>
  11. body = reReplace(body, "</p>[^<]*<p>", chr(13), "all");
  12. body = replace(body, "<hr />", repeatString("=", 70), "all");
  13. body = reReplace(body, "#chr(9)#|<(/)*[^>]*>", "", "all");
  14. return body;
  15. </cfscript>
  16. </cffunction>

Now all you do is pass the body of your email into the method, and it will return it to you formatted in plain text.

"That looks simple enough, but can I see it in action?"

Ayep. View the demo.

Comments
(Comment Moderation is enabled. Your comment will not appear until approved.)

On 7/4/08 at 5:51 AM, Katie ATkinson said:

Brilliant! thanks :)

On 7/4/08 at 6:47 AM, Raul Riera said:

No, ColdFusion has a feature so you can include both types of email to your users, you can send in the same message, both HTML and text and the mail client will choose the one that fits the users needs.

On 7/4/08 at 7:21 AM, Gary Fenton said:

Rual, that's what I always do - send both plain text and html in a multi-part email.

I used extra markup in html emails to make sure it's presented nicely. Like Quack's method I write the email as plain text (just the core of the message though) but only add paragraph tags for the html mime part. Within the cfmail tag I include extra market for the html version such as an embedded logo/image and a nicely formatted signature and contact details at the end.

My method takes more effort but suites more people - those who pick up email on their mobile/cell phone and those with Outlook etc. It's also important not to make email look like spam, hence one reason why I add extra formatting. Spammers don't normally go to that trouble.

One quick tip - never try to pass cfmail emails off as Outlook emails using the mailerid argument. Spam filters watch out for that, so just make your own mailerid up, like "CNET Mailer" (if your company is CNET). I don't use the default one in case some filters have it listed as a possible bulk email.

On 7/4/08 at 12:41 PM, James Moberg said:

If HTML, both TEXT and HTML should be used. If only TEXT, send as TEXT.

The mail tools that I create allow both TEXT and HTML editable fields. (The HTML field uses a WYSIWYG editor.) The reason I do this is so that the TEXT and HTML versions can both be customized to look exactly the way the customer wants. (for example, a bold HTML header may be sent as upper-case text in the TEXT version and hyperlinks are modified to have the link displayed below the anchor text.)

If the user enters only HTML, the TEXT version is created on-the-fly with the option to edit. (This is highly recommended as it can raise a spamscore if the message is HTML-only.) If only TEXT is entered, the HTML version is not generated and/or sent.

The user is also able to choose from available templates that contain pre-configured text and HTML headers and footers as well as standardized opt-out language.

We also add a bunch of headers. This is important too as it helps the message bypass some anti-spam filters and help us identify bounced recipients when the return message doesn't identify the address (AOL Scomp reports). The headers that we add are: X-Subscribed-As, X-MessageID, X-AntiAbuse, Precedence and List-Unsubscribe (this one is important).
http://www.list-unsubscribe.com/

On 7/7/08 at 7:49 PM, Matt Quackenbush said:

@Katie - I'm not sure that 'brilliant' applies, but you're welcome nonetheless! :-)

@Raul, Gary, and James - That is some GREAT information guys. Thank you so much for your input. As I stated in my post, I've never really had to worry about emails too much before, so I haven't really placed any focus on it. It's very cool to get some input from guys that have the experience that I lack in that area.
CodeBassRadio

Latest Articles

Eventually something really brilliant and witty will appear right here.

Calendar

June 2026
S M T W T F S
« May  
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30        

Subscribe

Enter a valid email address.

The Obligatory Wish List