Access URL Request Parameters from ActionMailer Preview

Login to Access Code

At first, I thought that maybe I was going crazy. How could rails support rendering email previews but have it so locked down it’s almost useless outside of local testing? Hey RAILS TEAM, haven’t you guys ever seen the “View this email in your browser” links on most email marketing platforms?! Apparently not.

Anyways, after a bit of hacking, I found the best way to go about this. These hacks are not only useful for permalinking your emails to your website, but also for development if you want to test with various dummy data or locales; which it seems a number of people do.

Custom Methods on ActionMailer Preview and Base

This is actually pretty easy, albeit not very obvious if you’re not familiar with Rails internals. Just create a new initializer with this code. It basically just extends ActionMailer::Preview and ActionMailer::Base with our ActionController::Base request object. We can tap into anything we want from action controller here in the inject_request method and make the Preview class behave more like a classic Rails controller as much as we want.

# config/initializers/mailer_injection.rb

# This allows `request` to be accessed from ActionMailer Previews
# And @request to be accessed from rendered view templates
# Easy to inject any other variables like current_user here as well

module MailerInjection
  def inject(hash)
    hash.keys.each do |key|
      define_method key.to_sym do
        eval " @#{key} = hash[key] "

class ActionMailer::Preview
  extend MailerInjection

class ActionMailer::Base
  extend MailerInjection

class ActionController::Base
  before_filter :inject_request

  def inject_request
    ActionMailer::Preview.inject({ request: request })
    ActionMailer::Base.inject({ request: request })

Allowing Email Previews to be Accessed in Production

Open up production.rb or whatever environment you want, and just opt-in to these previews with:

config.action_mailer.show_previews = true

I recommend jailing the default /rails/mailers route and making your own route with authentication. Here’s a sample to get you started on that path:

# config/application.rb

# Allow Mailer Previews on Production for static linking.
# This needs to be jailed as much as possible!!
config.action_mailer.show_previews = true
routes.append do
  get '/email/*path'   => "rails/mailers#preview"

This is all working for Rails 5, but I assume much of it is the same going back to Rails 4.1 or anywhere between. Comment with any questions or kudos!