July 6, 2017
Monkey Patching Griddler to Add Mailgun Properties

Griddler is a great gem to consider if your Rails application needs to receive email messages. Griddler works by creating an endpoint to receive webhooks from email services like SendGrid and Postmark. Since each email service formats their webhook payloads differently, Griddler adapts each incoming message into a generic Email class instance.
While this generic class makes it really easy to switch email services without rewriting your code, it does require you to discard any data from incoming messages that Griddler doesn’t include in its Email class. For example, I prefer to use Mailgun due to its addition a stripped-text parameter, which automatically removes quoted text and signature blocks from emails.
When using Griddler out of the box, messages received from Mailgun don’t include the stripped-text parameter since it’s not a common email field. Luckily, we can use monkey patching to cleanly extend Griddler and add this functionality just for our app.
Install Griddler
Let’s first install Griddler in our Rails app by adding the griddler-mailgun gem to the end of the Gemfile:
gem 'griddler-mailgun'Run bundle install to install the Griddler gem with the Mailgun adapter. Next, add the default Griddler endpoint to app/config/routes.rb:
Rails.application.routes.draw do
mount_griddler
endThis will create an endpoint at /email_processor - Mailgun will send emails to this route, and they’ll be processed by Griddler.
We also need to add an initializer file to configure Griddler, so create a new file named app/config/initializers/griddler.rb with the following code:
Griddler.configure do |config|
config.email_service = :mailgun
endFinally, we’ll need to create a class named EmailProcessor - Griddler needs this to be defined in our app, and it’s where you’ll eventually process email messages after they arrive. You can place this file wherever you prefer in your Rails project, but let’s create it at lib/email_processor.rb:
class EmailProcessor
def initialize(email)
@email = email
end
def process
# do something with @email here
end
endIn the process method above, the @email object will contain an email message that was sent from Mailgun, arrived at your app’s /email_processor endpoint, and was processed by Griddler. You can easily access the contents of the message as attributes, such as @email.from and @email.body.
Now let’s extend Griddler to handle Mailgun’s stripped-text attribute, which is currently simply dropped when an email is processed.
Extending the Mailgun Adapter
Let’s first take a look at the source code of the Griddler Mailgun adapter class, which processes webhook payloads as they arrive from Mailgun:
module Griddler
module Mailgun
class Adapter
attr_reader :params
def initialize(params)
@params = params
end
def self.normalize_params(params)
adapter = new(params)
adapter.normalize_params
end
def normalize_params
{
to: to_recipients,
cc: cc_recipients,
bcc: Array.wrap(param_or_header(:Bcc)),
from: determine_sender,
subject: params[:subject],
text: params['body-plain'],
html: params['body-html'],
attachments: attachment_files,
headers: serialized_headers
}
end
# ...
end
end
endWe’re mainly interested in normalize_params - this method maps the params values to a new hash that can be parsed into a Griddler::Email instance. Since we know stripped-text is included in the params sent from Mailgun, we simply need to add a new key/value pair to the hash returned from normalize_params.
Let’s create a new module in our app to extend Griddler::Mailgun::Adapter - add the following code to app/config/initializers/griddler.rb:
# Add Mailgun stripped-text to normalized params
module GriddlerMailgunAdapterExtensions
def normalize_params
normalized_params = super
normalized_params[:stripped_text] = params['stripped-text']
normalized_params
end
end
# Prepend custom extensions
Griddler::Mailgun::Adapter.class_eval do
prepend GriddlerMailgunAdapterExtensions
endOur module contains its own normalize_params method, which will be used to override the normalize_params method in Griddler::Mailgun::Adapter. The super method calls the original normalize_params method, which returns a hash object. A new :stripped_text key is added to the hash, with the value of params['stripped-text'] from the Mailgun payload. The modified hash is then returned.
Our extension module is then applied to Griddler::Mailgun::Adapter by using class_eval to “open” the original class. The prepend method is then used to “mix in” our extension module method.
Now our new normalize_params code will execute in place of the original method in Griddler::Mailgun::Adapter, and the resulting hash output will include our new key/value pair.
Extending Griddler’s Email Class
We also need to monkey patch Griddler::Email to account for the updates we made to the Adapter. Here’s the relevant source code:
require 'htmlentities'
module Griddler
class Email
include ActionView::Helpers::SanitizeHelper
attr_reader :to,
:from,
:cc,
:bcc,
:original_recipient,
:reply_to,
:subject,
:body,
:raw_body,
:raw_text,
:raw_html,
:headers,
:raw_headers,
:attachments,
:vendor_specific,
:spam_report
def initialize(params)
@params = params
@to = recipients(:to)
@from = extract_address(params[:from])
@subject = extract_subject
@body = extract_body
@raw_text = params[:text]
@raw_html = params[:html]
@raw_body = @raw_text.presence || @raw_html
@headers = extract_headers
@cc = recipients(:cc)
@bcc = recipients(:bcc)
@original_recipient = extract_address(params[:original_recipient])
@reply_to = extract_address(params[:reply_to])
@raw_headers = params[:headers]
@attachments = params[:attachments]
@vendor_specific = params.fetch(:vendor_specific, {})
@spam_report = params[:spam_report]
end
# ...
end
endWe need to add :stripped_text to the attr_reader declaration, and make sure it’s parsed in the initialize method.
Add this code to app/config/initializers/griddler.rb:
# Assign Mailgun stripped-text to attribute
module GriddlerEmailExtensions
def initialize(params)
super
@stripped_text = params[:stripped_text]
end
end
# Add attribute for Mailgun stripped-text and prepend custom extensions
Griddler::Email.class_eval do
attr_reader :stripped_text
prepend GriddlerEmailExtensions
endWe’ve now defined a module with an initialize method, which uses super to call the original overridden method. An instance variable named @stripped_text is declared to store the value of params[:stripped_text] from our modified adapter (see previous section).
Finally, class_eval is used to modify the Griddler::Email class, where we add :stripped_text to the attr_reader declarations, then prepend our extension module method.
Wrapping it Up
Here’s the final version of app/config/initializers/griddler.rb:
Griddler.configure do |config|
config.email_service = :mailgun
end
# Add Mailgun stripped-text to normalized params
module GriddlerMailgunAdapterExtensions
def normalize_params
normalized_params = super
normalized_params[:stripped_text] = params['stripped-text']
normalized_params
end
end
# Prepend custom extensions
Griddler::Mailgun::Adapter.class_eval do
prepend GriddlerMailgunAdapterExtensions
end
# Assign Mailgun stripped-text to attribute
module GriddlerEmailExtensions
def initialize(params)
super
@stripped_text = params[:stripped_text]
end
end
# Add attribute for Mailgun stripped-text and prepend custom extensions
Griddler::Email.class_eval do
attr_reader :stripped_text
prepend GriddlerEmailExtensions
endTo recap, we’ve added a small amount of functionality to Griddler. When an email arrives from Mailgun, the stripped-text parameter is now processed, and is included as an attribute of the resulting Griddler::Email object. We’re now free to use stripped-text anywhere in our application!
Source Code Available on GitHub
You can find the full source code for this example here: https://github.com/jwkratz/griddler-stripped-text