Smart Application Messaging: The Email Reflector

When it comes to the topic of messaging in a web application, clients will often ask if they can send targeted emails to their site's users with their preferred email client (usually Microsoft Outlook). This question starts to hint at the real functionality that a client wants. From their perspective, they need a solution that:
  1. Aligns with their current skill sets when it comes to messaging (e.g., using Outlook as the preferred email application).
  2. Allows them to deliver customized messages to every subset of their user base.
  3. Provides dynamic capabilities so that each time a new user is added, he or she will start receiving the appropriate messages.
Let's look at the pros and cons of the traditional ways developers have solved these problems. Approach #1: Email Export to Outlook Most of the time, web applications simply store and display data. A typical reporting feature in these applications is the ability to generate an email list based on certain criteria. Once you have access to this data in the format that you want, you can use this in the "Bcc" field in your desktop email client. This satisfies all three conditions above; but, there are a few key areas where this falls apart:
  • Instead of easily firing off an email from their address book, clients are now forced to log into the web application, run a report, and grab the contact list – not a simple proposition.
  • If the list of emails is large enough, the risk of exceeding the maximum number of recipients increases – not something we want our clients to have to suffer through.
  • Since this is a manual process, any human error introduces the possiblity of exposing our distribution list, compromising the privacy of our user base.
If we want to reduce the possibility for human error, we can rely on our application to handle the delivery of messages. Approach #2: Custom Messaging Assuming our application has the reporting mechanism discussed in the first approach, it's quite simple to tie in some basic messaging functionality. Once the user has generated the email list, we can provide a simple interface to customize the content of the message. While this removes the hassle of switching back-and-forth between applications, we are still faced with some issues:
  • Any advanced features (e.g., attachments, alternate content) that the client is familiar with in their existing email application will have to be custom-built into our new web-based system.
  • Though not necessarily difficult (depending on the implementation), the client now has to re-learn how to send a message from the new web application.
If we can both leverage the client's existing email skills and provide some dynamic capabilities, we will have a solution that addresses all three objectives. Approach #3: The Email Reflector When I attended the Flickr Workshop in NYC early this year, Cal discussed how Flickr gives users the ability to email photos from their existing mail clients into their Flickr account. This got me thinking about what other features were possible with this approach. As it turns out, this gives us the ability to send email to a dynamic list of recipients using a single pre-configured email address. The Technical Details At a high level, there are only three things necessary to make this work:
  1. Set up the MTA to push raw email content to a script.
  2. Gather a list of email addresses.
  3. Redirect the raw message to the list of recipients.
Let's look at these steps in more detail. The examples provided assume that you're working with my sample code (provided at the end of the post). Step #1: Set Up the MTA In my testing, I used the installation of Qmail that we had installed on one of our Gentoo development servers. This will work just as well with a Sendmail installation – in fact, Cal discussed using Sendmail in his example. We basically just need to configure the email for a single user to redirect to a script. For Qmail or Sendmail, you only need to add a single line to the .qmail or .forward file, respectively (make sure the script is at least executable by the user): |/path/to/demo/reflector.php This handles the messages as they come in; but, we still need to decide who will ultimately receive the message. Step #2: Gather the Email Addresses This is pretty simple: we just need to get a list of addresses based on certain reporting criteria. Once we have this list, we can send the original message on its way, stripping the original "To" address and any unnecessary "Received" headers before we send. Step #3: Send the Message Using the provided EmailReflector class, we can push off all the heavy-lifting to it with just a few lines of code: $reflector = new EmailReflector('smtp-host'); $reflector->setInputSource('php://stdin'); $reflector->redirect($recipientList); The message is now Bcc'd to the specified list of recipients with all the original contents (including attachments) in place. Enhancements Because this is still "proof-of-concept" code, there are some issues that still need to be addressed:
  • Security - If someone can guess the target email address for the reflector, he or she has the ability to spam your site's users. By making the target email harder to guess (good) or having the sender provide a security token (better), we can minimize this risk.
  • Batching - As a site's user base grows, the number of emails that will be sent through this sytem increases. By providing some basic batching features, we can handle a larger volume.
  • Catch-all addresses - A reporting feature that I see as useful would give users the ability to generate a report and save it with an associated email address. Any time a message is sent to this address, it will regenerate the report and send the email. Setting up a catch-all email address for a subdomain would make this possible.
The Code Download the source (.tar.gz format) Download the source (.zip format)

Patrick is development director in Viget's Boulder, CO, office. He writes clean Ruby code and automates system infrastructure for clients such as Shure and Volunteers of America.

More posts by Patrick