BackUp LevelNext

Crazy Cab Example Application

The Crazy Cab example application is a full featured POP3 email client you can use to manage email messages. In addition to basic email handling features, it allows you to attach external files to email messages. In the pages that follow, we step through the ColdFusion code that comprises the Crazy Cab application.

In addition to Crazy Cab, be sure to check out the other example applications (still being developed at the time of this writing) installed with ColdFusion.

Note

The example code that follows consists of selections from the relevant application pages, excluding as much HTML code, such as FONT tags as necessary to make the code as readable as possible. If you want to see the actual pages, open any of the Crazy Cab pages, installed in cfdocs/exampleapp/email/*.cfm, in ColdFusion Studio for closer inspection.

To launch Crazy Cab:

  1. Open the Example Application home page:
    http://servername/cfdocs/examplehome.htm
    

    Where servername is the name of the server where ColdFusion Server is installed.

  2. Click the Crazy Cab link. The login page for Crazy Cab appears, which prompts you for your email address, mail server name, and so on. Enter the required information and click OK. If you have any email waiting for you, it appears in the message listing.

Crazy Cab is a relatively simple ColdFusion application that consists of only 15 ColdFusion pages and a handful of graphics files. To start with, we'll take a look at the login page, login.cfm, which checks to see if a user has already entered Crazy Cab email account information.

The login page: What happens first

To start with in login.cfm, the ColdFusion CFINCLUDE tag is used to reference the _header.cfm application page, which encapsulates a set of graphics files used for this and other pages in Crazy Cab.

<CFINCLUDE TEMPLATE="_header.cfm">

Next, a CFLOOP block is employed to iterate processing through a list of items, in this case, a set of form variables used to store information about you and your email account. If you entered this information once before in Crazy Cab and chose the Save login information option, this information is stored as a cookie on your system. If ColdFusion finds this cookie when you return, it populates the form with the information you provided. You'll see how ColdFusion manages cookies in Crazy Cab later on.

<CFLOOP LIST="Email,Username,POPserver,SMTPserver" 
INDEX="CurrItem">
    <CFIF ISDEFINED("Cookie.#CurrItem#")>
        <CFSET "#CurrItem#" = EVALUATE("Cookie." & CURRITEM)>
    <CFELSE>
        <CFSET "#CurrItem#" = "">
    </CFIF>
</CFLOOP>

The CFLOOP block loops over the specified formfield variables. For each one, if a value is found in a cookie variable, ColdFusion returns the value of that item. If a value is not found, ColdFusion creates an empty string for the CurrItem variable. If the cookie exists, the individual values are used to populate the login form.

<CFIF ISDEFINED("Cookie.SaveInfo")>
    <CFSET CHECKED = "CHECKED">
<CFELSE>
    <CFSET CHECKED = "">
</CFIF>

The IF/ELSE block above does the following: If the cookie variable Cookie.SaveInfo exists, it creates a variable called CHECKED with the value "CHECKED," otherwise, it creates the variable but gives it an empty string value. The SaveInfo cookie variable is used in the form to indicate whether the form information should be saved or not.

The login form: login.cfm

This part of login.cfm is the HTML form used to collect information about your email account. Note how the form field variables are referenced in the CFLOOP and CFIF statements above. Note also that the form data is submitted to auth.cfm, which we'll examine momentarily.

<FORM ACTION="auth.cfm" METHOD="POST">

<CFOUTPUT>

<P><INPUT TYPE="TEXT" NAME="Email" VALUE="#Email#"><BR>
Email Address</P>

<P><INPUT TYPE="TEXT" NAME="Username" VALUE="#Username#"><BR>
POP Account Username</P>

<P><INPUT TYPE="PASSWORD" NAME="Password"><BR>
POP Password</P>

<P><INPUT TYPE="TEXT" NAME="POPserver" VALUE="#POPserver#"><BR>
POP Server</P>

<P><INPUT TYPE="TEXT" NAME="SMTPserver" VALUE="#SMTPserver#"><BR>
SMTP Server</P>

<P><INPUT TYPE="CHECKBOX" NAME="SaveInfo" #CHECKED#>
Save login information</P>

</CFOUTPUT>

<P><INPUT TYPE="SUBMIT" VALUE="Log In"></P>

</FORM>
</TD>
</TR>
</TABLE>

To view complete page code listings, see the files contained in the cfdocs/exampleapp/email directory on your ColdFusion application server.

Creating cookies: auth.cfm

When the form in the login.cfm page is submitted, form variables are created and passed to the auth.cfm page. Let's take a look at what happens next.

Here's the first part of auth.cfm. Notice the reference to the _header.cfm page in the CFINCLUDE tag.

CFINCLUDE TEMPLATE="_header.cfm">

Recall that it is used to embed a series of graphics at the top of every Crazy Cab page.

Next, a series of CFSET tags, which are used to create ColdFusion variables, change the form variables passed from the form in login.cfm into session variables. Session variables are useful here because they persist for the entire user session; they don't need to be recreated for other pages in the Crazy Cab application.

<CFSET Session.Email = Form.Email>
<CFSET Session.Username = Form.Username>
<CFSET Session.Password = Form.Password>
<CFSET Session.POPserver = Form.POPserver>
<CFSET Session.SMTPserver = Form.SMTPserver>

Next, CFIF, CFCOOKIE, and CFLOOP tags are used to find out if the SaveInfo variable was created. SaveInfo is created only if you check the Save login information box on the login.cfm page. The CFCOOKIE tag creates the cookie based on the value of the Expires variable and populates it with information submitted in the login.cfm form.

<CFIF IsDefined("Form.SaveInfo")>
    <CFSET Expires = "NEVER">
<CFELSE>
    <CFSET Expires = "NOW">
</CFIF>

<CFCOOKIE NAME="SaveInfo" VALUE="TRUE" EXPIRES="#Expires#">

<CFLOOP LIST="Email,Username,POPserver,SMTPserver" 
    INDEX="CurrItem">

    <CFCOOKIE NAME="#CurrItem#" 
        VALUE="#evaluate('Form.' & CurrItem)#" 
        EXPIRES="#Expires#">

</CFLOOP>

Retrieving mail

While the upper part of auth.cfm is dealing with cookies, a small JavaScript is used to load refresh.cfm, which does the job of retrieving email messages. Text in the page lets the user know that mail is being retrieved from the POP server.

<FONT FACE="Helvetica" SIZE="-1"><B>Attempting to retrieve 
messages.<BR>
This may take a few moments.</B></FONT>

<SCRIPT LANGUAGE="JavaScript">
location.replace('refresh.cfm')
</SCRIPT>

Populating the list of messages: refresh.cfm

The refresh.cfm page referenced in the JavaScript in auth.cfm is responsible for actually retrieving mail messages and checking for errors.

First, a CFTRY block is opened, inside of which CFPOP attempts to retrieve email messages.

<CFTRY>
<CFPOP ACTION="GETHEADERONLY"
    NAME="Messages"
    SERVER="#Session.POPserver#"
    TIMEOUT="120"
    USERNAME="#Session.Username#"
    PASSWORD="#Session.Password#">

If errors are encountered, CFCATCH is used to inform the user of any errors, such as invalid account information, or any other error generated by the POP mail server.

<CFCATCH TYPE="ANY">
    <CFINCLUDE TEMPLATE="_header.cfm">

    <P>Oops...!</P>

    <CFIF CFCatch.Detail CONTAINS "password">
        The username and/or password you supplied was invalid!
    <CFELSEIF CFCatch.Detail CONTAINS "timeout">
        Crazy Cab is tired of waiting for
        <CFOUTPUT>#Session.POPserver#</CFOUTPUT> to respond.
    <CFELSE>
        Crazy Cab has encountered the following error:</P>

<P>
        <TABLE BORDER="1" 
            CELLPADDING="5" 
            CELLSPACING="0" 
            BGCOLOR="#FFFFCC">
        <TR>
        <TD><TT><CFOUTPUT>
            <B>#CFCatch.Message#</B>
            <BR><BR>#CFCatch.Detail#</CFOUTPUT>
        </TT></TD>
        </TR>
        </TABLE>
</P>
    </CFIF>

    <P>Please <A HREF="login.cfm">log in</A> again.

    <CFINCLUDE TEMPLATE="_footer.cfm">

<CFABORT>

</CFCATCH>

</CFTRY>

At the bottom of the refresh.cfm page a session variable is created to store the messages retrieved by CFPOP. The session.messages variable is only created following a successful message retrieval. Last, a CFLOCATION tag is used to open messagelist.cfm, which presents email messages in a list.

<CFSET Session.Messages = Messages>
<CFLOCATION URL="messagelist.cfm" ADDTOKEN="NO">

Listing email messages with messagelist.cfm

In messagelist.cfm, a CFIF block tests for the existence of the session.messages variable, and if not found, attempts to retrieve messages again by opening the refresh.cfm file.

Session variables allow ColdFusion to successfully resolve the session.username variable in the message letting the user know that messages are waiting to be read.

<CFINCLUDE TEMPLATE="_header.cfm">

<!--- Make sure messages are loaded --->
<CFIF NOT ISDEFINED("Session.Messages")>
    <CFLOCATION URL="refresh.cfm" ADDTOKEN="NO">
</CFIF>

<TABLE BORDER="0" 
    CELLSPACING="2" 
    CELLPADDING="25" 
    ALIGN="CENTER" 
    BGCOLOR="#660000">
<TR>
    <TD COLSPAN="3" BGCOLOR="FFffcc">
    <!--- Display login information --->
    <CFOUTPUT>
        <B>Hello #Session.Username#,</B><BR>
        Welcome to your Crazy Cab inbox. You have
        #Session.Messages.RecordCount#</B> new message(s) on 
        <B>#Session.POPserver#</B> waiting to be read.
    </CFOUTPUT>
    </P>
    </TD>
</TR>
</TABLE>

Next, the email messages are listed. Since the page uses the HTML TABLE tag to position elements, it might be hard to see what's happening.

<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="0">
<TR>
    <TD COLSPAN="5">

<!-- Column headers -->
    <TABLE BORDER="0" 
        CELLSPACING="2" 
        CELLPADDING="3" 
        ALIGN="CENTER" 
        BGCOLOR="#660000">

    <TR>
        <TD BGCOLOR="660000"><B>From</B></TD>
        <TD BGCOLOR="660000"><B>Subject</B></TD>
        <TD BGCOLOR="660000"><B>Date</B></TD>
    </TR>

<!-- Output messages -->
    <CFOUTPUT QUERY="Session.Messages">

In this output block, the CFOUTPUT tag uses the QUERY attribute, which references the session.messages variable. The data returned by CFPOP earlier was stored in the session.messages variable, and this data takes the form of a query object, which means it can be referenced by CFOUTPUT just like data returned by the CFQUERY tag. Individual elements of the messages, such as the To, From, CC, and Subject elements are treated just like columns returned in a query to a database. ColdFusion outputs your email messages using the table rows and session variable references to position each element.

Notice in the following block how the email message's From element is wrapped in an HTML A tag. This creates a link to the viewmsg.cfm ColdFusion page, which is used to show the message. The ? character is used to pass the unique message number in the URL indicating which message to open. Notice also, how the ColdFusion HTMLEditFormat function is used to format the email address of the sender. Without it, the browser would attempt to interpret the raw HTML.

<TR>
    <TD BGCOLOR="FFffcc">
    <A HREF="viewmsg.cfm?Msg=#MessageNumber#">
    #HTMLEditFormat(From)#
    </A></TD>

This same technique is used to wrap the other message details, allowing the user to click on any part of the returned message information in order to view it. In this chunk, the ColdFusion Trim function is used to trim white space from the beginning and end of the message subject string. Also, if no subject exists, the string "(no subject)" replaces the Subject element of the message. Here is the message Subject chunk:

<TD BGCOLOR="FFffcc">
    <A HREF="viewmsg.cfm?Msg=#MessageNumber#">
    <CFIF TRIM(SUBJECT) IS "">
    (no subject)
    <CFELSE>#Subject#</CFIF>
    </A>
    </TD>

At the bottom of the page, graphic links allow you to refresh the message list by opening the refresh.cfm page. There is also a link you can use to compose a message using compose.cfm. See Composing a message: compose.cfm below, for details.

<TD BGCOLOR=CC9900 VALIGN="middle">
    <A HREF="compose.cfm">
    <IMG SRC="images/compose.gif" 
        WIDTH=29 
        HEIGHT=25 
        BORDER=0 
        ALT="" 
        ALIGN="left">
    </A>
    <A HREF="compose.cfm">Compose</A></TD>

<TD BGCOLOR=660000>
    <A HREF="refresh.cfm">
    <IMG SRC="images/refresh.gif" 
        WIDTH=25 
        HEIGHT=24 
        BORDER=0 
        ALT="" 
        ALIGN="left"></A>
    <A HREF="refresh.cfm">Refresh</A></TD>

</TR>
</TABLE>

Composing a message: compose.cfm

The Crazy Cab compose.cfm page is a simple HTML form with text input elements you use to enter message text, email addresses of recipients, and so on. At the bottom of the form, the HTML input type FILE allows you to select an attachment to send with the message.

<CFINCLUDE TEMPLATE="_header.cfm">

<FORM ACTION="send.cfm" 
    METHOD="POST" 
    ENCTYPE="multipart/form-data">

<CFOUTPUT>

<TABLE BORDER="0" 
    CELLPADDING="3" 
    CELLSPACING="0">
<TR>
    <TD ALIGN="RIGHT"><B>To</B></TD>
    <TD><INPUT TYPE="TEXT" NAME="To" SIZE="30"></TD>
</TR>

<TR>
    <TD ALIGN="RIGHT"><B>cc</B></TD>
    <TD><INPUT TYPE="TEXT" NAME="cc" SIZE="30"></TD>
</TR>

<TR>
    <TD ALIGN="RIGHT"><B>Subject</B></TD>
    <TD><INPUT TYPE="TEXT" NAME="Subject" SIZE="30"></TD>
</TR>
</TABLE>

<P><TEXTAREA NAME="MessageBody" 
    COLS="50" 
    ROWS="20" 
    WRAP="VIRTUAL">
</TEXTAREA></P>

</CFOUTPUT>

<P><B>Attachment</B><BR>
<INPUT TYPE="FILE" NAME="AttachFile"></P>

<P><INPUT TYPE="SUBMIT" VALUE="Send Message"></P>

</FORM>

<CFINCLUDE TEMPLATE="_footer.cfm">

Viewing a message: viewmsg.cfm

Crazy Cab uses the viewmsg.cfm file for a number of purposes. To start, viewmsg.cfm creates a temporary directory for inbound file attachments:

CFSET TempDir = GetTempDirectory() & "CrazyCab\">
<CFTRY>
    <CFDIRECTORY ACTION="CREATE" DIRECTORY="#TempDir#">
    <CFCATCH TYPE="ANY">
    </CFCATCH>
</CFTRY>

<!--- Create inbound temp directory if it doesn't already exist --->
<CFSET AttachDir = TempDir & "inbound\">
<CFTRY>
    <CFDIRECTORY ACTION="CREATE" DIRECTORY="#AttachDir#">
    <CFCATCH TYPE="ANY">
    </CFCATCH>
</CFTRY>

Note the use of CFTRY and CFCATCH to trap errors that might occur during the attempt to create these directories. In the next block, the CFPOP tag is used to retrieve an individual message. It uses the value of the URL.Msg variable to select the correct message to display and a number of session variables to communicate with the POP server. Remember that when you click on an individual message in the message list page, a URL variable is passed to viewmsg.cfm identifying which message is desired.

<CFPOP ACTION="GETALL"
    NAME="Message"
    MESSAGENUMBER="#URL.Msg#"
    SERVER="#Session.POPserver#"
    USERNAME="#Session.Username#"
    PASSWORD="#Session.Password#"
    ATTACHMENTPATH="#AttachDir#">

Then, a custom tag is used, CF_WRAP to control line width and how lines are wrapped in the message output. The CFSET tag is used to define a variable to hold the contents of the message body. The variable is used as an attribute passed to the custom tag, which (as you'll see) returns the message body ready for output.

<CFSET Body = Message.Body>
<CF_Wrap VARIABLE="Body" WIDTH=50>

The message details, such as the From, To, CC, and Subject elements are then displayed, preceded by the option to show the full message header.

<CFIF IsDefined("URL.FullHeaders")>
    <CFOUTPUT>#HTMLCodeFormat(Message.Header)#</CFOUTPUT>
<CFELSE>

<!---Show me the message! --->
<CFOUTPUT QUERY="Message">
    <P><B>Date:</B> #Date#<BR>
    <B>From:</B> #HTMLEditFormat(From)#<BR>
    <B>To:</B> #HTMLEditFormat(To)#<BR>
    <B>cc:</B> #HTMLEditFormat(cc)#<BR>
    <B>Subject:</B> #HTMLEditFormat(Subject)#<BR>

<A HREF="viewmsg.cfm?Msg=#URL.Msg#&FullHeaders=On">
    Click here for full headers
</A></P>

</CFOUTPUT>
</CFIF>

Next, the message body is displayed, returned by the custom tag as a variable called Body. The HTMLCodeFormat function replaces HTML code with escaped characters, for example &gt; for the greater than sign (>) and encloses the message content in the <PRE> and </PRE> tags.

<CFOUTPUT>
<PRE>--------</PRE>
#HTMLCodeFormat(Body)#
</CFOUTPUT>

Crazy Cab summary

Although there are several other pages that perform additional email handling tasks, what you've seen here should give you a very clear notion of how ColdFusion interacts with a POP server.

The following list details what we've examined in the Crazy Cab example application:



BackUp LevelNext

allaire

AllaireDoc@allaire.com
Copyright © 1998, Allaire Corporation. All rights reserved.