Last Updated: September 09, 2019
·
1.859K
· glebm

Rails Email Protips

CSS inlining

For the best HTML e-mail delivery results, CSS should be inline. This is a huge pain and a simple newsletter becomes un-managable very quickly. Inline email CSS automatically with premailer-rails or roadie-rails

UTM tracking

Append UTM params with email identifier to all the links in the emails:

# Gemfile
gem 'addressable'
# app/mailer_interceptors/utm_mailer_interceptor.rb
class UtmMailerInterceptor
  URL_RE  = /\b((https?):\/\/\w+\.[-A-Z0-9+&@#\/%?=~_|$!:,.;]*)/i
  URL_IN_HREF_RE=/href=["']#{URL_RE}["']/i 
  MIME_TYPES = %w(text/plain text/html application/xhtml+xml)
  class << self
    def delivering_email(message)
      [message, message.all_parts].flatten.compact.each do |part|
        if MIME_TYPES.include?(part.mime_type)
          part.body = part.body.decoded.gsub(URL_IN_HREF_RE) do |href, a|
            url = $1
            if url !~ /\.(jpg|png|gif)(\?|$)/
              %Q(href="#{append_utm message, url}")
            else
              href
            end
          end
        end
      end
    end

    private
    def append_utm(message, url)
      params = {
          utm_source:   'App Emails',
          utm_medium:   'email',
          utm_campaign: message.header['X-APP-EMAIL-ID'].value,
          utm_content:  message.subject
      }
      append_params url, params
    end

    def append_params(url, params)
      uri              = Addressable::URI.parse(url)
      uri.query_values = (uri.query_values || {}).merge(params)
      uri.to_s
    end
  end
end
# config/initializers/configure_mailers.rb
ActionMailer::Base.register_interceptor UtmMailerInterceptor
ActionMailer::Base.class_eval do
  def mail(headers = {}, &block)
    # Set identifier for the email being rendered
    headers['X-APP-EMAIL-ID'] ||= "#{self.class.name.underscore}-#{caller[0][/`.*'/][1..-2]}"
    super(headers, &block)
  end
end

Email Preview

For rapid development you might want to be able to preview emails and test deliveries easily, using a gem such as REP.

screenshot

3 Responses
Add your response

Cheers Gleb, some nice tips!

Another invaluable tool I've found recently is MailCatcher - A super simple SMTP server which catches emails with preview functionality. It's great for testing email deliveries and eliminates the risk of mails being sent to live customer addresses.

over 1 year ago ·

Thanks Steve! I found MailCatcher useful but having to trigger the email delivery inconvenient. REP instead provides a UI for previewing all the emails that the application can send:

rep

Saves the time to figure out where and how the email is sent whenever something needs changing.

over 1 year ago ·

You cannot call super when using classeval because you are overwriting it. A working solution is to use aliasmethod and to replace super.

...
aliasmethod :oldmail, :mail
...
old_mail(headers, &block)

over 1 year ago ·