Handling/Testing of Emails in a ColdFusion App

This post is more than 2 years old.

prims asked me:

In our testing and staging region I would like to stop sending emails. I thought the easiest way is to not to have anything in Mail settings. But then not all the users at our work environment have access to Administrator and wouldn't like to make request to System Administrator.

Some other co-worker suggested wrapping cfmail with some condition so that it will not send any emails in those region.

What is the best approach? Any suggestions. Thanks as always for looking into this issue.

I hesitate to say I have the best answer (which is the main reason I wanted to answer in a blog entry versus an email!) but here are some ideas to consider:
  • If it isn't too late, you can consider building a mail service component. This component would handle all mail tasks. That means nothing else in the system would use cfmail, but would instead ask the mail service to send email for it. This then makes it easy to change what exactly happens when a mail is requested. A configuration setting could be used to tell the mail service to simply log the mail instead of sending it. Or perhaps to create a simple text file that is accessible to the end user. I've done this before for reasons like this. It also lets me do things like "always CC someone" or "set TO to me in staging". Basically it gives me a way to override cfmail at the code level.
  • You mentioned just setting the mail settings to an empty string. If you do that then any code using cfmail will throw an error. I believe instead you want them to just enter "localhost", and as long as they don't have a mail server the mails won't go anywhere. But you said not everyone had access to the cfadmin. That may be something you want to fix. If your developers aren't using their own machines then you should look into "fixing" that as well!
  • In the past I've used a few simple mail servers that let me 'fake' a real mail server. I don't use it as much since you can easily view ColdFusion's undelivered email, but if I want the "real" experience I'll switch to a free mail server. I've used hMailServer for this in the past. You can set it up to accept global email patterns and just address them to one person. I know you said you wanted to stop emails - but this is another option that may be useful.

All things considered - I'd do the first option. You can get complex and use ColdSpring to manage this, but if you are looking for a quick fix, it shouldn't take too long to switch your existing code over. Anyone else have better ideas?

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by JF posted on 6/18/2011 at 2:28 AM

I recently started writing a custom tag for this at my workplace. I never got to finish it but the idea was to simply wrap cfmail completely with the same attributes.

Implementing it is as easy as doing a global replace for <cfmail by <cf_mail

It's sorta like a service, but more gettho. The biggest pro being that it doesn't require as much refactoring of the application.

Comment 2 by Django posted on 6/18/2011 at 2:58 AM

We're doing something along the lines of the first option you've outlined, with positive results.

We have an EmailService.cfc as part of a set of utility services that make it into most of our projects. This is where the actual cfmail tag is employed. As the majority of our development and testing is done from a specific IP range (or localhost), this mail service checks the current IP against a set of defined dev/staging IP's and then decides what to do. If the environment is development/staging, emails are re-routed to an internal, coldspring defined, email address. If not, then the email is sent to its intended target as one would expect.

I can highly recommend this, or some variation of this approach. Ray, you've even suggested a couple of potential upgrades for us to consider as well.

Comment 3 by MikeG posted on 6/18/2011 at 3:30 AM

We do something similar here as well; a simple email wrapper, custom tag or function for sending email. If not the prod environment the email is sent to a "variable defined" email address. Sometimes this variable is the logged in user's email address (assuming they are a dev or tester), sometimes it is a shared email address. One thing we do add though in the body of the email is what, had this been production, the real attributes would have been (to, from, cc, bcc, etc). This way you don't bother or confuse the real users of the production app while doing dev/test but you can still validate that the email would have been routed correctly.

Comment 4 by Phil Duba posted on 6/18/2011 at 3:36 AM

Ray, I have an even better suggestion. I set my IP address for our mail server 127.0.0.0 in our testing environments then I put our internal authentication mechanism in front of your Spoolmail application along with a list of users who would need to verify the mail format and that's how we do email confirmation for our ColdFusion applications.

Comment 5 by Raymond Camden posted on 6/18/2011 at 3:38 AM

@Phil: Ah - nice. I thought folks stopped using SpoolMail when CF9 included something similar in it. :)

Comment 6 by Phil Duba posted on 6/18/2011 at 3:46 AM

Remember though, the CF9 one is only accessible in the admin and it doesn't allow for editing of the emails themselves. Spoolmail lets me go in to the undelivered emails and fix the mistyped email address or any other issues present with the delivery strings without the need to download the files off the server and then manual fix and reupload.

Comment 7 by Ben Arledge posted on 6/18/2011 at 9:19 AM

I would suggest Amazon Simple Email Service (SES). I believe there is a CF wrapper on RIAForge.

Comment 8 by Raymond Camden posted on 6/18/2011 at 6:00 PM

Does SES also have simple support for "don't really email, just log"?

Comment 9 by Jade Cady posted on 6/18/2011 at 10:03 PM

We use Coldbox for most of our applications currently and I have been really happy using the "Environment Safe Mail Service" interceptor. I have the environment add the interceptor on our development server. It can be set it to override all emails sent to a single address so that testers can receive and review all the emails that would have been sent to anyone, or it allows me to just not send any emails at all. And for my local build environment I have "smtp4dev" installed so it picks up all the emails being generated and I can see what was being generated as I build/test.

It seems that a non-Coldbox wrapper of the Email interceptor would be very helpful.

Comment 10 by Gary F posted on 6/19/2011 at 1:25 AM

I run Dev Null SMTP Server which is a dummy mail server. Set CF to use it as its mail server and the emails don't go anywhere at all, but it lets you verify how many emails would have been sent and who the recipients would have been. And you don't have to change your CFML code to use it.

http://www.aboutmyip.com/Ab...

Comment 11 by Sean Coyne posted on 6/19/2011 at 4:29 AM

I use the DevNull server too. Creates a copy of each outgoing email in a folder on your system so you can verify the formatting and other details.

Comment 12 by prims posted on 6/19/2011 at 6:32 PM

Ray,
Thanks for blogging this issue and thanks for all those who posted as well. Ray I didn't get a chance to talk to developers yet because of the weekend. I like the idea of having mail service component that definetly gives us full control. But for a temporary fix I am not sure yet but I am guessing it might be Dev Null SMTP server simply because no need to change any code base.

Comment 13 by Henry posted on 6/21/2011 at 12:27 AM

ColdBox has a MailService plugin that solves this problem...

http://www.aliaspooryorik.c...

http://wiki.coldbox.org/wik...

Comment 14 by Ben Arledge posted on 6/21/2011 at 8:39 AM

Ray, I don't think it would be too hard to add a parameter to the cfc call that forces a log rather than a send. I think the SES option is great for portability... and nobody enjoys maintaining a mail server. :)

Comment 15 by Raymond Camden posted on 6/21/2011 at 2:51 PM

"and nobody enjoys maintaining a mail server"

Amen to that. The last time AWS went down - I remember thinking - my own boxes go down - and I don't think I'm any quicker than Amazon.

Comment 16 by Josh Curtiss posted on 6/27/2011 at 7:38 PM

Like some of the other guys, I wrap cfmail with a cf_mail tag, although my primary motivation back in the day (started this 10 years ago) was to log the mail to a SQL database. Added a couple additional fields (application name sending the email, a generic "purpose" field used for searching/filtering, etc). And also made the custom tag always BCC a particular address if no BCC is passed in from the code. This way I have a single email account that shows all email being sent from all apps on my intranet. Then I just added a "debug" attribute to the custom tag that will auto-set the TO and CC attributes to a set address if debug="true". Combine that with an application variable that is set in the app configuration that indicates whether the app is in dev or production mode, and accidental emails during development become a non-issue! :)