mcpField
A
action-mailer

action-mailer

github.com/thinkoodle開発7190 回インストール8 週間前に更新
リポジトリ

action-mailer について

アプリのメールを作成・管理する開発者やコーディングエージェント向けの Rails Action Mailer スキルです。メーラー、テンプレート、配信設定、プレビュー、テスト、添付ファイルを扱います。

主な機能

  1. 01パラメーター化メーラーのパターン
  2. 02HTML とテキストのメールテンプレート
  3. 03キューおよび SMTP 配信設定
  4. 04プレビューと配信テスト
  5. 05添付ファイルとインライン画像
  6. 06コールバックとメールのローカライズ

活用シーン

  1. 01アカウントやパスワードのメール作成
  2. 02マルチパートメールテンプレートの構築
  3. 03環境ごとのメール配信設定
  4. 04メール内容のプレビューとテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/thinkoodle/rails-skills --skill action-mailer

インストール後、Claude Code で/action-mailerを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
configuration.md
delivery.md
interceptors.md
previews.md
templates.md
testing.md

詳細

Rails Action Mailer エキスパート

Rails アプリケーションで Action Mailer を使ってメールを作成、設定、送信します。

方針

基本原則:

  1. デフォルトで deliver_later を使用します — Active Job 経由でメールをキューに登録します。deliver_now は HTTP リクエストをブロックするため、SMTP の往復処理が完了するまでユーザーを待たせます。
  2. HTML とテキストの両方のテンプレートを作成します — HTML をブロックするメールクライアントもあり、HTML のみのメールはスパムフィルターで不利になります。必ずテキストのフォールバックを用意してください。
  3. パラメーター化されたメーラーを使用します — メソッド引数ではなく、with() 経由でコンテキストを渡します。これにより、コールバックや共通のセットアップを適切に機能させられます。
  4. default from: を設定します — すべてのメーラーにデフォルトの送信元が必要です。設定しない場合、メールの送信が通知なく失敗したり、メールサーバーに拒否されたりします。
  5. プレビューを作成します — プレビュークラスを使うと、実際にメールを送信したり、テストデータを手作業で作成したりせずに、メールのデザインを反復して調整できます。
  6. _path ではなく _url ヘルパーを使います — メールにはリクエストのコンテキストがないため、相対パスではリンクが壊れます。_url は絶対 URL を生成します。

このスキルを使用する場面

  • 新しいメーラークラスの生成
  • メールテンプレート(HTML とテキスト)の作成
  • SMTP/配信設定
  • 添付ファイルやインライン画像の追加
  • メーラーのプレビューとテストの作成
  • インターセプターやオブザーバーのセットアップ
  • メールの件名への I18n の実装
  • メール配信の問題のデバッグ

手順

Step 1: 既存のメーラーパターンを確認する

まずプロジェクトを確認し、一貫性を保つため既存のメーラーパターンに合わせます:

# Find existing mailers
ls app/mailers/

# Check ApplicationMailer defaults
cat app/mailers/application_mailer.rb

# Find existing templates
ls app/views/layouts/mailer.*
find app/views -name "*.html.erb" -path "*/mailer*" -o -name "*.text.erb" -path "*/mailer*"

# Check delivery config
grep -r "action_mailer" config/environments/

# Find existing previews
ls test/mailers/previews/

理論上のベストプラクティスより、既存のコードベースとの一貫性が重要です。

Step 2: メーラーを生成または作成する

アクション名を指定してジェネレーターを使用します:

bin/rails generate mailer User welcome_email password_reset

次のファイルが作成されます:

  • app/mailers/user_mailer.rb — メーラークラス
  • app/views/user_mailer/welcome_email.html.erb — HTML テンプレート
  • app/views/user_mailer/welcome_email.text.erb — テキストテンプレート
  • app/views/user_mailer/password_reset.html.erb
  • app/views/user_mailer/password_reset.text.erb
  • test/mailers/user_mailer_test.rb — テストファイル
  • test/mailers/previews/user_mailer_preview.rb — プレビュークラス

ApplicationMailer が存在しない場合は、作成します:

# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: "[email protected]"
  layout "mailer"
end
Step 3: メーラークラスを作成する

