Update to my ColdFusion Mail Throttler

This post is more than 2 years old.

Last week I wrote a quick proof of concept that demonstrated a simple mail throttler for ColdFusion. The idea was that you may have some automatic mail process that you do not want to get overwhelmed with. Read the previous blog entry for full details and the original code. Dan Switzer commented that my method for "merging" dynamic emails (with a regex) could be done much simpler if I allowed people to simply name the emails. So with that in mind I've added the support for a cachename value. This actually takes priority over regex as the more I think about it, the more I think folks will prefer it over the regex option. Here is the new component.

<cfcomponent output="false">

<cfset variables.cache = {}>

<cffunction name="throttleSend" access="public" output="false" returnType="boolean"> <cfargument name="mail" type="struct" required="true" hint="Structure of args for the mail."> <cfargument name="limit" type="numeric" required="true" hint="Number of minutes to wait before sending again."> <cfargument name="cachename" type="string" required="false" hint="Used to name the email in terms of uniqueness. If used, the email contents won't be used to check for uniqueness."> <cfargument name="regex" type="string" required="false" hint="This regex is performed on your mail body. Helps remove items that may be dynamic in the body but should not be considered for caching.">

&lt;!--- used for required mail tags ---&gt;
&lt;cfset var reqlist = "to,from,subject,body"&gt;
&lt;cfset var l = ""&gt;
&lt;cfset var body = ""&gt;
&lt;cfset var cacheBody = ""&gt;
&lt;cfset var hashKey = ""&gt;

&lt;!--- quickly validate the mail object ---&gt;
&lt;cfloop index="l" list="#reqlist#"&gt;
	&lt;cfif not structKeyExists(arguments.mail, l)&gt;
		&lt;cfthrow message="mail object is missing required key #l#"&gt;
	&lt;/cfif&gt;
&lt;/cfloop&gt;

&lt;!--- Ok, first, create the hash ---&gt;
&lt;cfset body = arguments.mail.body&gt;
&lt;cfif structKeyExists(arguments, "cachename")&gt;
	&lt;cfset hashKey = arguments.cachename&gt;
&lt;cfelseif structKeyExists(arguments, "regex")&gt;
	&lt;cfset cacheBody = rereplace(body,regex,"","all")&gt;
	&lt;cfset hashKey = hash(arguments.mail.to & " " & arguments.mail.subject & " " & cacheBody)&gt;
&lt;cfelse&gt;
	&lt;cfset hashKey = hash(arguments.mail.to & " " & arguments.mail.subject & " " & body)&gt;
&lt;/cfif&gt;


&lt;!--- If we already sent it and it hasn't expired, don't do squat ---&gt;
&lt;cfif structKeyExists(variables.cache, hashKey) and dateCompare(now(), variables.cache[hashKey]) is -1&gt;
	&lt;cfreturn false&gt;
&lt;/cfif&gt;

&lt;!--- Ok, so we need to mail ---&gt;
&lt;cfmail attributecollection="#arguments.mail#"&gt;#body#&lt;/cfmail&gt;

&lt;cfset variables.cache[hashKey] = dateAdd("n", arguments.limit, now())&gt;
&lt;cfreturn true&gt;

</cffunction>

</cfcomponent>

And here is a new test script that shows all three options .

<cfapplication name="mtdemo">

<cfif not structKeyExists(application, "throttler") or structKeyExists(url,"init")> <cfset application.throttler = new mailthrottle()> </cfif>

<cfset mailOb = { to="ray@camdenfamily.com", from="ray@camdenfamily.com", subject="Error about X!", body="This is the body of the email." }>

<cfset res = application.throttler.throttleSend (mailOb,2)>

<cfoutput>result was #res#</cfoutput> <p/>

<cfset mailOb = { to="ray@camdenfamily.com", from="ray@camdenfamily.com", subject="Error about X!", body="This is the body of the email. Random: #randRange(1,100)#" }>

<cfset res = application.throttler.throttleSend (mail=mailOb,limit=2,regex="Random: [0-9]{1,3}")>

<cfoutput>result was #res#</cfoutput>

<p/>

<cfset mailOb = { to="ray@camdenfamily.com", from="ray@camdenfamily.com", subject="Error about Y!", body="This is the body of the email. Random: #randRange(1,100)#" }>

<cfset res = application.throttler.throttleSend (mail=mailOb,limit=2,cacheName="Error Email Y")>

<cfoutput>result was #res#</cfoutput>

The final example shows the cacheName in action. Useful?

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 Mark Ross posted on 10/27/2010 at 10:41 PM

I read your blog about this when you posted it last week, but commented to myself "I've never gotten a flood of emails, guess I don't need this". Then of course, last night my inbox was inundated with 400+ emails. Re-read your post this morning and got it implemented right away. Thanks a lot for this helpful tool!

Comment 2 by Raymond Camden posted on 10/30/2010 at 6:23 AM

Glad you found it useful!