Agent skill

rails-mailer-patterns

Action Mailer patterns for Rails applications. Automatically invoked when working with email delivery, mailer classes, email templates, mailer previews, interceptors, or delivery configuration. Triggers on "mailer", "email", "ActionMailer", "deliver_later", "deliver_now", "mail template", "email preview", "SMTP", "SendGrid", "Postmark", "notification email". NOT for push notifications, SMS, or in-app messaging.

Stars 4
Forks 0

Install this agent skill to your Project

npx add-skill https://github.com/ag0os/rails-dev-plugin/tree/main/skills/rails-mailer-patterns

SKILL.md

Rails Mailer Patterns

Analyze and recommend Action Mailer patterns for reliable, well-structured email delivery in Rails applications.

Follow standard Rails conventions for basic mailer structure, mail() calls, delivery configuration, multipart templates, attachments, and I18n subjects. Focus on the opinionated patterns below.

See patterns.md for detailed code examples.

Quick Reference

Pattern Use When
Parameterized mailer with before_action Shared context across multiple mailer methods
Mailer preview per method Every mailer method needs a preview — catches layout issues CI cannot
Staging interceptor Prevent real emails in non-production environments
_later/_now convention Model triggers delivery; mailer is just the template layer
Profile-aware testing Minitest (omakase) vs RSpec (service-oriented)

Core Principles

  1. Always deliver_later: Email delivery is I/O — background job by default
  2. Mailers are views, not logic: Assemble data and call mail(). No business logic
  3. One email per method: No conditionals choosing between templates
  4. Preview every email: Mailer previews catch layout issues CI cannot
  5. _later/_now on the model: The model defines when to send; the mailer defines what to send

Parameterized Mailers

Share context across methods without repeating arguments:

ruby
class UserMailer < ApplicationMailer
  before_action { @user = params[:user] }
  before_action { @account = params[:user].account }

  default to: -> { @user.email }

  def welcome
    mail(subject: "Welcome to #{@account.name}")
  end

  def weekly_digest
    @events = @user.events.from_last_week
    mail(subject: "Your weekly digest")
  end
end

# Usage
UserMailer.with(user: user).welcome.deliver_later

ApplicationMailer with Dynamic From

ruby
class ApplicationMailer < ActionMailer::Base
  default from: -> { "#{Current.account&.name || 'App'} <noreply@example.com>" }
  layout "mailer"

  rescue_from Net::SMTPSyntaxError, with: :log_delivery_error

  private

  def log_delivery_error(exception)
    Rails.logger.error("[Mailer] Delivery failed: #{exception.message}")
  end
end

Staging Email Interceptor

Prevent sending real emails in staging — redirects all mail to a safe inbox:

ruby
# app/mailers/interceptors/staging_interceptor.rb
class StagingInterceptor
  def self.delivering_email(message)
    original_to = message.to
    message.to = ["staging-inbox@example.com"]
    message.cc = nil
    message.bcc = nil
    message.subject = "[STAGING] #{message.subject} (was: #{original_to.join(', ')})"
  end
end

# config/initializers/mail_interceptors.rb
if Rails.env.staging?
  ActionMailer::Base.register_interceptor(StagingInterceptor)
end

Previews

ruby
# test/mailers/previews/order_mailer_preview.rb  (Omakase)
# spec/mailers/previews/order_mailer_preview.rb   (Service-oriented)
class OrderMailerPreview < ActionMailer::Preview
  def confirmation
    order = Order.first || Order.new(id: 1, number: "PREVIEW-001", created_at: Time.current)
    OrderMailer.confirmation(order)
  end

  def confirmation_with_discount
    order = Order.joins(:discount).first
    OrderMailer.confirmation(order)
  end
end
# Visit: http://localhost:3000/rails/mailers/order_mailer/confirmation

Profile-Aware Delivery Triggers

Omakase — model triggers delivery:

ruby
class Order < ApplicationRecord
  after_create_commit :send_confirmation

  private

  def send_confirmation
    OrderMailer.confirmation(self).deliver_later
  end
end

Service-oriented — service triggers delivery:

ruby
class Orders::Create
  def call
    order = Order.create!(params)
    OrderMailer.confirmation(order).deliver_later
    Result.new(success: true, order: order)
  end
end

Profile-Aware Testing

