One of the features you may be asked to add to a web site is a mailing list. A mailing list lets people subscribe to get the latest news and updates from whatever your site may be offering. In this series I'll talk about how to add this feature to your web site. Before going on, let me go over the features of this application and what it will provide.
- Users will be able to fill out a form to subscribe to the mailing list.
- Administrators will be able to see a list of people subscribed. They will also be able to remove or add a user manually.
- Administrators will be able to send an email to everyone in the list.
- Users will be able to remove themselves from the list.
There it is, short and sweet. Of course, I remember saying my Model-Glue series would be simple as well, and we all know how that turned out.
In this entry, I'll cover step one, allowing users to subscribe to the list. A client may ask for many different things from their users, but at minimum, all I need to ask for is an email address. So let's start off with the simplest of forms and validation:
<cfparam name="form.emailaddress" default=""> <cfset showForm = true>
<cfif structKeyExists(form, "subscribe")> <cfif isValid("email", form.emailAddress)> <cfset application.maillist.subscribe(form.emailaddress)> <cfset showForm = false> <cfelse> <cfset error = "Your email address isn't valid."> </cfif> </cfif>
<h2>Subscribe to Foo</h2>
<cfif structKeyExists(variables, "error")> <cfoutput> <p> <b>#error#</b> </p> </cfoutput> </cfif>
<p> <form action="subscribe.cfm" method="post"> <table> <tr> <td>Your Email Address</td> <cfoutput><td><input type="text" name="emailaddress" value="#form.emailaddress#"></td></cfoutput> </tr> <tr> <td> </td> <td><input type="submit" name="subscribe" value="Subscribe"></td> </tr> </table> </form> </p>
<p> Thank you for subscribing! </p>
So there really isn't anything too special about this form, but let talk about some particulars. First off - the form just checks for an email address. As I said, a client may want a lot more information about the user, however none of that really applies to what the goal is - subscribing to a list. Since the form is somewhat simple, I only needed to validate the email field. Note that I used the isValid function, so this code will only work in ColdFusionMX 7. (Just this one line though.)
After ensuring the email address is actually valid, I pass off to the main CFC I'm going to be using throughout this series:
In case your curious, I'm loading the CFC via onApplicationStart. (Included in the Application.cfc file that is in the zip.) Now let me show you the CFC. Right now it is pretty short, but I'll be adding to it as the series goes on.
<cfcomponent displayName="MailList" output="false">
<cffunction name="init" returnType="maillist" output="false" access="public"> <cfargument name="dsn" type="string" required="true">
<cfset variables.dsn = arguments.dsn>
<cfreturn this> </cffunction>
<cffunction name="subscribe" returnType="boolean" output="false" access="public" hint="Adds a user to the mailinst list, if and only if the person wasn't already on the list."> <cfargument name="email" type="string" required="true"> <cfset var checkIt = "">
<cfif not isValid("email", arguments.email)> <cfthrow message="#arguments.email# is not a valid email address."> </cfif>
<!--- only add if the user doesn't already exist. ---> <cflock name="maillist" type="exclusive" timeout="30"> <cfquery name="checkIt" datasource="#variables.dsn#"> select email from subscribers where email = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#"> </cfquery>
<cfif checkIt.recordCount is 0>
<cfquery datasource="#variables.dsn#"> insert into subscribers(email,token) values(<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#">,<cfqueryparam cfsqltype="cf_sql_varchar" value="#createUUID()#">) </cfquery>
Outside of the init method, right now the only code here is the subscribe method. The subscribe method does a few basic things. First it checks to ensure the email address sent to it was valid. Why am I doing this again? I mean, I know my form checked, so why bother? Well I think it is important to remember that the CFC is separated from the client enough that the CFC may not what to actually trust the client. The CFC should validate information as much, if not more than, the client is. So once again I use the isValid function for a quick way to validate email addresses. If you plan on using my code on a MX6 machine, this is the one line you will need to change. The rest of the method is rather simple. I see if the email address already exists, and if not, I add one to the subscribers table. Note two things. First off - I use a lock around the code block. This lock ensures that if I have multiple requests coming in with the same email address, I don't accidentally insert the same email address more than once. I could use the database to handle that as well, but I wanted to handle it on the CF side for this demonstration. Secondly, notice I insert a UUID into a column named token. I'll be explaining that in step four.
So - if you want to test this, download the zip attached to this article. Create a database with the included SQL file and make a DSN named maillist. Copy the files to a folder and run subscribe.cfm. In the next session I'll add a subscriber administrator tool. This will let the admin see who is subscribed and quickly add or remove individuals.