SMTP Extension

CFSMTP opens up a whole new world of possibilities to the CFML developer. In much the same way OpenBD makes building rich web applications for web (HTTP) requests, this plugin opens up the world of email to the CFML community. Just as a page reacts to a request, the CFSMTP invokes a CFC for every email that comes into the server allowing to build rich email applications.

Once you register this listener, this plugin will listen for email delivery on the standard Port25. You have the opportunity to determine if you wish to accept email before the sender transmits the full email body, allowing you to quickly stop spam and unwanted emails. Once you've decided to accept the email, the plugin will ensure delivery and then call your CFC again detailing the email.

You can then process the email, looking at its headers, body, attachments and if you need to send out any email, then you use the standard CFML CFMAIL way of achieving that.

This extension is built-in to the core distribution of OpenBD, no extra download/installation required.

Overview of functions

CFSMTP is setup using a series of functions letting you startup, shutdown and query the status of your CFSMTP endpoint. You can run multiple servers, each on their different interface/port, referencing them using a symbolic name.

Function Name Description
SmtpStart Starts up a listening service for incoming emails, calling a CFC in response to all mails
SmtpStatus Returns back the stats for this SMTP end point; running, totalmails, totalconnections
SmtpStop Stops a running SMTP server. Returns true if it was stopped; false if it wasn't running
MailRead Used in conjunction with MailWrite(). This function reads the previously serialized email out to disk
MailWrite This function writes the email out to disk for later processing or archiving
MailDeliver This function takes the email object and sends it for delivery to a new server, giving you the opportunity to override from, to, cc, bcc and server

The key to the success of the CFSMTP plugin is in the CFC that is used to process the incoming email. It is this CFC, with the pre-defined methods, that will be called for each stage of the email processing. Remember, these CFC's run as headless requests, which means they are outside of the normal scope of a web request. Therefore operations such as session management, cookie's and CGI scopes are not applicable.

However, the 'request' scope is available and is exclusive per each single transaction. This lets you, for example, put content into it when you are processing one of the onMailFrom() and pick it up again on the onAcceptMail()

Accepting Email

Email delivery is done in 3 stages. First the sender sends who the email is from, then it sends who the email is for, and finally it delivers the email body. Here is a full example using the same CFC for both the cfcmail and cfcfilter options.

<cfcomponent>

  <cffunction name="onmailfrom" access="public" returntype="boolean">
    <cfargument name="email" required="yes">
    <cfargument name="ip" required="yes">
    <cfreturn true>
  </cffunction>


  <cffunction name="onmailto" access="public" returntype="boolean">
    <cfargument name="email" required="yes">
    <cfargument name="ip" required="yes">
    <cfreturn true>
  </cffunction>


  <cffunction name="onMailAccept" access="public" returntype="any" output="no">
    <cfargument name="mail" required="yes">

  </cffunction>

</cfcomponent>

onmailfrom / onmailto

If you specify this CFC cfcfilter option then you are given the opportunity to hook into the very start of the email exchange with the remote server. This gives you an opportunity to deny any further exchange with the remote server by returning false. This is a huge benefit when reducing spam and unwanted emails.

onMailAccept

This is the main processing for emails that come in to the server. From here you can work with all aspects of the incoming email, including processing the body and downloading any attachments.

The mail object that is passed in has the following functions to process the mail.

Function Name Description
getAllBodyParts()returns Array of ALL Parts including the inner ones
getBodyParts()returns Array of Parts; as per email
getCcList()returns Array of Structs (name/email) of all the people addressed in the Cc field
getFromList()returns Array of Structs (name/email) of all the people addressed in the From field
getHeaders()returns Array of all the email headers
getHeader( string )returns the value of the given header
getIP()returns the IP address of the delivery agent
getMessageId() returns the email message id
getMailFrom() returns email address that was in the MAIL FROM
getReplyToList() returns Array of Structs (name/email) of all the people addressed in the Reply-To field
getSentDate() returns the date the message was sent
getReceivedDate() returns the date the message was received
getRecipients() returns Array of email addresses; these are the emails to which the email was delivered to via RCPT TO
getSubject() returns the email subject
getSize() returns the size of the email
getToList() returns Array of Structs (name/email) of all the people addressed in the To field
spoolMailToDir(dir) saves the mail to disk and returns the full path of the saved file

Here is an example of extracting out only the plain text part of the email. This method works over MIME type emails as well as plain ones

<cfcomponent>

<cfscript>
function onMailAccept( mail ){
  var body = getBodyFromParts( arguments.mail.getBodyParts(), "text/plain" );

}

function getBodyFromParts( parts, mimetype ){
  var x=true;
  var part=true;

  for ( x=1; x<=ArrayLen( arguments.parts ); x=x+1){
    part = arguments.parts[x];
    if ( part.isMultiPart() ){
      return getBodyFromParts( part.getBodyParts(), arguments.mimetype );
    } else if ( part.getContentType().indexOf(arguments.mimetype) != -1 ){
      return part.getContent().trim();
    }
  }

  //No body was found
  return "";
}
</cfscript>

</cfcomponent>