Mailer.cfc 1.8 Released

It has been more than a year since I released Mailer 1.5 and new enhancements have been slow in coming. That is because it has, for the most part, done exactly what I needed.

Still, from time to time, I get ideas or suggestions for small enhancements to the component.

New from 1.5:

  • ReplyTo argument (for Reply-To header)
    • Available in send method
    • Also available in init method to set a default
  • Sender argument (for Sender header) - thanks to Sami Hoda for this suggestion!

That's it!

As you can tell, Mailer is pretty stable. It does what it does and doesn't need to do much more.

Mailer.cfc is open source and free for any use.

NoticeMgr 1.0 Beta

On most web sites, I typically allow my clients to edit the content on the pages of the site. I also generally have email messages sent out in response to certain events.

For example, I might have an email that tells a user that we have received their application. This is generally sent out by the component that handles processing the application (in my case, usually using Mailer.cfc).

Much like in the case of content on their site, the client will often want to change the content of the email. It isn't as easy to have them do this, however, as the component needs to be aware of the email message and having the component reference a primary key of data in a database seems like bad form (violating encapsulation - after all the key may be different on the dev database than the live one).

Still, changing the content of the email myself isn't challenging work and isn't the best use of my clients money. As such, I needed a better solution.

[More]

Mailer.cfc 1.5 is Gold

It is a big week for me in terms of open source releases. I got DataMgr 2.0 released on Monday and now Mailer.cfc 1.5 is ready today.

Mailer.cfc is, in part, an abstraction for cfmail. While cfmail is already a great encapsulation of email functionality, Mailer.cfc provides several advantages - especially if you are using CFCs.

The first advantage is that it you can pass Mailer.cfc into a component instead of several email-related settings. This is especially useful if you may or may not use a username/password to send email as it keeps you from having to code that conditional into your component.

More significantly, however, is that like DataMgr, Mailer.cfc comes with a "Sim" version that can be used for development and testing. Switching between the two requires no change to your code except on the instantiation of your component. This allows you to test your code without actually sending email.

Mailer.cfc can also log all of the email that it sends in a database table (this feature requires DataMgr, but Mailer.cfc can be used without anything else if you don't use logging).

The use of Notices in Mailer.cfc is also helpful, but beyond the scope of this entry.

Mailer.cfc is open source and free for any use. 

Mailer.cfc 1.5 Release Candidate

Mailer.cfc 1.5, the email abstraction component that makes sending email from components (and switching to test email for development) easy is in release candidate stage.

This is a much simpler component set than DataMgr, so I don't expect to have the kind of trouble getting it out of release candidate that I have had with DataMgr.

Here are the only changes from beta:

  • Made isEmail() method public
  • Switch order of cfmailpart tags (Here's why)
Mailer.cfc is free and open source (and includes documentation). The Mailer.cfc page also has links to other blog entries about using Mailer.cfc.

Mailer.cfc Notices

I have blogged about Mailer.cfc before, but it can do more than send a static email. You can also tell it about a notice that you want to send and later send that notice with personalized information.

To add a notice, use the addNotice() method. You must give the notice a unique name by which Mailer.cfc will reference the notice. The other arguments are the same as the arguments for the send() method. You can also include markers for data by wrapping a word in brackets. For example, you can have "Dear [FirstName]," in the contents and have "[FirstName]" replaced with a first name when you send the notice.

The addNotice() method also has an optional datakeys argument as a list of required variables for which markers are in the notice. 

To send a notice, use the sendNotice() method. This method has just two arguments:

  • name: the name of the notice you want to send
  • data: a structure of data to replace the markers used in addNotice()

So, the data structure could have a "FirstName" key to replace the "[FirstName]" marker. The keys in the structure can also replace any of the arguments of the send() method. For example, it could have a "To" key to replace the "To" argument of the send() method.

That's it!

Mailer.cfc is free and open-source. Version 1.5 is currently in beta. 

Mailer 1.5 and Testing

For some time now, I have found testing email related functionality to be a bit of a pain. This has become especially true since I started using well-encapsulated CFCs.

For example, I will often need send email to users of the site. Sometimes, I want to test this using actual data, but I don't want to risk the messages to actually send during testing.

Historically, I have changed the code during testing to get around this. This approach has proved to be labor intensive and is a bit risky as well. 

I realized recently that since all of my code uses Mailer.cfc to send email now, I should be able to take advantage of this centralization of functionality.

Taking a page out of my DataMgr playbook, I now have a Mailer_Sim.cfc as part of Mailer 1.5 (now in beta). This allows me to have code in my CFC that sends mail using Mailer.cfc. Depending on the instantiation of Mailer.cfc, it may send the email or it may merely log the email to the database instead.

Here is an example in which request.isProduction is used to indicate if this is a production site. This example assumes that I have DataMgr stored in Application.DataMgr (DataMgr is only needed when using the logging feature).

<cfif request.isProduction>
  <cfset Application.Mailer = CreateObject("com.sebtools.Mailer").init("mail.example.com","admin@example.com")>
<cfelse>
  <cfset Application.Mailer = CreateObject("com.sebtools.Mailer_Sim").init(MailServer="mail.example.com",From="admin@example.com",DataMgr=Application.DataMgr)>
</cfif>

I then pass Mailer.cfc into my components with no concern for whether the site is production or development. On the production site, the email messages sent out via Mailer.cfc will go out normally. In development, however, they will be written to the "mailerLogs" table in your database.

I could also log email that I do send by using the startLogging() method of the main Mailer component, which takes DataMgr as an argument.

Here is some example code to send email:

<cfinvoke component="#Application.Mailer#" method="send">
    <cfinvokeargument name="To" value="sample@example.com">
    <cfinvokeargument name="Subject" value="My Subject">
    <cfinvokeargument name="Contents" value="Message Text">
</cfinvoke>

This would send an email to sample@example.com unless it was using Mailer_Sim, in which case it would write that email to the database instead.

Mailer.cfc is open source and free for any use. The component docs for 1.5 are also available. 

Mailer.cfc 1.0 and Email Logging

Instead of passing in multiple email settings, I use Mailer.cfc to send email from components.

I recently needed to keep track of every email sent by a client site (but not for the whole server). So, I added logging to Mailer.cfc.

Realizing that I had yet to make it a 1.0 release (an dI have been using Mailer since December 2004), this seemed like a good time.

I have already written an introduction to Mailer.cfc and I have done some presentations on Mailer.cfc, so I will cover the logging briefly here.

Like DataMgr, Mailer.cfc is part of the com.sebtools package (and like DataMgr it is no longer required that it be located there). It does not, however, require DataMgr or any other component. Unless, that is, you want to do logging of email sent by Mailer.cfc.

I chose to introduce the dependency on DataMgr for logging for the same basic reasons that I wrote DataMgr in the first place. It made adding the feature trivial to write (about 55 lines), but very flexible (records only the data available). It ensures that Mailer.cfc can work with any database supported by DataMgr (currently Access, MS SQL, MySQL, PostGreSQL - but adding more is easy and I plan to add support for more in the near future).

In order to have Mailer.cfc log the email that it sends, you need only call the startLogging() method. This method takes only one argument which is the DataMgr component that you want to use.

In order to stop Mailer.cfc from logging the email that it sends, call the stopLogging() method.

Feel free to download Mailer.cfc . It is free and open source.

Mailer.cfc Presentations

The free Mailer.cfc component makes it easy to send email from components with minimal dependencies. Watch presentations on this as well as installation and instantiation and sending personalized notices.

If you are using Mailer.cfc to send email from your component, then you won't have to pass in a bunch of email-related variables and you won't have to change your component if you change your mailserver or if username and password become required to send email.

Watch Presentations

Although not yet officially a 1.0 release, I have been using Mailer.cfc in production since December of 2004 (unchanged since March of 2006), so it is pretty stable. Come to think of it, I am not sure why I haven't labeled it as 1.0 yet. I should get around to that sometime...

Anyway, feel free to check out the presentations and try out the component. Free for use in commercial or non-commercial projects.

Free Goodies: Send Email From Components

I often need to send an email when a certain action is taken. The action is usually taken in a CFC. I have often seen email sent out when the CFC method is called, but this means you must remember to send the email each time you call the method.

Better, I think, to send the email from the method itself. Unfortunately, this means that you must pass into the component (preferably on initialization) all of the information you need to send an email message (generally, the mail server and the from address but potentially a username and password as well).

This can add several aguments to the initialization method of the component that aren't central to the task that the component performs.

To avoid this, I created a Mailer component that I initialize with this information. I then pass the Mailer component to my action component and use it to send email.

For example:

I will instantiate Mailer with my mail server and default from address (I can choose a different from address for any given message):

<cfset Mailer = CreateObject("component","com.sebtools.Mailer").init("mail.example.com","robot@example.com")>

If I needed a username and password, I would specify that during initialization as well. Note that Mailer must be installed in the com/sebtools directory either under the web root or in the custom tags directory.

I am assuming that I already have a Data Manager component loaded in the variable "DataMgr" (just to help keep the example short).

Now, I initialize my UserMgr component:

<cfset UserMgr = CreateObject("component,"UserMgr").init(DataMgr,Mailer)>

Now, in order to update a user and send an email to that user to let them know their record has been updated, I want to be able to call that method like this (on a form action page):

<cfset UserMgr.saveUser(argumentCollection=Form)>

Here is the UserMgr component:

UserMgr

Breaking it down by method:

<cffunction name="init" access="public" returntype="any" output="no">
    <cfargument name="DataMgr" type="any" required="yes">
    <cfargument name="Mailer" type="any" required="yes">
   
    <cfset variables.DataMgr = arguments.DataMgr>
    <cfset variables.Mailer = arguments.Mailer>
   
    <cfreturn this>
</cffunction>


This is the init() method inializes and returns the component. It takes the DataMgr and Mailer as arguments and makes them available (via variables scope) to the rest of the component.

<cffunction name="getUser" access="public" returntype="query" output="no">
    <cfargument name="UserID" type="numeric" required="yes">
   
    <cfreturn variables.DataMgr.getRecord("users",arguments)>
</cffunction>


The getUser() method returns a recordset of the given user. It is just included for completeness.

<cffunction name="saveUser" access="public" returntype="numeric" output="no">
    <cfargument name="UserID" type="string" required="no">
    <cfargument name="FirstName" type="string" required="no">
    <cfargument name="LastName" type="string" required="no">
    <cfargument name="Email" type="string" required="no">
   
    <cfset var result = variables.DataMgr.saveRecord("users",arguments)>
    <cfset var qUser = getUser(result)>
   
    <cfif Len(qUser.Email)>
        <cfset variables.Mailer.send(qUser.Email,"Record Updated","Just to let you know, your record was updated.")>
    </cfif>
   
    <cfreturn result>
</cffunction>


The saveUser() method saves the record and sends an email to the user. Any action could have been taken before or after calling the Mailer.send() method - this was just one example. Note that DataMgr was here only to keep the examples brief - it is not needed to use Mailer.

That's it!

Mailer can also handle dynamic data and multi-part email messages, but those are topics for another day (though a glance at the documentation should provide the answers).

Mailer is a free download and has documentation available.

BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.