ColdFusion Email Validation, IsValid(), And CFMail Errors

Posted September 12, 2006 at 2:36 PM by Ben Nadel

Tags: ColdFusion

Who here hasn't had to validate an email address format at some point? Heck, I do that in practically every application that I build. And why do I do it? The truth is, I don't really care if people mess up entering their own email address. I mean sure, I validate that. But really, my main concern is NOT having the ColdFusion page request crap out. If you attempt to send a CFMail tag with a bad email address format, it will throw an error.

Sometimes, my email validation is not perfect and I end up not allowing some emails that are actually valid. This got me thinking - what is a valid email address? Or rather, what does ColdFusion think a valid email address is? There are two ways to look at this:

  1. What will pass an IsValid() method call?
  2. What will let a CFMail tag execute successfully?

To test this, I set up an array of emails and then tried sending emails out. In the example below, you will notice that I use ".ben" in the email extension a lot. That is because I don't actually want to send emails to valid addresses. I just want to test to see if they send action works (yes, I did get several hundred undeliverable emails).

  • <!--- Set up emails to test format. --->
  • <cfset arrEmails = ArrayNew( 1 ) />
  •  
  • <!--- Add emails that we know are totally bunk. --->
  • <cfset ArrayAppend( arrEmails, "" ) />
  • <cfset ArrayAppend( arrEmails, "1" ) />
  • <cfset ArrayAppend( arrEmails, "@" ) />
  • <cfset ArrayAppend( arrEmails, ".ben" ) />
  • <cfset ArrayAppend( arrEmails, "." ) />
  • <cfset ArrayAppend( arrEmails, "..." ) />
  • <cfset ArrayAppend( arrEmails, "-.-.ben" ) />
  •  
  • <!--- Add emails that test the NAME part. --->
  • <cfset ArrayAppend( arrEmails, "sarah@hotties.ben" ) />
  • <cfset ArrayAppend( arrEmails, "mary-kate@equinox.ben" ) />
  • <cfset ArrayAppend( arrEmails, "mrs.molly@teacup.ben" ) />
  • <cfset ArrayAppend( arrEmails, "libby_star@blondes.ben" ) />
  • <cfset ArrayAppend( arrEmails, "d.d.busty@domain.ben" ) />
  • <cfset ArrayAppend( arrEmails, "heather..rose@gotglue.ben" ) />
  • <cfset ArrayAppend( arrEmails, "anne--fesekis@hackley.ben" ) />
  • <cfset ArrayAppend( arrEmails, ".anna.cooper.@hockeychicks.ben" ) />
  • <cfset ArrayAppend( arrEmails, "-christina.cox-@hollywoodhotties.ben" ) />
  • <cfset ArrayAppend( arrEmails, "@campuscuties.ben" ) />
  • <cfset ArrayAppend( arrEmails, "-@justlegal.ben" ) />
  • <cfset ArrayAppend( arrEmails, ".@swank.ben" ) />
  • <cfset ArrayAppend( arrEmails, "3@atatime.ben" ) />
  • <cfset ArrayAppend( arrEmails, "/@punctuation.ben" ) />
  • <cfset ArrayAppend( arrEmails, "*@punctuation.ben" ) />
  • <cfset ArrayAppend( arrEmails, "ben&molly@kittens.ben" ) />
  •  
  • <!--- Add emails that test the DOMAIN part. --->
  • <cfset ArrayAppend( arrEmails, "sarah@hot-girls.ben" ) />
  • <cfset ArrayAppend( arrEmails, "anne@got----blondes.ben" ) />
  • <cfset ArrayAppend( arrEmails, "jessica@-cool-girl-.ben" ) />
  • <cfset ArrayAppend( arrEmails, "julie@cool.beans.ben" ) />
  • <cfset ArrayAppend( arrEmails, "julia@brazil..buddies.ben" ) />
  • <cfset ArrayAppend( arrEmails, "kate@dorm.-.girls.ben" ) />
  • <cfset ArrayAppend( arrEmails, "lara@-.ben" ) />
  • <cfset ArrayAppend( arrEmails, "michelle@36-24-36.ben" ) />
  • <cfset ArrayAppend( arrEmails, "kimmie@ladies.who.smile.ben" ) />
  •  
  • <!--- Add emails that test the EXTENSION part. --->
  • <cfset ArrayAppend( arrEmails, "ye@whatwhat" ) />
  • <cfset ArrayAppend( arrEmails, "stacy@largeladies.4" ) />
  • <cfset ArrayAppend( arrEmails, "marci@totality.123" ) />
  • <cfset ArrayAppend( arrEmails, "jen@toocute.z" ) />
  • <cfset ArrayAppend( arrEmails, "jo@cutencurley.xy" ) />
  • <cfset ArrayAppend( arrEmails, "pam@waycute.xyz" ) />
  • <cfset ArrayAppend( arrEmails, "gina@cowgirls.a4b" ) />
  • <cfset ArrayAppend( arrEmails, "linda@lumpyladies.abcdef" ) />
  • <cfset ArrayAppend( arrEmails, "jane@ilikeemlarge.abcdefghij" ) />
  •  
  •  
  • <!--- Create a table to output the results. --->
  • <table border="0" cellspacing="0" cellpadding="0">
  • <tr>
  • <td>
  • Email
  • </td>
  • <td>
  • IsValid()
  • </td>
  • <td>
  • Email Success
  • </td>
  • </tr>
  •  
  • <!--- Loop over the emails and validate them. --->
  • <cfloop index="intI" from="1" to="#ArrayLen( arrEmails )#" step="1">
  •  
  • <!--- Try sending out email. --->
  • <cftry>
  •  
  • <!--- Send mail. --->
  • <cfmail
  • to="#arrEmails[ intI ]#"
  • from="xxx@yyy.zzz"
  • subject="This is a test email">
  •  
  • This is a test email.
  • </cfmail>
  •  
  • <!--- Set success flag. --->
  • <cfset blnEmailSuccess = true />
  •  
  • <!--- Catch email errors. --->
  • <cfcatch>
  •  
  • <!--- Email failed. Set success flag. --->
  • <cfset blnEmailSuccess = false />
  •  
  • </cfcatch>
  •  
  • </cftry>
  •  
  •  
  • <!--- Check for validity. --->
  • <cfset blnValid = IsValid( "email", arrEmails[ intI ] ) />
  •  
  • <tr>
  • <td>
  • #arrEmails[ intI ]#
  • </td>
  • <td>
  • #YesNoFormat( blnValid )#
  • </td>
  • <td>
  • #YesNoFormat( blnEmailSuccess )#
  • </td>
  • </tr>
  •  
  • </cfloop>
  • </table>

