スキル一覧に戻る
zerobearing2

rails-aimailers

by zerobearing2

Opinionated Rails AI agent system

20🍴 1📅 2026年1月20日
GitHubで見るManusで実行

SKILL.md


name: rails-ai:mailers description: Use when sending emails - ActionMailer with async delivery via SolidQueue, templates, previews, and testing

Email with ActionMailer

Send transactional and notification emails using ActionMailer, integrated with SolidQueue for async delivery. Create HTML and text templates, preview emails in development, and test thoroughly.


ActionMailer Setup

Mailer Class:

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

# app/mailers/notification_mailer.rb
class NotificationMailer < ApplicationMailer
  def welcome_email(user)
    @user = user
    @login_url = login_url
    mail(to: user.email, subject: "Welcome to Our App")
  end

  def password_reset(user)
    @user = user
    @reset_url = password_reset_url(user.reset_token)
    mail(to: user.email, subject: "Password Reset Instructions")
  end
end

HTML Template:

<%# app/views/notification_mailer/welcome_email.html.erb %>
<h1>Welcome, <%= @user.name %>!</h1>
<p>Thanks for signing up. Get started by logging in:</p>
<%= link_to "Login Now", @login_url, class: "button" %>

Text Template:

<%# app/views/notification_mailer/welcome_email.text.erb %>
Welcome, <%= @user.name %>!

Thanks for signing up. Get started by logging in:
<%= @login_url %>

Usage (Async with SolidQueue):

# In controller or service
NotificationMailer.welcome_email(@user).deliver_later
NotificationMailer.password_reset(@user).deliver_later(queue: :mailers)

Why: ActionMailer integrates seamlessly with SolidQueue for async delivery. Always use deliver_later to avoid blocking requests. Provide both HTML and text versions for compatibility.

# ❌ WRONG - Blocks HTTP request thread
def create
  @user = User.create!(user_params)
  NotificationMailer.welcome_email(@user).deliver_now  # Blocks!
  redirect_to @user
end
# ✅ CORRECT - Async delivery via SolidQueue
def create
  @user = User.create!(user_params)
  NotificationMailer.welcome_email(@user).deliver_later  # Non-blocking
  redirect_to @user
end

Why bad: deliver_now blocks the HTTP request until SMTP completes, creating slow response times and poor user experience. deliver_later uses SolidQueue to send email in background.

class NotificationMailer < ApplicationMailer
  def custom_notification
    @user = params[:user]
    @message = params[:message]
    mail(to: @user.email, subject: params[:subject])
  end
end

# Usage
NotificationMailer.with(
  user: user,
  message: "Update available",
  subject: "System Alert"
).custom_notification.deliver_later

Why: Cleaner syntax, easier to read and modify, and works seamlessly with background jobs.


Email Templates

HTML Layout:

<%# app/views/layouts/mailer.html.erb %>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      body {
        font-family: Arial, sans-serif;
        max-width: 600px;
        margin: 0 auto;
        color: #333;
      }
      .header {
        background-color: #4F46E5;
        color: white;
        padding: 20px;
        text-align: center;
      }
      .content {
        padding: 20px;
      }
      .button {
        display: inline-block;
        padding: 12px 24px;
        background-color: #4F46E5;
        color: white;
        text-decoration: none;
        border-radius: 4px;
      }
      .footer {
        padding: 20px;
        text-align: center;
        font-size: 12px;
        color: #666;
      }
    </style>
  </head>
  <body>
    <div class="header">
      <h1>Your App</h1>
    </div>
    <div class="content">
      <%= yield %>
    </div>
    <div class="footer">
      <p>&copy; 2025 Your Company. All rights reserved.</p>
    </div>
  </body>
</html>

Text Layout:

<%# app/views/layouts/mailer.text.erb %>
================================================================================
YOUR APP
================================================================================

<%= yield %>

--------------------------------------------------------------------------------
© 2025 Your Company. All rights reserved.

Why: Consistent branding across all emails. Inline CSS ensures styling works across email clients.

class ReportMailer < ApplicationMailer
  def monthly_report(user, data)
    @user = user

    # Regular attachment
    attachments["report.pdf"] = {
      mime_type: "application/pdf",
      content: generate_pdf(data)
    }

    # Inline attachment (for embedding in email body)
    attachments.inline["logo.png"] = File.read(
      Rails.root.join("app/assets/images/logo.png")
    )

    mail(to: user.email, subject: "Monthly Report")
  end
end

In template:

<%# Reference inline attachment %>
<%= image_tag attachments["logo.png"].url %>

Why: Attach reports, exports, or inline images. Inline attachments can be referenced in email body with image_tag.

# ❌ WRONG - Relative path doesn't work in emails
def welcome_email(user)
  @user = user
  @login_url = login_path  # => "/login" (relative path)
  mail(to: user.email, subject: "Welcome")
end
# ✅ CORRECT - Full URL works in emails
def welcome_email(user)
  @user = user
  @login_url = login_url  # => "https://example.com/login" (absolute URL)
  mail(to: user.email, subject: "Welcome")
end

# Required configuration
# config/environments/production.rb
config.action_mailer.default_url_options = { host: "example.com", protocol: "https" }