Omakase — Minitest:

ruby
class OrderMailerTest < ActionMailer::TestCase
  test "confirmation email" do
    order = orders(:confirmed)
    email = OrderMailer.confirmation(order)

    assert_emails 1 do
      email.deliver_now
    end
    assert_equal [order.user.email], email.to
    assert_match "Order ##{order.number}", email.subject
  end
end

Service-oriented — RSpec:

ruby
RSpec.describe OrderMailer, type: :mailer do
  describe "#confirmation" do
    let(:order) { create(:order) }
    let(:mail) { described_class.confirmation(order) }

    it "renders the headers" do
      expect(mail.to).to eq([order.user.email])
      expect(mail.subject).to match(/Order ##{order.number}/)
    end

    it "renders the body" do
      expect(mail.body.encoded).to include(order.number)
    end
  end
end

Anti-Patterns

Anti-Pattern Fix
deliver_now in controllers Use deliver_later — email is I/O
Business logic in mailers Move to model/service, pass data to mailer
Conditional templates in one method One method per email
No previews Add preview for every mailer method
HTML-only emails Always include text part

Output Format

When creating mailers, provide:

  1. Mailer class with proper structure
  2. View templates (HTML + text parts)
  3. Preview class for visual testing
  4. Test file matching project profile (Minitest or RSpec)
  5. Delivery configuration notes if relevant

Expand your agent's capabilities with these related and highly-rated skills.

ag0os/rails-dev-plugin

rails-caching-patterns

Caching patterns for Rails applications including fragment caching, low-level caching, HTTP caching, Russian doll caching, and cache invalidation strategies. Automatically invoked when working with Rails.cache, cache stores, stale?/fresh_when, fragment caching, cache keys, or performance optimization through caching. Triggers on "cache", "caching", "Rails.cache", "fragment cache", "Russian doll", "stale?", "fresh_when", "cache key", "cache store", "Redis cache", "Solid Cache", "memcached", "ETag", "cache invalidation", "cache bust". NOT for CDN configuration (use rails-devops-patterns) or database query optimization (use rails-model-patterns).

4 0
Explore
ag0os/rails-dev-plugin

rails-graphql-patterns

Analyzes and recommends GraphQL patterns for Rails using graphql-ruby including schema design, types, resolvers, mutations, subscriptions, DataLoader, and query complexity. Use when building GraphQL APIs, defining types, writing mutations, optimizing N+1 queries, or structuring app/graphql. NOT for REST API controllers, ActiveRecord queries outside GraphQL, or Turbo Stream responses.

4 0
Explore
ag0os/rails-dev-plugin

ruby-object-design

Automatically invoked when making decisions about Ruby code structure and organization. Triggers on "class or module", "should this be a class", "struct vs class", "PORO", "data object", "design pattern", "class vs module", "when to use class", "module vs class", "stateless class", "value object", "data container", "object factory", "extend self", "singleton class". Provides guidance on choosing the right Ruby construct (class, module, Struct, Data, Hash). NOT for code smell identification or refactoring (use ruby-refactoring) or Rails-specific framework patterns.

4 0
Explore
ag0os/rails-dev-plugin

rails-views-patterns

Analyzes Rails view templates, partials, layouts, helpers, and form patterns for best practices. Use when reviewing ERB templates, improving view performance with fragment caching, fixing form helpers, organizing partials, adding accessibility attributes, or evaluating collection rendering. NOT for Stimulus/Turbo logic (use hotwire-patterns), controller concerns, or API-only responses.

4 0
Explore
ag0os/rails-dev-plugin

rails-architecture-patterns

Provides architectural planning, design decisions, and coordination guidance for Rails applications. Use when planning new features, choosing between design approaches (STI vs polymorphic, service vs concern, monolith vs engine), evaluating system architecture, or deciding which domain skill or agent to delegate to. NOT for implementation details within a single domain (use the domain-specific skill instead).

4 0
Explore
ag0os/rails-dev-plugin

rails-devops-patterns

Analyzes Rails deployment, infrastructure, and production configuration for best practices. Use when setting up Docker, writing CI/CD pipelines, configuring Puma, adding monitoring or logging, hardening security (SSL, Rack::Attack, headers), optimizing database config, or reviewing production environment files. NOT for application business logic, model design, or test writing.

4 0
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results