パラメーター化されたメーラー(with/params パターン)を使用します:

# app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
  default from: "[email protected]"

  def welcome_email
    @user = params[:user]
    @login_url = login_url
    mail(
      to: email_address_with_name(@user.email, @user.name),
      subject: "Welcome to #{app_name}"
    )
  end

  def password_reset
    @user = params[:user]
    @token = params[:token]
    @reset_url = edit_password_reset_url(token: @token)
    mail(to: @user.email, subject: "Reset your password")
  end

  private

  def app_name
    Rails.application.class.module_parent_name
  end
end

メーラーの呼び出し — deliver_later を優先します:

# Preferred — async via Active Job (user doesn't wait for SMTP)
UserMailer.with(user: @user).welcome_email.deliver_later

# With params
UserMailer.with(user: @user, token: @token).password_reset.deliver_later

# Synchronous — blocks the request while talking to SMTP server
UserMailer.with(user: @user).welcome_email.deliver_now

deliver_now を使用するのは、rake タスク/cron ジョブ、コンソールでのデバッグ、または即時の確認が必要な重要なメールに限ります。

Step 4: 両方のテンプレートを作成する

HTML とテキストの両方のバージョンを作成します。 両方が存在すると、Action Mailer は multipart/alternative メールを自動生成します。

HTML テンプレート(app/views/user_mailer/welcome_email.html.erb):

<h1>Welcome, <%= @user.name %>!</h1>

<p>Thanks for signing up. Your account is ready.</p>

<p>
  <%= link_to "Log in to your account", @login_url %>
</p>

テキストテンプレート(app/views/user_mailer/welcome_email.text.erb):

Welcome, <%= @user.name %>!

Thanks for signing up. Your account is ready.

Log in: <%= @login_url %>

両方が必要な理由 HTML をブロックするメールクライアントもあります。HTML のみのメールはスパムフィルターで不利になります。テキストのフォールバックは、メールの到達率を確保するために必要です。

Step 5: URL ホストを設定する

相対パスを解決するブラウザーリクエストのコンテキストがないため、メールには絶対 URL が必要です:

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

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

テンプレートでは _url ヘルパーを使用します:

<%# CORRECT %>
<%= link_to "View order", order_url(@order) %>

<%# WRONG — will break in email %>
<%= link_to "View order", order_path(@order) %>
Step 6: メーラーのプレビューを作成する

メーラーの各アクションにプレビューを作成します — 実際にメールを送信せずに /rails/mailers でデザインを反復して調整できます:

# test/mailers/previews/user_mailer_preview.rb
class UserMailerPreview < ActionMailer::Preview
  def welcome_email
    user = User.first || User.new(name: "Preview User", email: "[email protected]")
    UserMailer.with(user: user).welcome_email
  end

  def password_reset
    user = User.first || User.new(name: "Preview User", email: "[email protected]")
    UserMailer.with(user: user, token: "preview-token-123").password_reset
  end
end

プレビューのヒント:

  • データベースが空でもプレビューが動作するように、User.first とフォールバックの User.new(...) を使用します
  • メールオブジェクトを返すだけにし、プレビュー内で deliver_later を呼び出さないでください
  • テンプレートの変更時にはプレビューが自動的に再読み込みされます
Step 7: メーラーのテストを作成する
# test/mailers/user_mailer_test.rb
require "test_helper"

class UserMailerTest < ActionMailer::TestCase
  test "welcome_email" do
    user = users(:active_user)
    email = UserMailer.with(user: user).welcome_email

    assert_emails 1 do
      email.deliver_now
    end

    assert_equal ["[email protected]"], email.from
    assert_equal [user.email], email.to
    assert_equal "Welcome to MyApp", email.subject

    # Test HTML part
    assert_match user.name, email.html_part.body.to_s
    assert_match "Log in", email.html_part.body.to_s

    # Test text part
    assert_match user.name, email.text_part.body.to_s
  end
end

主なテストアサーション:

# Count emails sent
assert_emails 1 do
  UserMailer.with(user: user).welcome_email.deliver_now
end

# No emails sent
assert_no_emails do
  # action that shouldn't send email
end