The results are kind of surprising. I was a bit shocked how many emails actually can get sent through CFMail with completely horrible email addresses. Here are the results (I have modified the table for display):


 
 
 

 
Email Form Errors Using IsValid() and CFMail  
 
 
 

As you can see, only THREE emails crashed the ColdFusion CFMail tag. It has hardly any issues. The salmon rows are the rows where IsValid() and CFMail disagree as to what is a valid email address. Very interesting indeed. Honestly, I think my email validation can be MUCH MUCH more simple (if only caring about the CFMail tag crashing). But I guess, I can start to use IsValid(). But, and I am no expert on email address formatting, but IsValid() seems very relaxed about some of the stuff above.



Reader Comments

Sep 12, 2006 at 9:00 PM // reply »
18 Comments

This one is a good one for Damon Cooper for enhancement to Scorpio. You can contact him or I can file an enhancement if you'd like. Great work by the way.


Sep 12, 2006 at 10:44 PM // reply »
10,640 Comments

Sami,

I just emailed Damon. But I am a little fish and I never hear back from anyone. Feel free to get in contact with him if you think it will help things along.

Thanks!


Sep 13, 2006 at 1:18 AM // reply »
1 Comments

Perhaps more information will help.

The IsValid() function uses the following regular expression to determine if the email is valid:
^[a-zA-Z0-9-'\+~]+(\.[a-zA-Z0-9-'\+~]+)*@([a-zA-Z_0-9-]+\.)+[a-zA-Z]{2,7}$

The CFMail tag uses the Sun Java class javax.mail.internet.InternetAddress parse() function. Since the implementation uses JavaMail, this is how we generate the InternetAddress objects that we pass in for the addresses (to, from, cc, etc).

The "strict" attribute is turned on. The JavaDoc says of this:

"Parse the given sequence of addresses into InternetAddress objects. If strict is false, simple email addresses separated by spaces are also allowed. If strict is true, many (but not all) of the RFC822 syntax rules are enforced. In particular, even if strict is true, addresses composed of simple names (with no "@domain" part) are allowed. Such "illegal" addresses are not uncommon in real messages.

Non-strict parsing is typically used when parsing a list of mail addresses entered by a human. Strict parsing is typically used when parsing address headers in mail messages"

See the JavaDoc at http://java.sun.com/products/javamail/javadocs/javax/mail/internet/InternetAddress.html

Hope that clears it up for you.


Sep 13, 2006 at 3:20 AM // reply »
34 Comments

