本ガイドでは、アプリケーションでメールを受信するために必要なすべての情報を提供します。
このガイドの内容:
Action Mailboxは、受信したメールをコントローラに似たメールボックスにルーティングし、Railsで処理できるようにします。Action Mailboxは、Mailgun、Mandrill、Postmark、SendGridへの入り口(ingress)を備えています。受信メールを組み込みのEximやPostfixやQmail用のingressで直接扱うこともできます。
受信メールはActive Recordを用いてInboundEmail
レコードになり、Active Storageによってライフサイクルトラッキングや元のメールのクラウドストレージ保存を行い、データの扱いを「on-by-default incineration(焼却)」で扱います。
受信メールはActive Jobによって非同期的に1つまたは複数の専用メールボックスにルーティングされ、ドメインモデルの他の部分と直接やりとりできます。
InboundEmail
で必要なマイグレーションをインストールし、Active Storageがセットアップ済みであることを確認します。
$ rails action_mailbox:install $ rails db:migrate
SMTPリレーからのメールを受け取るようAction Mailboxに指示します。
# config/environments/production.rb config.action_mailbox.ingress = :relay
Action Mailboxがrelay ingressへのリクエストを認証するのに使える強力なパスワードを生成します。
action_mailbox.ingress_password
の下にあるアプリケーションの暗号化済みcredential(Action Mailboxはこのcredentialを自動的に見つけます)にrails credentials:edit
でパスワードを追加します。
action_mailbox: ingress_password: ...
または、RAILS_INBOUND_EMAIL_PASSWORD
環境変数でパスワードを指定します。
Eximが受信メールをbin/rails action_mailbox:ingress:exim
にパイプでつなぐよう設定し、relay ingressのURL
と先ほど生成したINGRESS_PASSWORD
を指定します。アプリケーションがhttps://example.com
にある場合の完全なコマンドは以下のような感じになります。
bin/rails action_mailbox:ingress:exim URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...
Action Mailboxに自分のMailgun API keyを渡して、Mailgunのingressへのリクエストを認証できるようにします。
action_mailbox.mailgun_api_key
の下にあるアプリケーションの暗号化済みcredential(Action Mailboxはこのcredentialを自動的に見つけます)にrails credentials:edit
でAPIキーを追加します。
action_mailbox: mailgun_api_key: ...
または、MAILGUN_INGRESS_API_KEY
環境変数でパスワードを指定します。
Mailgunからのメールを受け取るようAction Mailboxに指示します。
# config/environments/production.rb config.action_mailbox.ingress = :mailgun
受信メールを/rails/action_mailbox/mailgun/inbound_emails/mime
に転送するようMailgunを設定します。アプリケーションがhttps://example.com
にある場合、完全修飾済みURLをhttps://example.com/rails/action_mailbox/mailgun/inbound_emails/mime
のように指定します。
Action Mailboxに自分のMandrill API keyを渡して、Mandrillのingressへのリクエストを認証できるようにします。
action_mailbox.mandrill_api_key
の下にあるアプリケーションの暗号化済みcredential(Action Mailboxはこのcredentialを自動的に見つけます)にrails credentials:edit
でAPIキーを追加します。
action_mailbox: mandrill_api_key: ...
または、MANDRILL_INGRESS_API_KEY
環境変数でパスワードを指定します。
Mandrillからのメールを受け取るようAction Mailboxに指示します。
# config/environments/production.rb config.action_mailbox.ingress = :mandrill
受信メールを/rails/action_mailbox/mandrill/inbound_emails
にルーティングするようMandrillを設定します。アプリケーションがhttps://example.com
にある場合、完全修飾済みURLをhttps://example.com/rails/action_mailbox/mandrill/inbound_emails
のように指定します。
SMTPリレーからのメールを受け取るようAction Mailboxに指示します。
# config/environments/production.rb config.action_mailbox.ingress = :relay
Action Mailboxがrelay ingressへのリクエストを認証するのに使える強力なパスワードを生成します。
action_mailbox.ingress_password
の下にあるアプリケーションの暗号化済みcredential(Action Mailboxはこのcredentialを自動的に見つけます)にrails credentials:edit
でAPIキーを追加します。
action_mailbox: ingress_password: ...
または、RAILS_INBOUND_EMAIL_PASSWORD
環境変数でパスワードを指定します。
受信メールをbin/rails action_mailbox:ingress:postfix
にルーティングするようPostfixを設定します。アプリケーションがhttps://example.com
にある場合、完全なコマンドは次のような感じになります。
$ bin/rails action_mailbox:ingress:postfix URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...
Postmarkからのメールを受け取るようAction Mailboxに指示します。
# config/environments/production.rb config.action_mailbox.ingress = :postmark
Action MailboxがPostmarkのingressへのリクエストを認証するのに使える強力なパスワードを生成します。
action_mailbox.ingress_password
の下にあるアプリケーションの暗号化済みcredential(Action Mailboxはこのcredentialを自動的に見つけます)にrails credentials:edit
でAPIキーを追加します。
action_mailbox: ingress_password: ...
または、RAILS_INBOUND_EMAIL_PASSWORD
環境変数でパスワードを指定します。
受信メールを/rails/action_mailbox/postmark/inbound_emails
に転送するようPostmarkのinbound webhookを設定します。アプリケーションがhttps://example.com
にある場合、完全なコマンドは次のような感じになります。
https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/postmark/inbound_emails
Postmarkのinbound webhookを設定するときには、必ず"Include raw email content in JSON payload"というチェックボックスをオンにしてください。Action Mailboxがrawメールを処理するのに必要です。
SMTPリレーからのメールを受け取るようAction Mailboxに指示します。
# config/environments/production.rb config.action_mailbox.ingress = :relay
Action Mailboxがrelay ingressへのリクエストを認証するのに使える強力なパスワードを生成します。
action_mailbox.ingress_password
の下にあるアプリケーションの暗号化済みcredential(Action Mailboxはこのcredentialを自動的に見つけます)にrails credentials:edit
でAPIキーを追加します。
action_mailbox: ingress_password: ...
または、RAILS_INBOUND_EMAIL_PASSWORD
環境変数でパスワードを指定します。
受信メールをbin/rails action_mailbox:ingress:qmail
にパイプでつなぐようQmailを設定し、relay ingressのURL
と先ほど生成したINGRESS_PASSWORD
を指定します。アプリケーションがhttps://example.com
にある場合の完全なコマンドは以下のような感じになります。
bin/rails action_mailbox:ingress:qmail URL=https://example.com/rails/action_mailbox/relay/inbound_emails INGRESS_PASSWORD=...
SendGridからのメールを受け取るようAction Mailboxに指示します。
# config/environments/production.rb config.action_mailbox.ingress = :sendgrid
Action MailboxがSendGridのingressへのリクエストを認証するのに使える強力なパスワードを生成します。
action_mailbox.ingress_password
の下にあるアプリケーションの暗号化済みcredential(Action Mailboxはこのcredentialを自動的に見つけます)にrails credentials:edit
でAPIキーを追加します。
action_mailbox: ingress_password: ...
または、RAILS_INBOUND_EMAIL_PASSWORD
環境変数でパスワードを指定します。
受信メールを/rails/action_mailbox/sendgrid/inbound_emails
に転送するようSendGridのInbound Parseを設定します。アプリケーションがhttps://example.com
にある場合、SendGridの設定に使うURLは次のような感じになります。
https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/sendgrid/inbound_emails
SendGridのInbound Parse webhookを設定するときには、必ず“Post the raw, full MIME message”というチェックボックスをオンにしてください。Action Mailboxがraw MIMEメッセージを処理するのに必要です。
基本的なルーティングを設定します。
# app/mailboxes/application_mailbox.rb class ApplicationMailbox < ActionMailbox::Base routing /^save@/i => :forwards routing /@replies\./i => :replies end
続いてメールボックスを設定します。
# 新しいメールボックスを生成する $ bin/rails generate mailbox forwards
# app/mailboxes/forwards_mailbox.rb class ForwardsMailbox < ApplicationMailbox # 処理に必要な条件をコールバックで指定する before_processing :require_forward def process if forwarder.buckets.one? record_forward else stage_forward_and_request_more_details end end private def require_forward unless message.forward? # Action Mailersを用いて受信メールを送信者に送り返す(bounce back) # ここで処理が停止する bounce_with Forwards::BounceMailer.missing_forward( inbound_email, forwarder: forwarder ) end end def forwarder @forwarder ||= Person.where(email_address: mail.from) end def record_forward forwarder.buckets.first.record \ Forward.new forwarder: forwarder, subject: message.subject, content: mail.content end def stage_forward_and_request_more_details Forwards::RoutingMailer.choose_project(mail).deliver_now end end
デフォルトでは、処理が成功したInboundEmailは30日が経過すると焼却(incinerate)されます。これにより、アカウントをキャンセルまたはコンテンツを削除したユーザーのデータをぐずぐず保持せずに済みます。設計の意図は、メールを処理した後に必要なメールをすべて切り出してアプリケーションの業務ドメインモデルやコンテンツに取り込んでおくべきであるということです。InboundEmailは単に、デバッグや法医学的なオプションを提供する目的でシステムに余分な期間残されます。
実際のincinerationは、config.action_mailbox.incinerate_after
でスケジュールされた時刻の後、IncinerationJob
で行われます。この値はデフォルトで30.days
に設定されますが、production.rbで設定を変更できます(incinerationを遠い未来にスケジューリングする場合、その間ジョブキューがジョブを保持できることが重要です)。
実際にメールを送受信せずに、development環境でメールの受信をテストできると便利です。このために、/rails/conductor/action_mailbox/inbound_emails
に「コンダクター(conductor)」コントローラがマウントされます。これはシステム内にあるすべてのInboundEmailsのインデックスや処理の状態を提供し、新しいInboundEmailを作成できるフォームも提供します。
例:
class ForwardsMailboxTest < ActionMailbox::TestCase test "directly recording a client forward for a forwarder and forwardee corresponding to one project" do assert_difference -> { people(:david).buckets.first.recordings.count } do receive_inbound_email_from_mail \ to: 'save@example.com', from: people(:david).email_address, subject: "Fwd: ステータスは更新された?", body: <<~BODY --- Begin forwarded message --- From: Frank Holland <frank@microsoft.com> 現在のステータスは? BODY end recording = people(:david).buckets.first.recordings.last assert_equal people(:david), recording.creator assert_equal "ステータスは更新された?", recording.forward.subject assert_match "現在のステータスは?", recording.forward.content.to_s end end
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。