# Enqueued for later delivery
assert_enqueued_emails 1 do
  UserMailer.with(user: user).welcome_email.deliver_later
end

# Check email content
assert_equal ["[email protected]"], email.to
assert_equal ["[email protected]"], email.from
assert_equal "Subject", email.subject
assert_match "expected text", email.body.encoded
Step 8: 配信方法を設定する

開発環境 — letter_opener または :test: を使用します

# config/environments/development.rb
config.action_mailer.delivery_method = :letter_opener # Opens in browser
# OR
config.action_mailer.delivery_method = :test # Stores in ActionMailer::Base.deliveries

本番環境 — SMTP:

# config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  address:         "smtp.example.com",
  port:            587,
  domain:          "example.com",
  user_name:       Rails.application.credentials.dig(:smtp, :user_name),
  password:        Rails.application.credentials.dig(:smtp, :password),
  authentication:  "plain",
  enable_starttls: true,
  open_timeout:    5,
  read_timeout:    5
}

テスト環境 — 必ず :test を使用します:

# config/environments/test.rb
config.action_mailer.delivery_method = :test

クイックリファレンス

mail() メソッドのオプション
オプション説明
to:受信者 — 文字列または配列
from:送信者(デフォルトを上書き)
cc:カーボンコピーの受信者
bcc:ブラインドカーボンコピーの受信者
reply_to:返信先アドレス
subject:メールの件名
headers:カスタムヘッダーのハッシュ
template_path:カスタムビューのディレクトリ
template_name:カスタムテンプレート名
delivery_method_options:メールごとの配信設定の上書き
添付ファイル
def invoice_email
  @invoice = params[:invoice]

  # Simple attachment
  attachments["invoice.pdf"] = File.read("/path/to/invoice.pdf")

  # Attachment with options
  attachments["report.csv"] = {
    mime_type: "text/csv",
    content: generate_csv_data
  }

  mail(to: @invoice.customer_email, subject: "Your Invoice")
end
インライン添付ファイル(メール本文内の画像)
# In mailer
def newsletter
  attachments.inline["logo.png"] = File.read("app/assets/images/logo.png")
  mail(to: params[:user].email, subject: "Newsletter")
end
<%# In HTML template %>
<%= image_tag attachments["logo.png"].url, alt: "Company Logo" %>
コールバック
class ApplicationMailer < ActionMailer::Base
  before_action :set_default_vars
  after_action  :log_delivery
  after_deliver :record_sent

  private

  def set_default_vars
    @company_name = "MyApp"
  end

  def log_delivery
    Rails.logger.info("Preparing email: #{action_name}")
  end

  def record_sent
    # Called after successful delivery
    EmailLog.create!(mailer: self.class.name, action: action_name)
  end
end
インターセプターとオブザーバー
# config/initializers/mail_interceptors.rb
Rails.application.configure do
  if Rails.env.staging?
    config.action_mailer.interceptors = %w[SandboxEmailInterceptor]
  end
  config.action_mailer.observers = %w[EmailDeliveryObserver]
end

# app/interceptors/sandbox_email_interceptor.rb
class SandboxEmailInterceptor
  def self.delivering_email(message)
    message.to = ["[email protected]"]
  end
end

# app/observers/email_delivery_observer.rb
class EmailDeliveryObserver
  def self.delivered_email(message)
    EmailDelivery.log(message)
  end
end
メーラーでの rescue_from
class NotifierMailer < ApplicationMailer
  rescue_from ActiveJob::DeserializationError do |exception|
    # Handle stale records gracefully
  end

  rescue_from Net::SMTPAuthenticationError do |exception|
    # Handle SMTP auth failures
  end
end
メールの件名の I18n
# config/locales/en.yml
en:
  user_mailer:
    welcome_email:
      subject: "Welcome to %{app_name}"
    password_reset:
      subject: "Reset your password"
# Mailer — omit subject: to auto-lookup from I18n
def welcome_email
  @user = params[:user]
  mail(to: @user.email) # Subject from en.user_mailer.welcome_email.subject
end
共通コンテキスト用のパラメーター化されたメーラー

複数のアクション間でコンテキストを共有するには、before_action と params を使用します。

