Ahrens Insights

action mailerrb

📅 October 29, 2026📖 Verified Publication
```html ActionMailer RB: The Complete Playbook for Rails Email Development

ActionMailer RB: The Complete Playbook for Rails Email Development

Rails applications almost universally need to send emails—password resets, transactional receipts, marketing campaigns, and system alerts. ActionMailer is Rails’s built-in framework for handling these use cases, and it remains one of the most powerful yet underutilized features in the Rails ecosystem. This playbook covers everything from basic setup through production-grade architecture.

Key Takeaways

  • ActionMailer classes inherit from ApplicationMailer or Mail::Message and use dedicated view templates for each email variant.
  • Always delegate actual delivery to Active Job — never call deliver_now in request-response cycles.
  • Use delivery_method configuration to switch between SMTP, API-based providers (SendGrid, AWS SES, Mailgun), and test/adapters during development.
  • Write focused test cases with deliver_later verification, fixture-based assertions, and delivery counter mocks.
  • Leverage inline layouts, text/HTML multipart bodies, and ActionMailer preview routes for a professional workflow.
  • Handle bounces, unsubscribes, and spam complaints through webhook receivers and proper list hygiene to protect sender reputation.

What Is ActionMailer?

ActionMailer is Rails’s mail delivery subsystem. It follows the same conventions as Action Controller: each mailer class contains methods that map to individual email templates, and Rails renders those templates using the familiar ERB or HAML tooling you already use in views.

Unlike a typical controller action, ActionMailer operates entirely outside the HTTP request cycle. It builds a Mail::Message object, renders templates asynchronously (when properly configured), and hands off the message to a delivery adapter. Understanding this separation is critical for writing performant, non-blocking applications.

Core Components

  • Mailer Class — Inherits from ApplicationMailer; defines email methods and default headers.
  • Email Templates — View files located under app/views/{mailer_name} supporting HTML, text, and attachments.
  • Delivery Adapter — Configured per environment (SMTP, SendGrid, AWS SES, test, file, logger).
  • Job Integration — deliver_later queues emails through Active Job for background processing.
  • Preview Route — /rails/mailers allows visual inspection of email templates during development.

Setting Up ActionMailer in Your Rails Application

Step 1 — Create the Mailer

rails generate mailer UserMailer welcome_password_reset

This generator creates four artifacts:

  • app/mailers/user_mailer.rb — The mailer class
  • app/views/user_mailer/ — Template directory
  • test/mailers/user_mailer_test.rb — Test skeleton
  • test/mailers/previews/user_mailer_preview.rb — Preview class

Step 2 — Configure the Mailer Base Class

class ApplicationMailer < ActionMailer::Base
  default from: "noreply@yourapp.com"
  default reply_to: "support@yourapp.com"
  default template_path: "emails"
  layout "email"
end

Step 3 — Set Delivery Configuration

Configure config/action_mailer in config/environments/production.rb:

config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_options = {from: "noreply@yourapp.com"}

config.action_mailer.smtp_settings = {
  address:              "smtp.sendgrid.net",
  port:                 587,
  domain:               "yourapp.com",
  user_name:            ENV["SENDGRID_USERNAME"],
  password:             ENV["SENDGRID_PASSWORD"],
  authentication:       "plain",
  enable_starttls_auto: true
}

Step 4 — Enable Action Mailer Preview Routes

# config/routes.rb
Rails.application.routes.draw do
  # ...
  mount Rails::MailersController => "/rails/mailers"
end

Pre-Launch Checklist

  • [ ] Verify config.action_mailer.perform_deliveries is true in production
  • [ ] Confirm all ENV variables for credentials are set in deployment
  • [ ] Add config.action_mailer.default_url_options for URL generation in links
  • [ ] Set up SPF, DKIM, and DMARC records for your sending domain
  • [ ] Configure a webhook endpoint for bounce and complaint handling
  • [ ] Add a staging delivery rule (e.g., deliver to a catch-all address)
  • [ ] Test deliver_now manually against the preview route before launch

Writing Effective Mailer Methods

Basic Mailer Method

class UserMailer < ApplicationMailer
  def welcome(user)
    @user = user
    mail(
      to: user.email,
      subject: "Welcome to Acme, #{@user.first_name}",
      cc: "onboarding@yourapp.com"
    )
  end
end

Multipart Emails

Production applications should always send both HTML and plain-text variants. Rails handles this automatically when both .html.erb and .text.erb templates exist in the same directory.

# app/views/user_mailer/welcome.html.erb
<h1>Welcome, <%= @user.first_name %>!</h1>
<p>Get started by <%= link_to "setting up your profile", signup_url(@user.signup_token) %>.</p>

# app/views/user_mailer/welcome.text.erb
Welcome, <%= @user.first_name %>!

Get started by signing up at: <%= signup_url(@user.signup_token) %>

Attachment Handling

def monthly_report(user, report)
  @user = user
  @report = report

  attachments["report.pdf"] = File.read(report.path)

  mail(
    to: @user.email,
    subject: "Your monthly report is ready"
  )
end

Inline Images

def onboarding_email(user)
  @user = user
  attachments.inline["logo.png"] = File.read(Rails.root.join("app/assets/images/logo.png"))

  mail(to: @user.email, subject: "Welcome aboard")
end

Then reference in the HTML template:

<%= image_tag attachments["logo.png"].url, alt: "Logo" %>

Integrating ActionMailer with Active Job

Why Use deliver_later Instead of deliver_now

Calling deliver_now inside a controller blocks the request thread until the email is sent. In production with external SMTP providers, this introduces unpredictable latency and risks timeout errors. The recommended pattern is to enqueue the mailer via deliver_later, which delegates to Active Job.

Standard Enqueue Pattern

# In a controller or service object
UserMailer.welcome(user).deliver_later
# or with explicit queue
UserMailer.welcome(user).set(queue: "email_high_priority").