How to use Rails mailer preview
Table of Contents
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:
And example of your new email:
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!