i've done some work w/javamail & what tom says is true (of course). even strict parsing passes a lot of addresses some folks would consider "bad", though by the same definition so does the RFC.

i guess complain to sun: http://java.sun.com/products/javamail/index.jsp better yet, if you get on the javamail list you can complain directly to bill shannon.


Sep 13, 2006 at 7:26 AM // reply »
10,640 Comments

Hey guys, I really appreciate the information. I am not familiar at all with the javax classes. I see that I can create them using CreateObject(). That is kind of cool.

But please, I don't want to be misunderstood. I wasn't attacking email validation. I DON'T want to complain to anyone. It's not important to me that some emails get through that maybe are not the best. As I said, I don't want the page to crash and from what I can see, I can relax a bit of my email validation. That was really my main point.

But again, thanks for all the feedback.


Apr 17, 2007 at 1:41 PM // reply »
168 Comments

This is great information. Thanks for posting this, Ben and Tom.

However, it confirms my fears about using ColdFusion's email address validation (through isValid() or cfparam), since the regex Tom posted is a little crazy, IMO (despite my acceptance that an email validation regex should not follow RFC 822 to the letter). For example, it allows underscores in the hostname (which technically makes it an invalid domain name), and yet there's no support for internationalized domain names (or usernames). And what's with the seemingly arbitrary seven-character top-level domain cap, when the longest official TLDs (.museum and .travel) are six characters? Is it trying to support reserved TLDs like .example and .invalid? If so, what about .localhost, which is eight characters? There are a number of other issues I could point out as well.

In any case, that regex (and any others which control validation provided by isValid/cfparam) should be in the LiveDocs.


Dec 6, 2007 at 3:14 PM // reply »
3 Comments

Ahh, email validation is not actually correct for many of those entries - http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx

I recently got a support request for an email that looks like

name&name@domain.com

On research, the "&" actually appears to be valid, although it is though to be not valid.

This is causing some problems.


Dec 10, 2007 at 8:14 AM // reply »
10,640 Comments

@Stephen,

I just recently heard of a big problem that was caused by the & characters. It was something bit, like New York Times email addresses or something. Can't remember where I heard it.

Just tried running this:

#IsValid( "email", "name&name@domain.com" )#

... and it returns NOT valid.


Dec 4, 2008 at 11:06 AM // reply »
1 Comments

