Find file
Fetching contributors…
Cannot retrieve contributors at this time
125 lines (95 sloc) 3.88 KB


SendgridPostback is a Rails Engine which integrates with the SendGrid Event API.

It includes a MailInterceptor which will attach a UUID header in all mails before they are sent. When properly configured, SendGrid will then post events for each message to your app. You'll know when emails are delivered, bounced, delayed, clicked, etc., according to your SendGrid account configuration.

Note that for performance reasons, you'll probably want to configure your Event API to batch events. The bad news is that SendGrid POSTs newline-separate JSON objects, rather than a JSON array. As such, ActionDispatch is patched (see action_dispatch_ext.rb) to handle the "invalid" incoming JSON.


Add this line to your application's Gemfile:

gem 'sendgrid_postback', git: "git://"

You'll need to configure your SendGrid account to enable the Event API.

Configure the library, i.e. in your app's config/initializers/sendgrid_postback.rb:

require 'sendgrid_postback'
SendgridPostback.configure do |config|
  config.logger = Rails::Logger

  # Path that routes to SendgridPostback::EventsController#create
  config.request_path = '/sendgrid_postback/events'

  # proc that accepts an exception for reporting
  config.report_exception = proc { |exc| ... } # Optional

  # If you're creating Sendgrid UUID yourself, disable the interceptor
  config.enable_interceptor = false

  # Allow the controller to recieve data over non-ssl connections
  config.require_ssl = false

  # Required proc that returns an instance for the given uuid.
  # The class should mix in SendgridPostback::EventReceiver
  config.find_receiver_by_uuid = proc do |uuid|
    Notification.find_by_uuid(uuid) # for example

  # Sendgrid will post all events to your receiver URL.  If emails are sent
  # via Sendgrid outside of this application their events will still post back here.
  # You can specify a model here.
  # Add a post_general_sendgrid_event(data) method to handle receiving the data as
  # you please.
  config.get_general_event_receiver = proc do

Add the route manually to your routes.rb at the top level, so the declaration can remain DRY:

  post SendgridPostback.config.request_path => 'sendgrid_postback/events#create', constraints: { protocol: 'https' }


Your app should have a class, i.e. an ActiveRecord model, that mixes in SendgridPostback::EventReceiver. This module adds attributes that should be persisted, sendgrid_events and sendgrid_state.

class AddEventsAndState < ActiveRecord::Migration
  def self.up
    add_column :notifications, :uuid, :string
    add_column :notifications, :state, :string
    add_column :notifications, :events, :text

  def self.down
    remove_column :notifications, :uuid
    remove_column :notifications, :state
    remove_column :notifications, :events
class Notification < ActiveRecord::Base
  include SendgridPostback::EventReceiver
  serialize :sendgrid_events

Add a new or adapt your existing MailObserver to trap email after they are sent to create a receiver instance. You may wish to also persist the email content itself.

class MailObserver

  # Capture UUID set by MailInterceptor and create a new Notification record
  def self.delivered_email(email)
        uuid: email.uuid
        to:', '),
        subject: email.subject,
        email: email.to_s

  def self.register



  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request