本ガイドは、Railsアプリケーションからメールを送信する方法について解説します。
このガイドの内容:
Action Mailerを使うと、アプリケーションからメールを送信できるようになります。Action Mailerは、Railsフレームワークにおけるメール関連コンポーネントの1つであり、メール受信を処理するAction Mailboxと対になります。
Action Mailerでは、「メーラー(mailer)」と呼ばれるクラスと、メールの作成や送信設定用のビューが使われます。メーラーは、ActionMailer::Baseクラスを継承します。
メーラーの振る舞いは、以下の点がコントローラときわめて似通っています。
app/viewsディレクトリ以下に配置される)があるこのセクションでは、Action Mailerによるメール送信方法を手順を追って説明します。詳しい手順は以下の通りです。
最初に、以下の「メーラー」ジェネレータコマンドを実行して、メーラー関連のクラスを作成します。
$ bin/rails generate mailer User create app/mailers/user_mailer.rb invoke erb create app/views/user_mailer invoke test_unit create test/mailers/user_mailer_test.rb create test/mailers/previews/user_mailer_preview.rb
生成されるすべてのメーラークラスは、以下のUserMailerと同様にApplicationMailerを継承します。
# app/mailers/user_mailer.rb class UserMailer < ApplicationMailer end
上のApplicationMailerクラスはActionMailer::Baseを継承しており、すべてのメーラーに共通する属性を以下のように定義できます。
# app/mailers/application_mailer.rb class ApplicationMailer < ActionMailer::Base default from: "from@example.com" layout "mailer" end
ジェネレータを使いたくない場合は、app/mailersディレクトリ以下にファイルを手動で作成します。このクラスは、必ずActionMailer::Baseを継承するようにしてください。
# app/mailers/custom_mailer.rb class CustomMailer < ApplicationMailer end
app/mailers/user_mailer.rbに最初に作成されるUserMailerクラスには、メソッドがありません。そこで、次に特定のメールを送信するメソッド(アクション)をメーラーに追加します。
メーラーには「アクション」と呼ばれるメソッドがあり、コントローラーのアクションと同様に、ビューを用いてコンテンツを構造化します。コントローラーはクライアントに送り返すHTMLコンテンツを生成しますが、メーラーはメールで配信されるメッセージを作成します。
UserMailerクラスに以下のようにwelcome_emailというメソッドを追加して、ユーザーの登録済みメールアドレスにメールを送信しましょう。
class UserMailer < ApplicationMailer default from: "notifications@example.com" def welcome_email @user = params[:user] @url = "http://example.com/login" mail(to: @user.email, subject: "私の素敵なサイトへようこそ") end end
メーラー内のメソッド名は、末尾を_emailにする必要はありません。
上のメソッドで使われているメーラー関連のメソッドについて簡単に説明します。
default: メーラーから送信するあらゆるメールで使われるデフォルト値のハッシュです。上の例の場合、:fromヘッダーにこのクラスのすべてのメッセージで使う値を1つ設定しています。この値はメールごとに上書きすることもできます。mail: 実際のメールメッセージです。ここでは:toヘッダーと:subjectヘッダーを渡しています。また、headersメソッドは、メールのヘッダーをハッシュで渡すか、headers[:field_name] = 'value'を呼び出すことで指定できます(上のサンプルで使っていません)。
以下のように、メーラーをジェネレータで生成するときに直接アクションを指定することも可能です。
$ bin/rails generate mailer User welcome_email
上のコマンドは、空のwelcome_emailメソッドを持つUserMailerクラスを生成します。
1個のメーラークラスから複数のメールを送信することも可能です。これは、関連するメールをグループ化するのに便利です。たとえば、、UserMailerクラスにはwelcome_emailメソッドの他に、password_reset_emailメソッドも追加できます。
次に、welcome_emailアクションに対応するwelcome_email.html.erbというファイル名のビューをapp/views/user_mailer/ディレクトリの下に作成する必要があります。以下は、ウェルカムメールに使えるHTMLテンプレートのサンプルです。
<h1><%= @user.name %>様、example.comへようこそ。</h1> <p> example.comへのサインアップが成功しました。 ユーザー名は「<%= @user.login %>」です。<br> </p> <p> このサイトにログインするには、次のリンクをクリックしてください: <%= link_to 'login`, login_url %> </p> <p>本サイトにユーザー登録いただきありがとうございます。</p>
上のサンプルは<body>タグの内容です。これは、<html>タグを含むデフォルトのメーラーレイアウトに埋め込まれます。詳しくは、メーラーのレイアウトを参照してください。
また、上のメールのテキストバージョンをapp/views/user_mailer/ディレクトリのwelcome_email.text.erbファイルに保存することも可能です(拡張子がhtml.erbではなく.text.erbである点にご注意ください)。テキストバージョンも用意しておくと、HTMLレンダリングで問題が発生した場合に信頼できるフォールバックとして機能するため、HTML形式とテキスト形式の両方を送信することがベストプラクティスと見なされます。テキストメールの例を次に示します。
<%= @user.name %>様、example.comへようこそ。 =============================================== example.comへのサインアップが成功しました。ユーザー名は「<%= @user.login %>」です。 このサイトにログインするには、次のリンクをクリックしてください: <%= @url %> 本サイトにユーザー登録いただきありがとうございます。
なお、インスタンス変数(@userと@url)は、HTMLテンプレートとテキストテンプレートの両方で利用可能になります。
これで、mailメソッドを呼び出せば、Action Mailerは2種類のテンプレート(テキストおよびHTML)を探索して、multipart/alternative形式のメールを自動生成します。
メーラーのクラスとビューのセットアップが終わったら、次は、メーラーメソッドを実際に呼び出してメールのビューをレンダリングします。メーラーは、コントローラと別の方法でビューをレンダリングするものであるとみなせます。コントローラのアクションは、HTTPプロトコルで送信するためのビューをレンダリングしますが、メーラーのアクションは、メールプロトコルを経由して送信するためのビューをレンダリングします。
それでは、ユーザーの作成に成功したらUserMailerでウェルカムメールを送信するサンプルコードを見てみましょう。
最初にscaffoldでUserを作成します。
$ bin/rails generate scaffold user name email login $ bin/rails db:migrate
次に、UserControllerのcreateアクションを編集して、新しいユーザーが作成されたときにウェルカムメールを送信するようにします。これは、ユーザーが正常に保存された直後にUserMailer.with(user: @user).welcome_emailへの呼び出しを挿入する形で行います。
ここではdeliver_laterを使って、Active Jobによるメールキューにメールを登録して後で送信するようにしています。これにより、コントローラのアクションはメールの送信完了を待たずに処理を続行できます。deliver_laterメソッドは、Active Jobに支えられています。
class UsersController < ApplicationController # ... def create @user = User.new(user_params) respond_to do |format| if @user.save # 保存後にUserMailerを使ってwelcomeメールを送信 UserMailer.with(user: @user).welcome_email.deliver_later format.html { redirect_to user_url(@user), notice: "ユーザーが正常に作成されました" } format.json { render :show, status: :created, location: @user } else format.html { render :new, status: :unprocessable_entity } format.json { render json: @user.errors, status: :unprocessable_entity } end end end # ... end
withに任意のキーバリューペアを渡すことで、Mailerアクションのparamsにできます。たとえば、with(user: @user, account: @user.account)を渡すことで、Mailerアクションでparams[:user]とparams[:account]が利用可能になります。
上記のメーラー、ビュー、コントローラーをセットアップできたので、後は新しいUserを作成すれば、ウェルカムメールが送信されているかどうかをログをチェックすることで確認できます。ログファイルには、以下のように、テキストバージョンのメールとHTMLバージョンのメールが送信される様子が表示されます。
[ActiveJob] [ActionMailer::MailDeliveryJob] [ec4b3786-b9fc-4b5e-8153-9153095e1cbf] Delivered mail 6661f55087e34_1380c7eb86934d@Bhumis-MacBook-Pro.local.mail (19.9ms) [ActiveJob] [ActionMailer::MailDeliveryJob] [ec4b3786-b9fc-4b5e-8153-9153095e1cbf] Date: Thu, 06 Jun 2024 12:43:44 -0500 From: notifications@example.com To: test@gmail.com Message-ID: <6661f55087e34_1380c7eb86934d@Bhumis-MacBook-Pro.local.mail> Subject: Welcome to My Awesome Site Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="--==_mimepart_6661f55086194_1380c7eb869259"; charset=UTF-8 Content-Transfer-Encoding: 7bit ----==_mimepart_6661f55086194_1380c7eb869259 Content-Type: text/plain; ... ----==_mimepart_6661f55086194_1380c7eb869259 Content-Type: text/html; ...
Railsコンソールでメーラーを呼び出してメールを送信することも可能です。この方法は、コントローラーアクションを設定する前のテストとして有用でしょう。以下は、上記と同じwelcome_emailを送信します。
irb> user = User.first irb> UserMailer.with(user: user).welcome_email.deliver_later
メールをcronjobなどから今すぐ送信したい場合は、以下のようにdeliver_nowを呼び出すだけで済みます。
class SendWeeklySummary def run User.find_each do |user| UserMailer.with(user: user).weekly_summary.deliver_now end end end
UserMailerなどのweekly_summaryメソッドは、ActionMailer::MessageDeliveryオブジェクトを1つ返します。このオブジェクトは、そのメール自身が送信対象であることをdeliver_nowやdeliver_laterに伝えます。ActionMailer::MessageDeliveryオブジェクトは、Mail::Messageのラッパーです。内部のMail::Messageオブジェクトの表示や変更などを行いたい場合は、ActionMailer::MessageDeliveryオブジェクトのmessageメソッドにアクセスできます。
上のRailsコンソールにおけるMessageDeliveryの例を以下に示します。
irb> UserMailer.with(user: user).weekly_summary
#<ActionMailer::MailDeliveryJob:0x00007f84cb0367c0
@_halted_callback_hook_called=nil,
@_scheduled_at_time=nil,
@arguments=
["UserMailer",
"welcome_email",
"deliver_now",
{:params=>
{:user=>
#<User:0x00007f84c9327198
id: 1,
name: "Bhumi",
email: "hi@gmail.com",
login: "Bhumi",
created_at: Thu, 06 Jun 2024 17:43:44.424064000 UTC +00:00,
updated_at: Thu, 06 Jun 2024 17:43:44.424064000 UTC +00:00>},
:args=>[]}],
@exception_executions={},
@executions=0,
@job_id="07747748-59cc-4e88-812a-0d677040cd5a",
@priority=nil,
MIMEタイプmultipartは、ドキュメントを複数のコンポーネントパーツで構成して表現します。個別のコンポーネントパーツには、それぞれ独自のMIMEタイプ(text/htmlやtext/plainなど)を利用できます。multipartタイプは、複数のファイルを1つのトランザクションで送信するために使います(例: メールに複数のファイルを添付する)。
Action Mailerで添付ファイルを追加するには、以下のようにattachmentsメソッドにファイル名とコンテンツを渡します。Action Mailerは自動的にmime_typeを推測し、encodingを設定して添付ファイルを作成します。
attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
mailメソッドをトリガーすると、マルチパート形式のメールが1件送信されます。送信されるメールは、トップレベルがmultipart/mixedで最初のパートがmultipart/alternativeという正しい形式でネストしている、プレーンテキストメールまたはHTMLメールです。
添付ファイルを送信するもう1つの方法は、以下のようにファイル名、MIMEタイプとエンコードヘッダー、コンテンツを指定することです。Action Mailerは、渡された設定を利用します。
encoded_content = SpecialEncode(File.read("/path/to/filename.jpg")) attachments["filename.jpg"] = { mime_type: "application/gzip", encoding: "SpecialEncoding", content: encoded_content }
Action Mailerは添付ファイルを自動的にBase64でエンコードします。別のエンコードが必要な場合は、コンテンツをエンコードしてから、エンコードされたコンテンツとエンコードをHashとしてattachmentsメソッドに渡せます。エンコードを指定すると、Action Mailerは添付ファイルをBase64でエンコードしません。
場合によっては、添付ファイル(画像など)をメール本文内にインライン表示したいことがあります。
これを行うには、まず以下のように#inlineを呼び出して添付ファイルをインライン添付ファイルに変換します。
def welcome attachments.inline["image.jpg"] = File.read("/path/to/image.jpg") end
次に、ビューでattachmentsをハッシュとして参照して、インライン表示したい添付ファイルを指定します。以下のように、ハッシュでurlを呼び出した結果をimage_tagメソッドに渡せます。
<p>こんにちは、リクエストいただいた写真は以下です:</p> <%= image_tag attachments['image.jpg'].url %>
これはimage_tagに対する標準的な呼び出しであるため、画像ファイルを扱う場合と同様に、添付URLの後にもオプションのハッシュを渡せます。
<p>こんにちは、以下の写真です。</p> <%= image_tag attachments['image.jpg'].url, alt: 'My Photo', class: 'photos' %>
メーラービューを作成するで説明したように、同じアクションに異なるテンプレートがある場合、Action Mailerは自動的にマルチパートメールを送信します。たとえば、UserMailerがapp/views/user_mailerディレクトリにwelcome_email.text.erbとwelcome_email.html.erbを配置している場合、Action MailerはHTMLバージョンとテキストバージョンのメーラーを両方とも異なる部分として含めたマルチパートメールを自動的に送信します。
Mail gemには、text/plainおよびtext/htmlというMIMEタイプを対象とするmultipart/alternateメールを作成するためのヘルパーメソッドがあり、その他のMIMEタイプのメールについては手動で作成できます。
挿入されるパーツの順序は、ActionMailer::Base.defaultメソッド内の:parts_orderで決定されます。
マルチパートは、電子メールで添付ファイルを送信するときにも使われます。
Action Mailerは、メールで送信するコンテンツをビューファイルで指定します。デフォルトでは、メーラーのビューはapp/views/name_of_mailer_classディレクトリに配置されます。コントローラのビューの場合と同様に、ファイル名はMailerのメソッド名と一致します。
メーラーのビューは、コントローラのビューと同様に、レイアウトの内側でレンダリングされます。メーラーのレイアウトは、app/views/layoutsに配置されます。メーラーのデフォルトのレイアウトファイルは、mailer.html.erbとmailer.text.erbです。このセクションでは、メーラーのビューとレイアウトに関するさまざまな機能について説明します。
アクションに対応するデフォルトのメーラービューは、以下のようにさまざまな方法で変更できます。
mailメソッドでは、以下のようにtemplate_pathとtemplate_nameオプションが利用できます。
class UserMailer < ApplicationMailer default from: "notifications@example.com" def welcome_email @user = params[:user] @url = "http://example.com/login" mail(to: @user.email, subject: "私の素敵なサイトへようこそ", template_path: "notifications", template_name: "hello") end end
上の設定によって、mailメソッドはapp/views/notificationsディレクトリ以下にあるhelloという名前のテンプレートを探索します。template_pathにはパスの配列も指定できます。この場合探索は配列順に沿って行われます。
より柔軟な方法を使いたい場合は、ブロックを渡して特定のテンプレートをレンダリングする方法や、テンプレートファイルを使わずにインラインでテキストをレンダリングする方法も利用できます。
class UserMailer < ApplicationMailer default from: "notifications@example.com" def welcome_email @user = params[:user] @url = "http://example.com/login" mail(to: @user.email, subject: "私の素敵なサイトへようこそ") do |format| format.html { render "another_template" } format.text { render plain: "hello" } end end end
上のコードは、HTMLパートをanother_template.html.erbテンプレートでレンダリングし、テキストパートを"hello"でレンダリングしています。renderメソッドはAction Controllerで使われているものと同じなので、:plainや:inlineなどのオプションもすべて同様に利用できます。
最後に、デフォルトのapp/views/mailer_name/ディレクトリ以外の場所にあるテンプレートでレンダリングしたい場合は、以下のようにprepend_view_pathを適用します。
class UserMailer < ApplicationMailer prepend_view_path "custom/path/to/mailer/view" # "custom/path/to/mailer/view/welcome_email" テンプレートの読み出しを試みる def welcome_email # ... end end
またはappend_view_pathメソッドも利用できます。
アプリケーションのホスト情報をメーラー内で使いたい場合は、最初に:hostパラメータでアプリケーションのドメイン名を明示的に指定する必要があります。理由は、メーラーのインスタンスは、コントローラと異なり、サーバーが受信するHTTPリクエストのコンテキストと無関係であるためです。
アプリケーション全体で共通のデフォルト:hostを設定するには、config/application.rbに以下を追加します。
config.action_mailer.default_url_options = { host: "example.com" }
独自のhostを設定したら、メールビューでは、相対URLを生成する*_pathヘルパーではなく、完全なURLを生成する*_urlを使うことをオススメします。メールクライアントはWebリクエストのコンテキストを持たないため、*_pathヘルパーが完全なWebアドレスをビルドするのに必要なベースURLがありません。
<%= link_to 'ようこそ', welcome_path %>
たとえば、メールビューでは上の*_pathではなく、以下のように*_urlを使う必要があります。
<%= link_to 'ようこそ', welcome_url %>
フルパスのURLを使うことで、メール内のリンクが正常に機能するようになります。
url_forでURLを生成するテンプレートでurl_forを用いて生成したURLは、デフォルトでフルパスになります。
:hostオプションをグローバルに設定していない場合は、url_forに:hostオプションを明示的に渡す必要があります。
<%= url_for(host: 'example.com', controller: 'welcome', action: 'greeting') %>
他のURLと同様に、名前付きルーティングヘルパーについても*_pathではなく*_urlを使う必要があります。
:hostオプションをグローバルに設定するか、url_forに:hostオプションを明示的に渡すようにしてください。
<%= user_url(@user, host: 'example.com') %>
image_tagヘルパーをメールで使えるようにするには、:asset_hostパラメータを指定する必要があります。理由は、メーラーのインスタンスは、サーバーが受信するHTTPリクエストのコンテキストを持っていないためです。
:asset_hostはアプリケーション全体で同じものを使うのが普通なので、config/application.rbで以下のようにグローバルに設定できます。
config.action_mailer.asset_host = "http://example.com"
このプロトコルはリクエストから推測できないため、:asset_hostコンフィグではhttp://やhttps://などのプロトコルを指定する必要があります。
これで、以下のようにメール内で画像を表示できます。
<%= image_tag 'image.jpg' %>
アプリケーションビューでcacheメソッドを用いるときと同じように、メーラービューでもフラグメントキャッシュを利用できます。
<% cache do %> <%= @company.name %> <% end %>
この機能を使うには、アプリケーションのconfig/environments/*.rbファイルで以下の設定が必要です。
config.action_mailer.perform_caching = true
フラグメントキャッシュはマルチパートメールでもサポートされています。詳しくはRails のキャッシュ機構ガイドを参照してください。
メーラーのレイアウトも、コントローラのビューと同様の方法で設定できます。メーラーのレイアウトはapp/views/layoutsディレクトリに配置されます。以下はデフォルトのレイアウトです。
# app/views/layouts/mailer.html.erb <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style> /* Email styles need to be inline */ </style> </head> <body> <%= yield %> </body> </html>
上のレイアウトは、mailer.html.erbファイルにあります。デフォルトのレイアウト名は、先ほどメーラーを生成するセクションのlayout "mailer"行で見たように、ApplicationMailerで指定されます。コントローラーのレイアウトと同様に、メーラーのビューをレイアウト内でレンダリングするにはyieldを使います。
別のレイアウトファイルを明示的に指定したい場合は、メーラーでlayoutを呼び出します。
class UserMailer < ApplicationMailer layout "awesome" # awesome.(html|text).erbをレイアウトとして使う end
特定のメールでレイアウトを指定するには、以下のようにformatブロック内のrenderメソッド呼び出しでlayout: "layout_name"オプションを渡します。
class UserMailer < ApplicationMailer def welcome_email mail(to: params[:user].email) do |format| format.html { render layout: "my_layout" } format.text end end end
上のコードは、HTMLパートについてはmy_layout.html.erbレイアウトファイルでレンダリングし、テキストパートについては通常のuser_mailer.text.erbでレンダリングします。
:toキーにメールアドレスのリストを設定すると、1件のメールを複数の相手に送信できます。メールアドレスのリストの形式は、メールアドレスの配列でも、メールアドレスをカンマで区切った単一の文字列でも構いません。
たとえば、新規登録を管理者全員に通知するには以下のようにします。
class AdminMailer < ApplicationMailer default to: -> { Admin.pluck(:email) }, from: "notification@example.com" def new_registration(user) @user = user mail(subject: "新規ユーザーサインアップ: #{@user.email}") end end
CC(カーボンコピー)やBCC(ブラインドカーボンコピー)のメールアドレスを指定する場合にも同じ形式を使えます。それぞれ:ccキーと:bccキーを使います(使い方は:toフィールドと同じ要領です)。
メールアドレスを表示する代わりに、メールの受信者や送信者の名前をメールに表示したいことがあります。
ユーザーがメールを受信したときにメールアドレスの位置に受信者名を表示するには、以下のようにto:フィールドでemail_address_with_nameメソッドを使います。
def welcome_email @user = params[:user] mail( to: email_address_with_name(@user.email, @user.name), subject: "私の素敵なサイトへようこそ" ) end
同じ要領で、送信者名もfrom:フィールドで指定できます。
class UserMailer < ApplicationMailer default from: email_address_with_name("notification@example.com", "会社からのお知らせの例") end
名前が空白(nilまたは空文字)の場合は、メールアドレスのみを返します。
メールメソッドに件名を渡さなかった場合、Action Mailerは件名を国際化(I18n)の訳文から探索します。詳しくは、国際化ガイドを参照してください。
メール送信時にテンプレートのレンダリングをスキップしてメール本文に単なる文字列を指定したい場合は、:bodyオプションを使えます。このオプションを使う場合は、:content_typeオプションも指定も忘れないでください。:content_typeオプションが指定されていないと、デフォルトのtext/plainが適用されます。
class UserMailer < ApplicationMailer def welcome_email mail(to: params[:user].email, body: params[:email_body], content_type: "text/html", subject: "レンダリング完了") end end
SMTP認証情報(credential)などのデフォルトの配信設定をメール配信時に上書きしたい場合、メーラーのアクションでdelivery_method_optionsを使って変更できます。
class UserMailer < ApplicationMailer def welcome_email @user = params[:user] @url = user_url(@user) delivery_options = { user_name: params[:company].smtp_user, password: params[:company].smtp_password, address: params[:company].smtp_host } mail(to: @user.email, subject: "添付の利用規約を参照してください", delivery_method_options: delivery_options) end end
Action Mailerには以下のコールバックがあります。
メッセージの設定: before_action、after_action、
around_action。
配信の制御: before_deliver、after_deliver、around_deliver。
メーラーのコールバックには、コントローラやモデルのコールバックと同様、ブロックまたはシンボル(メーラークラス内のメソッド名を表す)を渡せます。コールバックをメーラーで利用する場合の例をいくつか示します。
before_actionbefore_actionコールバックは、インスタンス変数を設定したり、デフォルト値付きのメールオブジェクトを渡したり、デフォルトのヘッダや添付ファイルを挿入したりするのに利用できます。
class InvitationsMailer < ApplicationMailer before_action :set_inviter_and_invitee before_action { @account = params[:inviter].account } default to: -> { @invitee.email_address }, from: -> { common_address(@inviter) }, reply_to: -> { @inviter.email_address_with_name } def account_invitation mail subject: "#{@inviter.name} をBasecampに招待いたします (#{@account.name})" end def project_invitation @project = params[:project] @summarizer = ProjectInvitationSummarizer.new(@project.bucket) mail subject: "#{@inviter.name.familiar} をBasecampのプロジェクトに追加しました (#{@account.name})" end private def set_inviter_and_invitee @inviter = params[:inviter] @invitee = params[:invitee] end end
after_actionafter_actionコールバックもbefore_actionと同様のセットアップで利用できますが、メーラーのアクション内で設定されたインスタンス変数も利用できます。after_actionコールバックは、mail.delivery_method.settings設定を更新して配信メソッドを上書きするときにも利用できます。
class UserMailer < ApplicationMailer before_action { @business, @user = params[:business], params[:user] } after_action :set_delivery_options, :prevent_delivery_to_guests, :set_business_headers def feedback_message end def campaign_message end private def set_delivery_options # ここではメールのインスタンスや # @businessや@userインスタンス変数にアクセスできる if @business && @business.has_smtp_settings? mail.delivery_method.settings.merge!(@business.smtp_settings) end end def prevent_delivery_to_guests if @user && @user.guest? mail.perform_deliveries = false end end def set_business_headers if @business headers["X-SMTPAPI-CATEGORY"] = @business.code end end end
after_deliverafter_deliverはメッセージ配信を記録するのに利用できます。メーラーのコンテキスト全体にアクセスするオブザーバーやインターセプタのような振る舞いも可能です。
class UserMailer < ApplicationMailer after_deliver :mark_delivered before_deliver :sandbox_staging after_deliver :observe_delivery def feedback_message @feedback = params[:feedback] end private def mark_delivered params[:feedback].touch(:delivered_at) end # インターセプタの代替 def sandbox_staging message.to = ["sandbox@example.com"] if Rails.env.staging? end # コールバックは、同様のオブザーバーの例よりも多くのコンテキストを含む def observe_delivery EmailDelivery.log(message, self.class, action_name, params) end end
メールのbodyにnil以外の値が設定されている場合、メーラーのコールバックは以後の処理を中止します。
before_deliverはthrow :abortで中止できます。
Action Mailerでは、通常のビューと同様のヘルパーメソッドを利用できます。
Action Mailer固有のヘルパーメソッドは、ActionMailer::MailHelperで利用できます。
たとえば、mailerを用いてビューからメーラーインスタンスにアクセスすることも、messageでメッセージにアクセスすることも可能です。
<%= stylesheet_link_tag mailer.name.underscore %> <h1><%= message.subject %></h1>
本セクションでは、Action Mailerの設定例の一部を示すにとどめます。
さまざまな設定オプションの説明について詳しくは、別ガイド「Railsアプリケーションを設定する」内にあるAction Mailerを設定するを参照してください。これらのオプションは、production.rbなどの環境固有の設定ファイルで設定できます。
適切なconfig/environments/$RAILS_ENV.rbファイルに追加する設定の例を以下に示します。
config.action_mailer.delivery_method = :sendmail # デフォルトは以下: # config.action_mailer.sendmail_settings = { # location: '/usr/sbin/sendmail', # arguments: %w[ -i ] # } config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true config.action_mailer.default_options = { from: "no-reply@example.com" }
Gmail経由でメールを送信するには、config/environments/$環境名.rbファイルに以下の設定を追加します。
config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { address: "smtp.gmail.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 }
Googleは、安全性が低いと判断したアプリからのサインインをブロックしています。
Gmailの設定を変更することで、サインイン試行を許可できます。Gmailアカウントで2要素認証が有効になっている場合は、アプリケーションのパスワードを設定し、通常のパスワードの代わりにそれを使う必要があります。
メーラーのテスト方法について詳しくは、テスティングガイドのメーラーをテストするを参照してください。
Action Mailerのプレビュー機能は、レンダリング用のURLを開くことでメールの外観を確認する方法を提供します。
上述のUserMailerクラスでプレビューをセットアップするには、UserMailerPreviewという名前のクラスを作成してtest/mailers/previews/ディレクトリに配置します。UserMailerのwelcome_emailのプレビューを表示するには、UserMailerPreviewで同じ名前のメソッドを実装してから、UserMailer.welcome_emailを呼び出します。
class UserMailerPreview < ActionMailer::Preview def welcome_email UserMailer.with(user: User.first).welcome_email end end
これで、http://localhost:3000/rails/mailers/user_mailer/welcome_emailにアクセスしてプレビューを表示できます。
app/views/user_mailer/welcome_email.html.erbメーラービューやメーラー自身に何らかの変更を加えると、自動的に再読み込みしてレンダリングされるので、スタイル変更を画面ですぐ確認できます。利用可能なプレビューのリストはhttp://localhost:3000/rails/mailersで表示できます。
これらのプレビュー用クラスは、デフォルトでtest/mailers/previewsに配置されます。このパスはpreview_pathsオプションで設定できます。たとえばlib/mailer_previewsに変更したい場合はconfig/application.rbに以下の設定を追加します。
config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
rescueするメーラーメソッド内のrescueブロックは、レンダリングの外で発生したエラーをキャッチできません。たとえば、バックグラウンドジョブ内でのレコードのデシリアライズエラーや、サードパーティのメール配信サービスからのエラーはキャッチできません。
メール送信処理中に発生するエラーをキャッチするには、以下のようにrescue_fromを使います。
class NotifierMailer < ApplicationMailer rescue_from ActiveJob::DeserializationError do # ... end rescue_from "SomeThirdPartyService::ApiError" do # ... end def notify(recipient) mail(to: recipient, subject: "Notification") end end
Action Mailerは、メールのオブザーバーやインターセプターのメソッドへのフックを提供します。これを用いて、送信されるすべてのメールのメール配信のライフサイクル中に呼び出されるクラスを登録できます。
インターセプタを使うと、メールを配信エージェントに渡す前にメールを加工できます。インターセプタクラスは以下のように、メールが送信される前に呼び出される::delivering_email(message)メソッドを実装しなければなりません。
class SandboxEmailInterceptor def self.delivering_email(message) message.to = ["sandbox@example.com"] end end
interceptors設定オプションを用いてインターセプタを登録しておく必要があります。これを行うには、config/initializers/mail_interceptors.rbなどのイニシャライズファイルを以下のような内容で作成します。
Rails.application.configure do if Rails.env.staging? config.action_mailer.interceptors = %w[SandboxEmailInterceptor] end end
上の例では"staging"というカスタマイズした環境を使っています。これはproduction環境に準じた状態でテストを行うための環境です。Railsのカスタム環境についてはRails環境を作成するを参照してください。
オブザーバーを使うと、メールが送信された後でメールのメッセージにアクセスできるようになります。オブザーバークラスは以下のように、メール送信後に呼び出される:delivered_email(message)メソッドを実装しなければなりません。
class EmailDeliveryObserver def self.delivered_email(message) EmailDelivery.log(message) end end
インターセプタのときと同様、observers設定オプションを用いてオブザーバーを登録しておかなければなりません。これを行うには、config/initializers/mail_observers.rbなどのイニシャライズファイルを以下のような内容で作成します。
Rails.application.configure do config.action_mailer.observers = %w[EmailDeliveryObserver] end
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。