class InvitationsMailer < ApplicationMailer
  before_action { @inviter = params[:inviter]; @invitee = params[:invitee] }

  default to:   -> { @invitee.email },
          from: -> { email_address_with_name("[email protected]", @inviter.name) }

  def account_invitation
    mail subject: "#{@inviter.name} invited you to #{params[:inviter].account.name}"
  end
end

# Call with: InvitationsMailer.with(inviter: user, invitee: other).account_invitation.deliver_later

詳細なリファレンス

より詳しいパターンや例については、references/ ディレクトリを参照してください。

  • references/templates.md — メーラークラスのパターン、HTML/テキストテンプレート、添付ファイル、I18n、レイアウト
  • references/delivery.md — SMTP 設定、環境ごとのセットアップ、エラー処理
  • references/testing.md — メーラーテストのパターン、配信アサーション、統合テスト
  • references/interceptors.md — コールバック、インターセプター、オブザーバー、配信ライフサイクル
  • references/previews.md — プレビュークラス、フォールバックデータ、カスタムプレビューパス
  • references/configuration.md — エッジケース、注意点、本番環境向けレシピ

エージェントによくある間違い

  1. deliver_later の代わりに deliver_now を使用する — SMTP の応答を待つ間、HTTP リクエストをブロックするため、ユーザーはページの読み込みが遅いと感じます
  2. HTML テンプレートだけを作成する — スパムフィルターは HTML のみのメールを低く評価し、一部のクライアントは HTML を完全にブロックします
  3. default from: アドレスを設定し忘れる — メールサーバーは送信者のないメールを拒否します。多くの場合、通知なく拒否されます
  4. テンプレートで _path ヘルパーを使用する — メールクライアントでは解決に使うリクエストコンテキストがないため、相対 URL が生成され、リンクが機能しません
  5. with() を使わずに引数を渡す — パラメーター化されたメーラー(Mailer.with(user: @user).action)を使うと、コールバックや共通セットアップをすっきり扱えます
  6. default_url_options の設定を忘れる — ホスト設定がない場合、本番環境で _url ヘルパーがエラーを発生させるか、localhost へのリンクを生成します
  7. プレビューを書かない — プレビューがないと、実際にメールを送信するか、メールの見た目を確認するためだけのテストを書くことになります
  8. 環境ごとに配信方法を設定しない — テストには :test、開発には :letter_opener、本番には :smtp を使用します

避けるべきアンチパターン

  1. 肥大化したメーラー — ビジネスロジックはモデルやサービスに置いてください。メーラーは組み立てて送信するだけにします。メーラー内のロジックはテストや再利用が困難です
  2. テンプレート内のインラインスタイル — 共通スタイルを備えたメーラーレイアウトを使い、メールクライアントとの互換性のために CSS を自動でインライン化する premailer-rails の使用を検討してください
  3. ハードコードされた URL — _url 接尾辞のルートヘルパーはルートが変わっても正しく機能しますが、ハードコードされた文字列はすぐに古くなります
  4. テキストのフォールバックがない — HTML のみのメールは配信スコアを下げ、スクリーンリーダーから利用できなくなります
  5. コントローラーでの同期配信 — リクエスト内で deliver_now を呼び出すと、SMTP の往復を待つ間ユーザーを待たせます
  6. テストされていないメーラー — 内容、受信者、件名、配信数をテストしてください
  7. メーラービュー内のシークレット — メールでトークンやパスワードを決して公開しないでください。代わりに、有効期間が短いハッシュ化リンクを使います

ファイル構成

app/
  mailers/
    application_mailer.rb          # Base class — default from, layout
    user_mailer.rb                 # Mailer class
  views/
    layouts/
      mailer.html.erb              # HTML layout (wraps all mailer HTML views)
      mailer.text.erb              # Text layout
    user_mailer/
      welcome_email.html.erb       # HTML template
      welcome_email.text.erb       # Text template
config/
  environments/
    development.rb                 # delivery_method, default_url_options
    production.rb                  # SMTP settings
    test.rb                        # delivery_method: :test
test/
  mailers/
    user_mailer_test.rb            # Mailer tests
    previews/
      user_mailer_preview.rb       # Email previews

コメント