Saturday, February 16, 2013

Easy Mandrill inbound email and webhook handling with Rails

(blogarhythm ~ Psycho Monkey - Joe Satriani)

Mandrill is the transactional email service by the same folks who do MailChimp, and I've been pretty impressed with it. For SMTP mail delivery it just works great, but where it really shines is inbound mail handling and the range of event triggers you can feed into to your application as webhooks (for example, to notify on email link clicks or bounces).

The API is very nice to use, but in a Rails application it's best to keep all the crufty details encapsulated and hidden away, right? That's what the mandrill-rails gem aims to do - make supporting Mandrill web hooks and inbound email as easy and Rails-native as possible.

I recently added some new methods to mandrill-rails to provide explicit support for inbound mail attachments (in the 0.0.3 version of the gem).

With the mandrill-rails gem installed, we simply define the routes to our webhook receiver (in this example an 'inbox' controller):
resource :inbox, :controller => 'inbox', :only => [:show,:create]
And then in the controller we provide handler implementations for any of the 9 event types we wish to consume. Here's how we might get started handling inbound email, including pulling out the attachments:
class InboxController < ApplicationController
  include Mandrill::Rails::WebHookProcessor

  # Defines our handler for the "inbound" event type. 
  # This gets called for every inbound event sent from Mandrill.  
  def handle_inbound(event_payload)
    [... do something with the event_payload here, 
         or stuff it on a background queue for later ... ]
    if attachments = event_payload.attachments.presence
      # yes, we have at least 1 attachment. Let's examine the first:
      a1 = attachments.first
      a1.name # => e.g. 'sample.pdf'
      a1.type # => e.g. 'application/pdf'
      a1.content
      # => this is the raw content provided by Mandrill, 
      #    and will be base64-encoded if not plain text
      # e.g. 'JVBERi0xLjMKJcTl8uXrp/Og0MTGCjQgMCBvY ... (etc)'
      a1.decoded_content
      # => this is the content decoded by Mandrill::Rails, 
      #    ready to be written as a File or whatever
      # e.g. '%PDF-1.3\n%\xC4\xE5 ... (etc)'
    end
  end

end
That's nice and easy, yes? See the Mandrill::Rails Cookbook for more tips.

If you love playing with transactional mail and haven't tried Mandrill yet, it's well worth a look!