Why bad: Emails are viewed outside your application context, so relative paths don't work. Always use *_url helpers to generate absolute URLs.


Email Testing

Configuration:

# Gemfile
group :development do
  gem "letter_opener"
end

# config/environments/development.rb
config.action_mailer.delivery_method = :letter_opener
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }

# config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  address: "smtp.sendgrid.net",
  port: 587,
  user_name: Rails.application.credentials.dig(:smtp, :username),
  password: Rails.application.credentials.dig(:smtp, :password),
  authentication: :plain,
  enable_starttls_auto: true
}
config.action_mailer.default_url_options = { host: "example.com", protocol: "https" }

Why: letter_opener opens emails in browser during development - no SMTP setup needed. Test email appearance without actually sending.

# test/mailers/previews/notification_mailer_preview.rb
class NotificationMailerPreview < ActionMailer::Preview
  # Preview at http://localhost:3000/rails/mailers/notification_mailer/welcome_email
  def welcome_email
    user = User.first || User.new(name: "Test User", email: "test@example.com")
    NotificationMailer.welcome_email(user)
  end

  def password_reset
    user = User.first || User.new(name: "Test User", email: "test@example.com")
    user.reset_token = "sample_token_123"
    NotificationMailer.password_reset(user)
  end

  # Preview with different data
  def welcome_email_long_name
    user = User.new(name: "Christopher Alexander Montgomery III", email: "long@example.com")
    NotificationMailer.welcome_email(user)
  end
end

Why: Mailer previews at /rails/mailers let you see all email variations without sending. Test different edge cases (long names, missing data, etc.).

# test/mailers/notification_mailer_test.rb
class NotificationMailerTest < ActionMailer::TestCase
  test "welcome_email sends with correct attributes" do
    user = users(:alice)
    email = NotificationMailer.welcome_email(user)

    # Test delivery
    assert_emails 1 do
      email.deliver_now
    end

    # Test attributes
    assert_equal [user.email], email.to
    assert_equal ["noreply@example.com"], email.from
    assert_equal "Welcome to Our App", email.subject

    # Test content
    assert_includes email.html_part.body.to_s, user.name
    assert_includes email.text_part.body.to_s, user.name
    assert_includes email.html_part.body.to_s, "Login Now"
  end

  test "delivers via background job" do
    user = users(:alice)

    assert_enqueued_with(job: ActionMailer::MailDeliveryJob, queue: "mailers") do
      NotificationMailer.welcome_email(user).deliver_later(queue: :mailers)
    end
  end

  test "password_reset includes reset link" do
    user = users(:alice)
    user.update!(reset_token: "test_token_123")
    email = NotificationMailer.password_reset(user)

    assert_includes email.html_part.body.to_s, "test_token_123"
    assert_includes email.html_part.body.to_s, "password_reset"
  end
end

Why: Test email delivery, content, and background job enqueuing. Verify recipients, subjects, and that emails are queued properly.


Email Configuration

Development:

# config/environments/development.rb
config.action_mailer.delivery_method = :letter_opener
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }

Test:

# config/environments/test.rb
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { host: "example.com" }

Production:

# config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = false
config.action_mailer.default_url_options = {
  host: ENV["APP_HOST"],
  protocol: "https"
}

config.action_mailer.smtp_settings = {
  address: ENV["SMTP_ADDRESS"],
  port: ENV["SMTP_PORT"],
  user_name: Rails.application.credentials.dig(:smtp, :username),
  password: Rails.application.credentials.dig(:smtp, :password),
  authentication: :plain,
  enable_starttls_auto: true
}

Why: Different configurations per environment. Development previews in browser, test stores emails in memory, production sends via SMTP.


# test/mailers/notification_mailer_test.rb
class NotificationMailerTest < ActionMailer::TestCase
  setup do
    @user = users(:alice)
  end

  test "welcome_email" do
    email = NotificationMailer.welcome_email(@user)

    assert_emails 1 { email.deliver_now }
    assert_equal [@user.email], email.to
    assert_equal ["noreply@example.com"], email.from
    assert_match @user.name, email.html_part.body.to_s
    assert_match @user.name, email.text_part.body.to_s
  end

  test "enqueues for async delivery" do
    assert_enqueued_with(job: ActionMailer::MailDeliveryJob) do
      NotificationMailer.welcome_email(@user).deliver_later
    end
  end

  test "uses correct queue" do
    assert_enqueued_with(job: ActionMailer::MailDeliveryJob, queue: "mailers") do
      NotificationMailer.welcome_email(@user).deliver_later(queue: :mailers)
    end
  end
end

# test/system/email_delivery_test.rb
class EmailDeliveryTest < ApplicationSystemTestCase
  test "sends welcome email after signup" do
    visit signup_path
    fill_in "Email", with: "new@example.com"
    fill_in "Password", with: "password"
    click_button "Sign Up"

    assert_enqueued_emails 1
    perform_enqueued_jobs

    email = ActionMailer::Base.deliveries.last
    assert_equal ["new@example.com"], email.to
    assert_match "Welcome", email.subject
  end
end

Official Documentation:

Gems & Libraries:

Tools:

Email Service Providers:

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です