ColdFusion is capable of high-output mail delivery. One problem with the ColdFusion server that is not addressed by any built-in functionality is what happens when an email cannot be delivered from the ColdFusion server to the mail server. This article will address one possible way to handle undeliverable messages. This method only works in instances where you control your own server, however, as the central spool folders for emails in ColdFusion are server-wide rather than site-wide.

When ColdFusion attempts to send a message, it first connects to the mail server. Upon receiving a response from the server, the message is delivered to the mail server which will in turn deliver the message to the recipient. When ColdFusion cannot connect, however, the message moves from the spool folder (cfusionmx\mail\Spool) to the undeliverable folder (cfusionmx\mail\Undelivr). This can happen for several reasons:

  1. Mail server is not connected to the Internet due to any number of possible reasons.
  2. Mail server is too busy due to traffic.
  3. Mail server cannot handle the traffic from the ColdFusion server.

After that happens, the mail just sits. No notification is sent to the recipient, sender, or site administrator. This is a problem.

We want several things to happen here. First, we want the mail to be resent if it can be. Secondly, if the mail cannot be resent we want to know about it so that something can be done about it. Third, we want to be able to administer this from the web.

Resending mail

To resend a message, the only thing that needs to be done is to move the undeliverable messages from the undeliverable folder to the spool folder. This is a fairly easy process, and involves some simple ColdFusion code and a scheduled task in the ColdFusion Administrator. The code below will handle this. It is commented inline.

<!--- Get the contents of the Undelivr folder --->

<cfdirectory
 name="rsDirectory"
 action="list"
 directory="c:\cfusionmx\mail\Undelivr\" />

<!--- Create a loop of files from the Undelivr directory --- >
<cfoutput query="rsDirectory">

<!--- Move each file from the Undelivr folder to the Spool folder--->
<cffile action = "move"
 source = "c:\CFusionMX\Mail\Undelivr\#rsDirectory.name#"
 destination = "c:\cfusionmx\mail\spool\" />

</cfoutput>

This file should be saved as resend.cfm in your web directory and can be run manually at any time, such as right after you send a blast to a mailing list. It should also be set up as an automated task?especially if your site sends automated emails to customers, or automated error emails to the site administrator. The following steps will set up and automated task in CF MX, as shown in Figure 1:

  1. Open the ColdFusion Administrator
  2. Click the Scheduled Tasks link under Debugging and Logging
  3. Click the Schedule New Task button
  4. Give the task a name, such as ResendUndeliverables
  5. Set the task to trigger daily every hour from 12 midnight to 6 AM. This effectively sets up the task to only move files during off hours. You can also set it up to work continuously throughout the day if you prefer.
  6. Set up the URL for the file.

figure1
Figure 1: The ColdFusion Administrative interface for setting up scheduled tasks

With this file set up, your undeliverables will be resent, and will have several attempts made to resend them.

Notification

What happens when there is a problem with the message, however? Some email spool files will fail for reasons other than the connection to the mail server. For these files we'll set up another notification service to notify you when they exist. The following code listing, saved as notify.cfm, will look at the Undelivr directory and notify you by email when files exist there:

<!--- Get the contents of the Undelivr directory --->
<cfdirectory name="rsDirectory"
 action="list"
 directory="c:\cfusionmx\mail\Undelivr\">

<!--- Count the number of messages in the directory --->
<cfset Undeliverable = rsDirectory.recordcount>

<!--- If the count isn't zero, send a notification email to the admin --->
<cfif Undeliverable NEQ 0>
  <cfmail to="admin@mydomain.com"
   from="admin@mydomain.com"
   subject="Undeliverable mail in folders">
There are #Undeliverable# emails undelivered in the ColdFusion server.

Examine messages at:
http://www.mydomain.com/admin/undeliverables.cfm
  </cfmail>
</cfif>

This code will also have to be set up as a scheduled task. This task should occur once daily so that you can constantly monitor the state of the undeliverables. You can follow the same steps as you did earlier to set up the scheduled task, however this one should run once daily. You can alter this to meet your own needs, of course. The URL listed in the email is going to point to the files we are creating next.

Examining the Undelivr folder

Now that you have the functionality in place to resend the valid undeliverable emails, you need to do something about invalid files. There can be numerous reasons for an invalid file. For one, a mail server setting may be incorrect or missing. There could also have been a server error that creates a blank spool file. This is a known problem with ColdFusion. Whatever the reason, when the messages cannot be resent after the 6 attempts set up in your scheduled tasks, there is a problem with the message. The following code can be used as undeliverables.cfm to examine the contents of the Undelivr folder:

<html>
<head>
<title>Undelivr Directory</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<h1>Examine the Undelivr Directory</h1>

<!--- Get the contents of the Undelivr folder --->
<cfdirectory
 name="rsDirectory"
 action="list"
 directory="c:\cfusionmx\mail\Undelivr\" />

<p>Click link to examine, modify, or delete message</p>

<table>
  <tr>
    <th>Message</th>
    <th>Date</th>
    <th>Filename</th>
  </tr>
<!--- Create a loop of files from the Undelivr directory --->
<cfoutput query="rsDirectory">
  <!--- Display the results --->
  <tr>
    <td>#rsDirectory.currentrow#</td>
    <td>#rsDirectory.dateLastModified#</td>
    <td><a href="examine.cfm?email=#rsDirectory.name#">
        c:\CFusionMX\Mail\Undelivr\#rsDirectory.name#</a></td>
  </tr>
</cfoutput>
</table>
</body>
</html>

The file will display a list of messages in your undeliverable folder, as shown in Figure 2. The link will pass the name of the email spool file in a URL variable named email to the examine.cfm page.

figure2
Figure 2: Interface for the undeliverable.cfm page

Finally, we need to create the examine.cfm file that will allow you to examine the individual message and either delete it or fix it. The file will make much use of the <cffile> tag to read, write, and delete the message. The code is shown below and is commented inline:

<html>
<head>
<title>Examine Undeliverable Message</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<h1>Examine Undeliverable Message</h1>

<!--- If the email variable comes from the URL, show the form
and display the email spool message.
Also show a Fix and Delete button --->

<cfif IsDefined("url.email")>
  <cffile
   action="read"
   file="c:/cfusionmx/mail/undelivr/#url.email#"
   variable="theEmail">

<form name="form1" method="post" action="examine.cfm">
<p>
<textarea name="theEmailText" cols="80" rows="20"><cfoutput>#theEmail#</cfoutput></textarea>
</p>

<p><input name="delete" type="submit" id="delete" value="Delete">

<input name="fix" type="submit" id="fix" value="Fix">

<input type="hidden" name="email" value="<cfoutput>#url.email#</cfoutput>">
</p>
</form>
</cfif>

<!--- If the form is submitted, check to see if the Delete button was
      clicked. If so, delete the message from the Undelivr folder. --->

<cfif isdefined("form.delete")>

  <cffile action="delete" file="c:/cfusionmx/mail/undelivr/#form.email#">

  <cflocation url="undeliverables.cfm">

</cfif>

<!--- If the form is submitted, check to see if the Fix button was
      clicked. If so, write the contents of the message to the
      Spool folder and delete the message from the Undelivr folder. --->

<cfif isdefined("form.fix")>

  <cffile action="write"
   file="c:/cfusionmx/mail/spool/#form.email#"    output="#form.theEmailText#">

  <cffile action="delete"
   file="c:/cfusionmx/mail/undelivr/#form.email#">

  <cflocation url="undeliverables.cfm">

</cfif>

</body>
</html>

The form displays the contents of the spool file (shown in Figure 3), which includes some of the email headers. You can modify the file and attempt to resend it if you see an obvious problem, such as a badly formatted email address, although CF MX 6.1 has changes that prevent most badly formatted email addresses from even getting to the spool folder. You can also delete the message. After performing an action on the message, you will be redirected to the undeliverables.cfm again, which should now display the new list of messages left in the Undelivr folder.

figure3
Figure 3: Interface for the examine.cfm file

To test out the new functionality, you will need to make a few undeliverable emails. You can easily do this by sending an email using a non-existent email server. Put the following code on a blank page and browse it from your ColdFusion server to create a bad email message that will go into the undeliverable folder.

<cfmail to="me@myserver.com"
 from="me@myserver.com"
 server="mail.blahblahblahblahblahblah.com"
 subject="test">
 Testing undeliverable functionality
</cfmail>

With a few of these bad messages in place, test out the undeliverables.cfm file. When you click a message, you should see the spool file shown in the text area. You can now modify this or delete it.

Conclusion

ColdFusion has many great email features, especially since CF MX 6.1 came out, but still has no functionality for handling undelivered messages. This article has shown one possible approach in dealing with this problem.