One of my e-mail addresses has the domain with format @xx.xxxxxx.com, yet it seems like you might exclude that as an invalid e-mail address (either that or you were checking to see if the system would trip over a perfectly valid e-mail address, I'm not clear what your expected result was). My point is, although validation will help reduce human error and keep out some spam, being too stringent may block out a perfectly valid e-mail. Please exercise caution!


Dec 4, 2008 at 11:17 AM // reply »
10,640 Comments

@Ryan,

I am not sure what you are saying. From my testing above, that format of email address IS valid. Notice that the address:

julie@cool.beans.ben

... passed both IsValid() and a successful CFMail execution. Sub-domains clearly work in ColdFusion.

Am I confused about what you are saying?


SP
Jul 17, 2009 at 10:08 AM // reply »
3 Comments

What is the trick to using cfmail to send an email to an address with a single quote in it?

ie micky.o'flannigan@somedomain.com


Jul 18, 2009 at 1:19 PM // reply »
10,640 Comments

@Steve,

Can you even use single quotes in an email address? I am not sure that is even valid.


Jul 18, 2009 at 5:24 PM // reply »
168 Comments

@Ben Nadel, yes, it's valid according to RFC 2822--the special characters allowed as part of an email address's username are _!#$%&'*+/=?`{|}~^.-. At my last job I ran into single quotes in email addresses a lot. It's unfortunate that a lot of naïve validation (including CF's isValid, etc.) disallows it.


Jul 18, 2009 at 5:28 PM // reply »
10,640 Comments

@Steven,

Really?!? Emails can use all of those characters? Bananas!


she
Aug 11, 2009 at 4:07 AM // reply »
1 Comments

why cc in cfmail not function if more than 1 cc at the same time, could someone help me?


Sep 6, 2009 at 2:51 PM // reply »
10,640 Comments

@She,

It should work as long as the are comma-separated.


Sep 9, 2009 at 2:16 AM // reply »
6 Comments

I unfortunately discovered the cfmail crashing when I switched from OpenBlueDragon to CF8. Apparently BD doesn't validate the email address. Someone entered an email of http://blah@somewhere.com. This was old code (CF 5) and obviously my validation was faulty. Probably a good thing it crashed and forced me to do a better job.


Sep 12, 2009 at 10:47 PM // reply »
10,640 Comments

@Don,

Did this throw a CF error? Or did it just go in the undeliverable folder?


Sep 12, 2009 at 10:58 PM // reply »
6 Comments

It threw a cf error. Since it was run as a scheduled task I didn't find it until I trolled logs after a couple of subscribers said they weren't getting their email.


Sep 12, 2009 at 11:04 PM // reply »
10,640 Comments

@Don,

Ah, gotcha. So, what would have happened with OBD? It must have errored out at some point?


Sep 12, 2009 at 11:13 PM // reply »
6 Comments

It is entirely possible that the event did not occur in BD as the errant subscriber may not have been present so my assumption that BD didn't fail may be false.
The "phantom processes" disappeared after a day or two.
To avoid any future occurences I have made all tasks run once and then have the task delete the task and regenerate it to start it at the appropriate time. The drawback to that is that if the site is down at the time the task is supposed to run the new task won't be created. I have solved that with a cron job which runs every 30 mins that uses curl to run a cfm that checks for missing tasks and recreates them.


Nov 16, 2009 at 4:21 PM // reply »
1 Comments

There have obviously been some changes in CF9. An address with an erroneous trailing period ( e.g. john@keyston.ca.) does not pass the isvalid() check in either CF8 or CF9. However, in CF8 it does not crash CFMAIL, and the mail arrives at the intended destination. In CF9, it crashes CFMAIL, as I found out the hard way! I do not know, however, how extensive the changes in CF9 are.


Nov 16, 2009 at 4:26 PM // reply »
10,640 Comments

@John,

Well, I guess it's a step in the right direction.


May 19, 2010 at 6:19 AM // reply »
3 Comments

hi - does anyone have a fix for emails with an ampersand in them eg name&name@domain.com

using isvalid("email","name&name@domain.com") - results in cf (incorrectly) saying that email is invalid - when in reality it is valid (i know coz I've just emailed a customer on their address which contains an ampersand to check and works).

I'm presuming that isvalid uses some regex (somewhere in java?) so maybe one could edit that regex to allow for ampersands?

Anyone know how?

Thanks guys

Nick


May 22, 2010 at 9:58 AM // reply »
10,640 Comments

@Nick,

There's probably no way to edit the core regular expression that is being used. But, if you scroll up to Tom Jordahl's comment, you'll see the regular expression that ColdFusion is using under the hood. You could create your own UDF (user defined function) that adds the & to the appropriate character class.


May 24, 2010 at 5:30 PM // reply »
3 Comments

@Ben

Thank you very much for your reply, sorry I missed Tom's comment. But you are right, that is exactly what I was looking for so thank you. I'll post our amended expression here when I'm done.

Thanks again for your help Ben

best regards

Nick


May 25, 2010 at 5:34 AM // reply »
3 Comments

ok so i'm not strong on regex but i *think* this works

^[&-&a-zA-Z0-9-'\+~]+(\.[&-&a-zA-Z0-9-'\+~]+)*@([a-zA-Z_0-9-]+\.)+[a-zA-Z]{2,7}$

ie

<cfset temp.myemail = "name&name@domain.com" >

<cfif refind("^[&-&a-zA-Z0-9-'\+~]+(\.[&-&a-zA-Z0-9-'\+~]+)*@([a-zA-Z_0-9-]+\.)+[a-zA-Z]{2,7}$",temp.myemail) eq 1>
email is fine
<cfelse>
bad email
</cfif>

you can see i've just added &-& in 2 locations to the regex Tom posted. I'm sure there is a better way but I post my findings here in case it helps anyone else.

Maybe someone who understands regex better can correct my slightly hacky way of shoehorning the ampersand character into the equation.

Thanks again for your help Tom and Ben


Jun 8, 2010 at 9:56 AM // reply »
10,640 Comments

@Nick,

That looks good to me. One small note - in a character class, not everything has to be a range of characters (ie. &-&). If you simply add the literal &, that will be enough. Ranges are are only needed for multi-character ranges; otherwise, literals will suffice.


Aug 8, 2010 at 6:47 PM // reply »
16 Comments

So, I found what I think is the ultimate EMAIL validation script. It was created using PHP by Dominic Sayers and apparently it's the best one out there. It follows the email spec to a T.

I began to convert it into a nice CFFUNCTION, but then I ran across your post here.

So just to clarify something, are you saying that no matter what, even if you validate an email address (using this script or whatever), that it might not matter because CFMAIL may still reject the address based on it own regexp? If that's the case, that really really sucks.

Sorry if I'm misunderstanding this, but I didn't want to go through all this work and then find out that it didn't matter. Is it possible you could clarify?

Thanks

p.s. Dominic's script can be found here. It's worth a look...
http://code.google.com/p/isemail/ (Project HOME)
http://code.google.com/p/isemail/source/browse/trunk/is_email.php (CODE)


Aug 8, 2010 at 6:59 PM // reply »
10,640 Comments

@Doug,

I think just the opposite; it appears that the CFMail tag is *much* more relaxed than the isValid(email) method. If you put your own validation in place, I am sure you will get fine results.


Aug 8, 2010 at 7:10 PM // reply »
16 Comments

Ok, so it's just the isValid function that is using that simple regexp. That makes sense then. Cool.

As always, thank for the informative response! (And on a Sunday to boot!)

-Doug


Aug 8, 2010 at 8:16 PM // reply »
10,640 Comments

@Doug,

Yeah, from what I can tell, isValid() is more limited than CFMail. And no worries on the response - I'm trying to "chunk" my responses in my free time.


Oct 11, 2010 at 12:24 PM // reply »
2 Comments

@nick way:

your RegEx doesn't pass the underscore.

eg:
first_name@doimain.com

is a bad email using your RegEx


Oct 17, 2010 at 4:57 AM // reply »
1 Comments

Note that domain names can use foreign characters in the meanwhile like ö ü ä in German for example... I think they are not covered by the regex mentioned in this thread!


Oct 20, 2010 at 10:46 PM // reply »
10,640 Comments

@Guest,

I had to Google that when you mentioned it. Looks like this is a very new thing for domain registration. It will be interesting to deal with.


Oct 21, 2010 at 5:38 PM // reply »
2 Comments

I am a German living in NewYork now for quite some time and asking myself if these special letters are valid internationally. Especially if Germans are VERY comfortable writing 'ö' as 'oe', 'ü' as 'ue' and 'ä' as 'ae'.
Where does it end. How about some chinese or japanese symbols? It is getting a bit to specific for me at this point.


Oct 21, 2010 at 10:08 PM // reply »
10,640 Comments

@PixelGrinch,

It's definitely gonna be interesting to navigate to such domains. I don't know how to type in foreign characters, so I would only be able to Google for these sites. Although, maybe that's not a problem??? After all, so much of navigation is done via Google these days anyway.


Dec 22, 2010 at 11:03 AM // reply »
1 Comments

almost need to just check for everything!
*@*.* hehe


Aug 26, 2011 at 12:34 PM // reply »
1 Comments

@Tom,
There is a small difference n the REGEX expression on this post and the REGEX expression on your blog at http://tjordahl.blogspot.com/2006/09/coldfusion-email-validation-isvalid.html. The posting on Ben's blog omits underscore as a valid character in user names by using 'a-zA-Z0-9' instead of 'a-zA-Z_0-9'.

It looks to me like the one in your (Tom's) blog is correct.


Sep 12, 2011 at 9:25 AM // reply »
4 Comments

@Art,

If I interpret the RFC2822 spec (http://tools.ietf.org/html/rfc2822, section 3.2.4) correctly, the underscore should be accepted in the 'name' part of an email address - just like these characters: !#$%&'*+-/=?^`{|}~

Domain names (RFC1034 and RFC1035) seem less strictly defined, because those standards write about a "preferred name syntax". That syntax includes only letters, numbers and the hyphen.

I suppose the newer internationalized domain names are subject to certain rules as weel, but my admittedly cursory search hasn't turned them up.

Anyway, even if 'isValid()' could use enhancements, it's better than nothing!


Sep 21, 2011 at 3:12 PM // reply »
1 Comments

>>I don't know how to type in foreign characters

You are a genius at CF yet you can't add another keyboard layout through the Control Panel? I am sure you are not being serious here.


Jan 12, 2012 at 2:48 AM // reply »
2 Comments

So glad i found this post. Im developing an intranet app for a client, and they seem to enjoy typing the emails incorrectly.

Im glad , as now i can validate them when they input the emails and ensure the DB does not end up with a load of false ones.

I will still have to check bounce mails to ensure they do exist.



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 12, 2012 at 3:37 AM
Learning ColdFusion 8: CFImage Part III - Watermarks And Transparency
Hi Ben, Just to ask currently it is placed bottom right corner, if i need to replace the same rendered image on the bottom left side or in the bottom center, how that can be calculated. bottom ce ... read »
Feb 11, 2012 at 9:29 PM
Use jQuery's SlideDown() With Fixed-Width Elements To Prevent Jumping
I can't say how glad I am that I found your post. Thank you very much. ... read »
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »