ActionMailer advanced patterns for transactional emails

Sarah Mitchell Feb 2026
2 tabs
# app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
  default from: 'noreply@example.com'

  def welcome_email(user)
    @user = user
    @url = login_url

    mail(
      to: email_address_with_name(@user.email, @user.name),
      subject: 'Welcome to My App!'
    )
  end

  def password_reset(user)
    @user = user
    @token = user.generate_reset_token

    mail(
      to: @user.email,
      subject: 'Reset your password'
    )
  end

  def notification(user, message)
    @user = user
    @message = message

    mail(
      to: @user.email,
      subject: "New notification: #{message.title}",
      reply_to: 'support@example.com'
    )
  end

  def weekly_digest(user, posts)
    @user = user
    @posts = posts

    # Add custom headers
    headers['X-Campaign-ID'] = 'weekly-digest'

    # Attach file
    attachments['report.pdf'] = File.read('path/to/report.pdf')

    # Inline attachment for images in email
    attachments.inline['logo.png'] = File.read('app/assets/images/logo.png')

    mail(
      to: @user.email,
      subject: "Your weekly digest (#{posts.count} new posts)",
      template_name: 'digest',
      template_path: 'user_mailer'
    )
  end

  def bulk_email(users, content)
    @content = content

    users.find_each do |user|
      @user = user
      mail(
        to: user.email,
        subject: content.subject
      ).deliver_later(wait: rand(60).seconds)  # Spread out delivery
    end
  end
end

# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: 'noreply@example.com'
  layout 'mailer'

  private

  def email_address_with_name(email, name)
    "\"#{name}\" <#{email}>"
  end
end

# Sending emails
# Synchronous (blocks until sent)
UserMailer.welcome_email(@user).deliver_now

# Asynchronous (queues for background delivery)
UserMailer.welcome_email(@user).deliver_later

# Delayed delivery
UserMailer.welcome_email(@user).deliver_later(wait: 1.hour)
UserMailer.welcome_email(@user).deliver_later(wait_until: Date.tomorrow.noon)

# Configuration
# config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  address: 'smtp.sendgrid.net',
  port: 587,
  domain: 'example.com',
  user_name: ENV['SENDGRID_USERNAME'],
  password: ENV['SENDGRID_PASSWORD'],
  authentication: 'plain',
  enable_starttls_auto: true
}

config.action_mailer.default_url_options = { host: 'example.com' }
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
2 files · ruby Explain with highlit

ActionMailer handles email delivery in Rails. Mailers are similar to controllers—actions generate email content. I use ActionMailer for welcome emails, password resets, notifications. Layouts apply consistent styling across emails. Previews enable viewing emails without sending. deliver_later queues emails via ActiveJob for async sending. Interceptors modify emails before delivery—useful for staging environments. Multi-part emails include both HTML and text versions. Attachments add files to emails. Testing uses ActionMailer::TestCase and email spy. Understanding email delivery configuration—SMTP, SendGrid, Postmark—is essential. ActionMailer integrates with email service providers for reliability and deliverability.