Reprocessing bounced emails
The problem I have always seen with ColdFusion's internal mailer is, well, it is kinda stupid.
If it can not send an email the first time successfully, it dumps it in the undeliverable directory and ignores it forever. Even if there was nothing wrong with the email itself, it'll reject it if it can not connect to the mail server as well due to network problems or whatnot.
So I wrote a little simi-intelligent tool to allow you to reprocess an undeliverable email up to five times before it's permanently deleted off of the server (or you can modify the code to move it elsewhere for later review).
Installing is easy, stuff the file somewhere on your server (like in the CFIDE directory) and update line #6 to reflect the mail directory on your server (such as "C:\CFusion\Mail"). Then set up a scheduled task to run it every five minutes from 00:00:00 to 23:59:59.
Do be sure to purge your Undelivr directory before running it the first time - there may be quite a bit of old emails in there.
Example HTML/CFML code: Code:
<cfapplication name="MailCheck" sessionmanagement="Yes"
sessiontimeout="#CreateTimeSpan(0,0,0,1)#"
applicationtimeout="#CreateTimeSpan(0,1,0,0)#">
<!--- ColdFusion's Mail directory --->
<CFSET MailRoot="E:\CFusion\Mail">
<!--- Copy the key list form the Application scope --->
<cflock timeout="30" throwontimeout="Yes" type="EXCLUSIVE" scope="APPLICATION">
<CFPARAM name="Application.EmailKeys" default="">
<CFIF IsArray(Application.EmailKeys) EQ "No">
<CFSET Application.EmailKeys=ArrayNew(2)>
</CFIF>
<CFSET Keys=Duplicate(Application.EmailKeys)>
</cflock>
<!--- Set a "Successfully Sent Flag" so that we know if the email managed to make it through the mail server --->
<CFLOOP index="KeyLoop" from="1" to="#ArrayLen(Keys)#">
<CFSET Keys[KeyLoop][3]=0>
</CFLOOP>
<!--- Get a list of bounced mail --->
<cfdirectory action="LIST" directory="#MailRoot#/UnDelivr" name="Dir">
<CFLOOP query="Dir">
<CFSET cr=CurrentRow>
<CFIF Dir.Type EQ "File">
<!--- Read in the file and generate a unique Hash value from the contents to identify this email from all the others --->
<cffile action="READBINARY" file="#MailRoot#/UnDelivr/#Dir.Name[cr]#" variable="FileData">
<CFSET FileHash=Hash(ToBase64(FileData))>
<!--- If Ok stays zero, it's a new email that we haven't seen before --->
<CFSET Ok=0>
<!--- Loop over the bounced emails we've already logged --->
<CFLOOP index="KeyLoop" from="#ArrayLen(Keys)#" to="1" step="-1">
<CFIF Keys[KeyLoop][1] EQ FileHash>
<CFSET Keys[KeyLoop][2]=Keys[KeyLoop][2] + 1>
<CFIF Keys[KeyLoop][2] GT 5>
<!--- We've tried to send this email five times already, kill it (or if you wish, move to a different directory) --->
<cffile action="DELETE" file="#MailRoot#/UnDelivr/#Dir.Name[cr]#">
<CFSET Jnk=ArrayDeleteAt(Keys,KeyLoop)>
<CFSET Ok=1>
<CFELSE>
<!--- We've tried to send this email five times or less so far, let's try again --->
<cffile action="MOVE" source="#MailRoot#/UnDelivr/#Dir.Name[cr]#" destination="#MailRoot#/Spool/#Dir.Name[cr]#">
<CFSET Ok=1>
<CFSET Keys[KeyLoop][3]=1>
</CFIF>
</CFIF>
</CFLOOP>
<CFIF Ok EQ 0>
<!--- It's a new email, let's add it to our list --->
<CFSET NR=ArrayLen(Keys) + 1>
<CFSET Keys[NR][1]=FileHash>
<CFSET Keys[NR][2]=1>
<CFSET Keys[NR][3]=1>
<cffile action="MOVE" source="#MailRoot#/UnDelivr/#Dir.Name[cr]#" destination="#MailRoot#/Spool/#Dir.Name[cr]#">
</CFIF>
</CFIF>
</CFLOOP>
<!--- Purge emails from the array that were successfully sent --->
<CFLOOP index="KeyLoop" from="#ArrayLen(Keys)#" to="1" step="-1">
<CFIF Keys[KeyLoop][3] EQ 0>
<CFSET Jnk=ArrayDeleteAt(Keys,KeyLoop)>
</CFIF>
</CFLOOP>
<cflock timeout="30" throwontimeout="Yes" type="EXCLUSIVE" scope="APPLICATION">
<CFSET Application.EmailKeys=Duplicate(Keys)>
</cflock>