ColdFusion in Context: Warn through E-mail

Suppose you have responsibilities for multiple sites, and you want to be notified if they go off-line. The site itself can't send you an E-mail if it's down, but a central site that checks the others from time to time could do that.

Suppose instead that you simply want to be notified when the content of a site changes. Read further to see how you could use this technique for this purpose.

This simple example assumes that you have sufficient control of your central site to run a scheduler to invoke a page (or you wouldn't have this opportunity). So, it deals directly with how to perform the check and how to send the E-mail. Along the way, you'll work with cfhttp and cfmail.

Check with cfhttp

Put all this code in check.cfm. If you only want to know if a site can be browsed - if you don't care about logging in, etc. - all you have to do is use the cfhttp tag to get a page and confirm something about its content. This example uses a real site; so, be gentle. Because your ISP may not let you point the tag at yourself, point it elsewhere, even when testing. (After all, if you're down, running a page on your own box to check yourself isn't a useful strategy.)

Set a variable (OK) as if you've succeeded. Open a cftry pair so the page won't just die if cfhttp fails. Invoke cfhttp in the get mode against the desired page (not just the domain name). Even though you won't be following links this time, to keep good habits, use the resolveurl attribute to make all links useful.

If the cfhttp attempt fails, the code in a cfcatch tag pair will be executed. Set OK to zero there to denote failure. Close the cftry tag.

<!--- See if a remote site is OK --->
<cfset OK=1>
<cftry>
<cfhttp url="http://www.exploacad.org/index.htm" method="get" resolveurl="true">
</cfhttp>
<cfcatch>
<cfset OK=0>
</cfcatch>
</cftry>

Now check the page content if the page was found. If OK, find specific text in cfhttp.filecontent. If you're not sure of the case of the text, use findNoCase instead of the find function used here. If the text is not found, set OK to zero. (You could shortcut this by setting OK to the value of the find command.)

<cfif OK>
  <cfif not find("Exploratorium Academy",
    cfhttp.filecontent)>
    <cfset OK=0>
  </cfif>
</cfif>

Report Failure via E-mail

If it's OK, use cfabort to stop. In a real application, you'd note success in a log at this point. (We'll just tell the screen.) Otherwise, set and try to mail a message.

To have the message contain the current date and time, store the current date and time from the now function to a variable. If you work directly from the now function instead of taking this intermediate step, you may wind up displaying the day from today and the time from tomorrow as you cross midnight. (You know what I mean.) Use dateFormat and timeFormat functions to turn the datetime variable you've created into a date string and a time string.

Mail can fail. If you were logging success and failure for a real application, you'd want to know if the mail process had itself been interrupted at the outset. Mail failure may still occur later, but at least you'll know that the task has begun if you use a cftry-cfcatch combination to check it. Set MailOK to 1. Open the cftry tag.

The cfmail tag is easy to use if the E-mail server's configured right. For minimal E-mail like this, you only need to specify attributes that say where it's going, its subject, and in whose name (well, account) it was sent. Note that if the from address isn't recognized by the mail server, it may ignore your request. So, don't use cartoon characters when testing this. If this doesn't seem to work when you test it, be sure you've specified YOUR E-mail address as the recipient.

Between the beginning and ending cfmail tags, place your text. You've already defined your message; so, just put it in pound signs and keep going. Note that if you indent the contents of the cfmail tag to format your code, the content of the E-mail will also be indentented when the recipient sees it (assuming you use plain text as we've done here). So, you may need to make an exception to your local coding standards to accommodate reality.

If mail fails right away, set MailOK to zero within a cfcatch tag. Close the cftry tag.

<!--- Report results --->
<cfif OK>
  Remote site is OK.
  <cfabort>
</cfif>

<cfset DateTime=now()>
<cfset Msg="Could not reach Exploratorium Academy on ">
<cfset Msg=Msg&"#dateFormat(DateTime)# at #timeFormat(DateTime)#.">
<cfset MailOk=1>
<cftry>
<cfmail to="martin.ladner@charter.net"
from="admin@fedinvoicing.com"
subject="Remote Site Down">
#Msg#
</cfmail>
<cfcatch>
<cfset MailOK=0>
</cfcatch>
</cftry>

At this point, you would note the success or failure of the E-mail notification in your log. For this demo, we'll simply display it.

<cfif MailOK>
  Could not reach remote site; E-mail sent.
<cfelse>
  Could not reach remote site; E-mail NOT sent.
</cfif>

Try It; Extend It

Browse check.cfm. To see it send mail, point it to a ficticious site or check for text the page does not contain. You'll find pages of notes from other sources on how to send mail. If this example works on your server, then you'll know things are configured right and you can experiment with the finer points of the cfmail tag.

If you want to be notified when site content changes, then instead of looking for specific words, simply compare the content with what the tag saw on the previous pass and send the alert when they don't match in material respects.

To send alerts via E-mail in the real world, you'll want one more thing we haven't discussed yet: a semaphore, otherwise known as a flag.

If you've set your box to perform this check every six minutes and then neglect to read mail all weekend, imagine the possible result, especially if you're running copies of this against several sites. To avoid spamming yourself, you should set a flag in a database or file when you send the first message, only send a subsequent message if the flag is NOT set, and clear the flag when a check is successful. =Marty=