Stay Ahead in Ruby!
From development processes to the most useful gems, get it all straight in your inbox. Join our Ruby blog today!

Skip to main content

How to use Rails mailer preview

·3 mins
Attention! This article might be outdated, refer to latest documentation if solution does not work.
How to use Rails mailer preview - cover image

Each of us has come across a situation when we need to test emails. For example, check the appearance, markup, or content of the email. Starting with Rails 4.1, it became possible to view emails without sending them. Let’s take a look at this tool.

Rails Mailer #

Firstly, let’s generate a Mailer which sends emails about new teams:

rails generate mailer TeamMailer
      create  app/mailers/team_mailer.rb
      invoke  erb
      create    app/views/team_mailer
      invoke  rspec
      create    spec/mailers/team_spec.rb
      create    spec/mailers/previews/team_preview.rb

The next step is to define a method that will allow us to send an email when a new team is created:

# /app/mailers/team_mailer.rb
class TeamMailer < ApplicationMailer
  def new_team_added(team)
    @team = team
    subject = 'A new team has been created'
    mail(from: TECH_TEAM_EMAIL, to: team.president.email, subject: subject)
  end
end
# /app/models/team.rb
after_create :send_email_to_president

...

private

def send_email_to_president
  TeamMailer.new_team_added(self).deliver_now
end

Since TeamMailer is inherited from ApplicationMailer, it will use the mailer default layout. But you can create your own custom layout and save it in /app/views/layouts/team_mailer.html.erb:

# /app/views/layouts/team_mailer.html.erb
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style>
      /* Email styles need to be inline */
    </style>
  </head>

  <body>
    <%= yield %>
  </body>
</html>
# /app/mailers/team_mailer.rb
class TeamMailer < ApplicationMailer
  layout 'team_mailer'

  def new_team_added(team)
    @team = team
    subject = 'A new team has been created'
    mail(from: TECH_TEAM_EMAIL, to: team.president.email, subject: subject)
  end
end

If you only need to use the layout for one specific email, you can also do this:

# /app/mailers/team_mailer.rb
class TeamMailer < ApplicationMailer
  layout 'team_mailer'

  def introduce_to_president(team, user_email)
    subject = "Thanks for your interest in joining the #{team.name} team"
    mail(from: team.president.email, to: user_email, subject: subject) do |format|
      format.html { render layout: 'new_team_member' }
    end
  end
end

Mailer preview #

What if we want to see our email in the browser to make sure it looks as expected? Actually, the Rails generator has already done most of the work for us. The command we launched at the beginning also created this file: /spec/mailers/preview/team_mailer.rb

# spec/mailers/previws/team_mailer_preview.rb

# Preview all emails at http://localhost:3000/rails/mailers
class TeamMailerPreview < ActionMailer::Preview
  def new_team_added
    team = Team.first
    TeamMailer.new_team_added(team)
  end

  def introduce_to_president
    user_email = FactoryBot.create(:user).email
    team = FactoryBot.create(:team, :group)
    TeamMailer.introduce_to_president(team, user_email)
  end
end

Note that you can use existing data from the database, or you can use FactoryBot to generate the data. Factories need to be set up first.

As a result, going to the preview page, we will see the following structure:

Preview page

And example of your new email:

Preview page

You can also setup email preview in other environments. You can use the following config:

# config/environments/staging.rb

config.action_mailer.show_previews = true

Problems and how to solve them #

When working with FactoryBot, you may run into the problem that all generated data remains in the database and is not cleared after viewing. To avoid this problem, you can add a helper method that will do rollbacks:

# config/initializers/preview_helper.rb

if Rails.env.development?
  def preview_helper
    message = nil
    begin
      ActiveRecord::Base.transaction do
        message = yield
        message.to_s
        raise ActiveRecord::Rollback
      end
    rescue ActiveRecord::Rollback
    end
    message
  end
end

Then you need to make changes in your preview file

# spec/mailers/previws/team_mailer_preview.rb

# Preview all emails at http://localhost:3000/rails/mailers
class TeamMailerPreview < ActionMailer::Preview
  preview_helper do
    def new_team_added
      team = Team.first
      TeamMailer.new_team_added(team)
    end
  end
end

We are ready to provide expert's help with your product
or build a new one from scratch for you!

Contact MobiDev’s tech experts!