RoR Action Mailer
Action Mailer lets your Rails application send emails. It works similarly to controllers — you write a mailer class with methods (like actions), create corresponding view templates, and call the mailer from your controllers or background jobs. Rails handles composing and sending the email for you.
How Action Mailer Fits In
Controller (like ArticlesController) Mailer (like UserMailer) handles HTTP requests handles email sending has actions (index, show, create) has mail methods (welcome, reset_password) has views (index.html.erb) has views (welcome.html.erb) returns HTML response returns email message
Generate a Mailer
rails generate mailer UserMailer welcome_email password_reset
This creates:
app/mailers/user_mailer.rb app/views/user_mailer/welcome_email.html.erb app/views/user_mailer/welcome_email.text.erb app/views/user_mailer/password_reset.html.erb app/views/user_mailer/password_reset.text.erb spec/mailers/user_mailer_spec.rb
Writing a Mailer
app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
default from: "noreply@myapp.com"
def welcome_email(user)
@user = user
@login_url = new_user_session_url
mail(
to: @user.email,
subject: "Welcome to MyApp, #{@user.name}!"
)
end
def password_reset(user)
@user = user
@reset_url = edit_user_password_url(reset_password_token: user.reset_password_token)
mail(
to: @user.email,
subject: "Reset your MyApp password"
)
end
def order_confirmation(order)
@order = order
@user = order.user
mail(
to: @user.email,
subject: "Order ##{@order.id} Confirmed"
)
end
end
Email View Templates
Every mailer method has two views — HTML and plain text. Always provide both so email clients that block HTML still receive readable content.
app/views/user_mailer/welcome_email.html.erb <h1>Welcome to MyApp, <%= @user.name %>!</h1> <p>Your account is ready. You can log in at any time:</p> <p> <a href="<%= @login_url %>">Log In to MyApp</a> </p> <p>If you have any questions, reply to this email.</p> <p>— The MyApp Team</p>
app/views/user_mailer/welcome_email.text.erb Welcome to MyApp, <%= @user.name %>! Your account is ready. Log in at: <%= @login_url %> If you have any questions, reply to this email. — The MyApp Team
Sending Email from a Controller
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
UserMailer.welcome_email(@user).deliver_later ← async (recommended)
redirect_to root_path, notice: "Check your inbox for a welcome email!"
else
render :new, status: :unprocessable_entity
end
end
end
deliver_later → queues email as a background job (does not block the request) deliver_now → sends email immediately (blocks the request until sent)
Always use deliver_later in production. Email sending can take seconds and should never slow down a user's page load.
Configuring the Mail Server
Configure how Rails sends email in your environment files:
config/environments/development.rb
config.action_mailer.delivery_method = :letter_opener
# Shows emails in the browser instead of actually sending them
# gem "letter_opener" required
config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.sendgrid.net",
port: 587,
domain: "myapp.com",
user_name: "apikey",
password: ENV["SENDGRID_API_KEY"],
authentication: :plain,
enable_starttls_auto: true
}
config.action_mailer.default_url_options = { host: "myapp.com", protocol: "https" }
Email Preview in Development
Rails includes a mailer preview feature. Generate previews to see exactly how your emails look before sending:
test/mailers/previews/user_mailer_preview.rb
class UserMailerPreview < ActionMailer::Preview
def welcome_email
user = User.first || FactoryBot.build(:user)
UserMailer.welcome_email(user)
end
def password_reset
user = User.first
UserMailer.password_reset(user)
end
end
Visit http://localhost:3000/rails/mailers/user_mailer/welcome_email to see the rendered email in your browser.
Email Attachments
def invoice_email(order)
@order = order
pdf_data = InvoiceGenerator.generate(@order)
attachments["invoice-#{@order.id}.pdf"] = {
mime_type: "application/pdf",
content: pdf_data
}
mail(to: @order.user.email, subject: "Your Invoice")
end
Action Mailer Flow
User registers on your site
|
v
UsersController#create
@user.save
UserMailer.welcome_email(@user).deliver_later
|
v
Job queued in ActiveJob (background)
|
v
Background worker picks up the job
Calls UserMailer.welcome_email(@user)
|
v
Mailer builds the email:
Renders welcome_email.html.erb + .text.erb
Sets to:, subject:, from:
|
v
Rails hands email to SMTP server
|
v
SMTP delivers email to user's inbox
Testing Mailers
spec/mailers/user_mailer_spec.rb
RSpec.describe UserMailer, type: :mailer do
describe "#welcome_email" do
let(:user) { create(:user, name: "Alice", email: "alice@example.com") }
let(:mail) { UserMailer.welcome_email(user) }
it "renders the subject" do
expect(mail.subject).to eq("Welcome to MyApp, Alice!")
end
it "sends to the user's email" do
expect(mail.to).to include("alice@example.com")
end
it "sends from the default address" do
expect(mail.from).to include("noreply@myapp.com")
end
it "includes the user's name in the body" do
expect(mail.body.encoded).to include("Alice")
end
end
end
Action Mailer makes transactional email — welcome messages, confirmations, password resets, invoices — straightforward to build, preview, test, and deliver reliably in production.
