Action Mailer の基礎

本章では、アプリケーションでメールの送受信を行うために必要なすべての事項と、Action Mailerのさまざまな内部情報を提供します。また、メーラーのテスト方法についても説明します。

このガイドの内容:

  • Railsアプリケーションでメールを送信する方法
  • Action Mailerクラスとメーラービューの生成および編集方法
  • 環境に合わせてAction Mailerを設定する方法
  • Action Mailerクラスのテスト方法

1 はじめに

Action Mailerを使うと、アプリケーションのメーラークラスやビューでメールを送信できます。メーラーの動作はコントローラときわめて似通っています。メーラーはActionMailer::Baseを継承し、app/mailersに配置され、app/viewsにあるビューと結び付けられます。

メーラーには以下が含まれます。

  • アクション、および関連付けられたビュー(app/viewsに現れる)
  • インスタンス変数(ビューでアクセス可能)
  • レイアウトやパーシャルを利用可能にする機能
  • paramsハッシュにアクセス可能にする機能

2 メールを送信する

このセクションでは、メーラーとビューの作成方法を手順を追って説明します。

2.1 メーラー生成の全手順

2.1.1 メーラーを作成する
$ bin/rails generate mailer User
create  app/mailers/user_mailer.rb
create  app/mailers/application_mailer.rb
invoke  erb
create    app/views/user_mailer
create    app/views/layouts/mailer.text.erb
create    app/views/layouts/mailer.html.erb
invoke  test_unit
create    test/mailers/user_mailer_test.rb
create    test/mailers/previews/user_mailer_preview.rb

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

上に示したとおり、Railsの他のジェネレータ同様の方法でメーラーを生成できます。

ジェネレータを使いたくない場合は、app/mailersディレクトリ以下にファイルを作成し、ActionMailer::Baseを継承してください。

class MyMailer < ActionMailer::Base
end
2.1.2 メーラーを編集する

メーラーはRailsのコントローラと非常に似通っています。メーラーには「アクション」と呼ばれるメソッドがあり、ビューを使ってメールのコンテンツを構成します。コントローラでHTMLなどのメールコンテンツを生成して顧客に送信したい場合、その箇所でメーラーを使って、送信したいメッセージを作成します。

app/mailers/user_mailer.rbには空のメーラーがあります。

class UserMailer < ApplicationMailer
end

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

上のメソッドで使われている項目について簡単に説明します。利用可能なすべてのオプションについては、「Action Mailerの全メソッド」セクションでユーザー設定可能な属性を参照してください。

  • default: メーラーから送信するあらゆるメールで使われるデフォルト値のハッシュです。上の例の場合、:fromヘッダーにこのクラスのすべてのメッセージで使う値を1つ設定しています。この値はメールごとに上書きすることもできます。
  • mail: 実際のメールメッセージです。ここでは:toヘッダーと:subjectヘッダーを渡しています。

コントローラの場合と同様、メーラーのメソッド内で定義されたすべてのインスタンス変数はそのままビューで使えます。

2.1.3 メーラービューを作成する

app/views/user_mailer/ディレクトリでwelcome_email.html.erbというファイルを1つ作成してください。このファイルを、HTMLでフォーマットされたメールテンプレートにします。

<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <h1><%= @user.name %>様、example.comへようこそ。</h1>
    <p>
      example.comへのサインアップが成功しました。
      ユーザー名は「<%= @user.login %>」です。<br>
    </p>
    <p>
      このサイトにログインするには、<%= @url %>をクリックしてください。
    </p>
    <p>本サイトにユーザー登録いただきありがとうございます。</p>
  </body>
</html>

続いて、同じ内容のテキストメールも作成しましょう。顧客によってはHTMLフォーマットのメールを受け取りたくない人もいるので、テキストメールも作成しておくとベストです。これを行なうには、app/views/user_mailer/ディレクトリでwelcome_email.text.erbというファイルを以下の内容で作成してください。

<%= @user.name %>様、example.comへようこそ。
===============================================

example.comへのサインアップが成功しました。ユーザー名は「<%= @user.login %>」です。

このサイトにログインするには、<%= @url %>をクリックしてください。

本サイトにユーザー登録いただきありがとうございます。

現在のAction Mailerでは、mailメソッドを呼び出すと2種類のテンプレート (テキストおよびHTML) があるかどうかを探し、multipart/alternative形式のメールを自動生成します。

2.1.4 メーラーを呼び出す

Railsのメーラーは、ビューのレンダリングと本質的に同じことを行っています。ビューのレンダリングではHTTPプロトコルとして送信されますが、メーラーではメールのプロトコルを経由して送信する点のみが異なります。従って、コントローラでユーザー作成に成功したときに、ビューのレンダリングと同じ要領でメーラーにメール送信を指示できます。

メーラー呼び出しは非常に簡単です。

例として、最初にscaffoldでUserを作成してみましょう。

$ bin/rails generate scaffold user name email login
$ bin/rails db:migrate

説明用のユーザーモデルを作成したので、続いてapp/controllers/users_controller.rbを編集し、新規ユーザーの保存成功直後にUserMailerUserMailer.with(user: @user)を用いてそのユーザーにメールが送信されるようにしましょう。

deliver_laterを使うと、Active Jobによるメールキューにメールを登録できます。これにより、コントローラは送信完了を待たずに処理を続行できます。

class UsersController < ApplicationController
  # ...

  # POST /users(または/users.json)
  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, notice: 'ユーザーが正常に作成されました') }
        format.json { render json: @user, status: :created, location: @user }
      else
        format.html { render action: 'new' }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # ...
end

Active Jobはデフォルトでジョブを:asyncアダプタで実行するので、この時点でメールをdeliver_laterで送信できます。 Active Jobのデフォルトのアダプタでは、インプロセスのスレッドプールが送信に用いられます。これは外部のインフラを一切必要としないので、development/test環境に適していますが、ペンディング中のジョブが再起動時に削除されるため、productionには不向きです。永続的なバックエンドが必要な場合は、永続的なバックエンドを用いるActive Jobアダプタ(SidekiqやResqueなど)を使う必要があります。

メールをcronjobなどから今すぐ送信したい場合は、deliver_nowを呼び出すだけで済みます。

class SendWeeklySummary
  def run
    User.find_each do |user|
      UserMailer.with(user: user).weekly_summary.deliver_now
    end
  end
end

withに渡されるキーの値は、メーラーアクションでは単なるparamsになります。つまり、with(user: @user, account: @user.account)と書けば、メーラーアクションでparams[:user]params[:account]を使えるようになります。ちょうどコントローラのparamsと同じ要領です。

このweekly_summaryメソッドはActionMailer::MessageDeliveryオブジェクトを1つ返します。このオブジェクトは、そのメール自身が送信対象であることをdeliver_nowdeliver_laterに伝えます。ActionMailer::MessageDeliveryオブジェクトは、Mail::Messageをラップしています。内部のMail::Messageオブジェクトの表示や変更などを行いたい場合は、ActionMailer::MessageDeliveryオブジェクトのmessageメソッドにアクセスします。

2.2 ヘッダーの値を自動エンコードする

Action Mailerは、メールのヘッダーや本文のマルチバイト文字を自動的にエンコードします。

別の文字セットを定義したい場合や、事前に手動で別のエンコードを行っておきたい場合などの複雑な事例については、Mailライブラリを参照してください。

2.3 Action Mailerの全メソッド

以下の3つのメソッドを使えば、ほとんどのメール送信をカバーできます。

  • headers: メールに追加したいヘッダーを指定します。メールヘッダーのフィールド名と値のペアをハッシュにまとめて渡すことも、headers[:field_name] = 'value'のように呼び出すことも可能です。
  • attachments: メールにファイルを添付します。attachments['file-name.jpg'] = File.read('file-name.jpg')のように記述します。
  • mail: 実際のメール自身を送信します。このメソッドにはヘッダーのハッシュをパラメータとして渡せます。メソッドを呼び出すと、定義しておいたメールテンプレートに応じて、プレーンテキストメールまたはマルチパートメールを送信します。
2.3.1 ファイルを添付する

Action Mailerではファイルを簡単に添付できます。

  • ファイル名とコンテンツを渡すと、Action MailerとMail gemが自動的にmime_typeを推測し、encodingを設定してファイルを添付します。

    attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
    

    mailメソッドをトリガーすると、マルチパート形式のメールが1つ送信されます。送信されるメールは、トップレベルがmultipart/mixedで最初のパートがmultipart/alternativeという正しい形式でネストしている、プレーンテキストメールまたはHTMLメールです。

メールに添付されるファイルは自動的にBase64でエンコードされます。他のエンコードを使いたい場合は、事前に好みのエンコードを適用したコンテンツをHashでエンコードしてからattachmentsに渡します。

  • ヘッダーとコンテンツを指定してファイル名を渡すと、それらの設定がAction MailerとMailによって使われます。

    encoded_content = SpecialEncode(File.read('/path/to/filename.jpg'))
    attachments['filename.jpg'] = {
      mime_type: 'application/gzip',
      encoding: 'SpecialEncoding',
      content: encoded_content
    }
    

エンコーディングの種類を指定すると、Mailはコンテンツが既にエンコード済みであると判断し、Base64によるエンコードを行いません。

2.3.2 ファイルをインラインで添付する

Action Mailer 3.0はファイルをインライン添付できます。この機能は3.0より前に行われた多数のハックを基に、理想に近づけるべくシンプルな実装にしたものです。

  • インライン添付を利用することをMailに指示するには、Mailer内のattachmentsメソッドに対して#inlineを呼び出すだけで済みます。

    def welcome
      attachments.inline['image.jpg'] = File.read('/path/to/image.jpg')
    end
    
  • これで、ビューでattachmentsをハッシュとして参照するだけで、表示したい添付ファイルを指定できます。これを行なうには、attachmentsに対してurlを呼び出し、その結果をimage_tagメソッドに渡します。

    <p>Hello there, this is our image</p>
    
    <%= image_tag attachments['image.jpg'].url %>
    
  • これはimage_tagに対する標準的な呼び出しであるため、画像ファイルを扱う場合と同様に、添付URLの後にもオプションのハッシュを渡せます。

    <p>こんにちは、以下の写真です。</p>
    
    <%= image_tag attachments['image.jpg'].url, alt: 'My Photo', class: 'photos' %>
    
2.3.3 メールを複数の相手に送信する

1つのメールを複数の相手に送信することももちろん可能です(サインアップが新規に行われたことを全管理者に通知するなど)。これを行なうには、メールのリストを:toキーに設定します。メールのリストの形式は、メールアドレスの配列でも、メールアドレスをカンマで区切った文字列でも構いません。

class AdminMailer < ApplicationMailer
  default to: -> { Admin.pluck(:email) },
          from: 'notification@example.com'

  def new_registration(user)
    @user = user
    mail(subject: "New User Signup: #{@user.email}")
  end
end

CC (カーボンコピー) やBCC (ブラインドカーボンコピー) アドレスを指定する場合にも同じ形式を使えます。それぞれ:ccキーと:bccキーを使います。

2.3.4 メールアドレスを名前で表示する

受信者のメールアドレスをメールにそのまま表示するのではなく、受信者の名前で表示したいことがあります。これは以下のようにemail_address_with_nameメソッドで行なえます。

def welcome_email
  @user = params[:user]
  mail(
    to: email_address_with_name(@user.email, @user.name),
    subject: '私の素敵なサイトへようこそ'
  )
end

同じ要領で、送信者名も指定できます。

class UserMailer < ApplicationMailer
  default from: email_address_with_name('notification@example.com', '会社からのお知らせの例')
end

名前が空文字列の場合は、メールアドレスのみを返します。

2.4 メーラーのビュー

メーラーのビューはapp/views/name_of_mailer_classディレクトリに置かれます。個別のメーラービューは、その名前がメーラーメソッドと同じになるので、クラスから認識できます。先の例の場合、welcome_emailメソッドで使うメーラービューは、HTML版ではapp/views/user_mailer/welcome_email.html.erbが使われ、プレーンテキストではwelcome_email.text.erbが使われます。

アクションで使うデフォルトのメーラービューを変更するには、たとえば以下のようにします。

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: 'another')
  end
end

上のコードは、app/views/notificationsディレクトリ以下にあるanotherという名前のテンプレートを探索します。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: 'Render text' }
    end
  end
end

上のコードは、HTMLの部分を'another_template.html.erb'テンプレートでレンダリングし、テキスト部分をプレーンテキストでレンダリングしています。レンダリングのコマンドはAction Controllerで使われているものと同じなので、:text: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メソッドの利用を検討してもよいでしょう。

2.4.1 メーラービューをキャッシュする

cacheメソッドを用いるアプリケーションビューと同じように、メーラービューでもフラグメントキャッシュを利用できます。

<% cache do %>
  <%= @company.name %>
<% end %>

この機能を使うには、アプリケーションで以下の設定が必要です。

config.action_mailer.perform_caching = true

フラグメントキャッシュはメールがマルチパートの場合にもサポートされています。詳しくはRails のキャッシュ機構ガイドを参照してください。

2.5 Action Mailerのレイアウト

メーラーのレイアウトも、コントローラのビューと同様の方法で設定できます。メーラーで使うレイアウト名はメーラーと同じ名前にする必要があります。たとえば、user_mailer.html.erbuser_mailer.text.erbというレイアウトは自動的にメーラーでレイアウトとして認識されます。

別のレイアウトファイルを明示的に指定したい場合は、メーラーでlayoutを呼び出します。

class UserMailer < ApplicationMailer
  layout 'awesome' # awesome.(html|text).erbをレイアウトとして使う
end

レイアウト内のビューは、コントローラのビューと同様にyieldでレンダリングできます。

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があればそれを使ってレンダリングします。

2.6 メールのプレビュー

Action Mailerのプレビュー機能は、レンダリング用のURLを開くことでメールの外観を確認する方法を提供します。上の例のUserMailerクラスは、プレビューではUserMailerPreviewという名前にしてtest/mailers/previews/user_mailer_preview.rbに配置すべきです。welcome_emailのプレビューを表示するには、同じ名前のメソッドを実装して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"

2.7 Action MailerのビューでURLを生成する

メーラーのインスタンスは、サーバーが受信するHTTPリクエストのコンテキストと無関係である点がコントローラと異なります。アプリケーションのホスト情報をメーラー内で使いたい場合は:hostパラメータを明示的に指定します。

通常、:hostに指定する値はそのアプリケーション内で共通なので、config/application.rbに以下の記述を追加してグローバルに利用できるようにします。

config.action_mailer.default_url_options = { host: 'example.com' }

*_pathヘルパーは、この動作の性質上メール内では一切利用できない点にご注意ください。メールでURLが必要な場合は、*_urlヘルパーをお使いください。

<%= link_to 'ようこそ', welcome_path %>

上のコードの代わりに、以下のコードを使う必要があります。

<%= link_to 'ようこそ', welcome_url %>

これでフルパスのURLが引用され、メールのURLが正常に機能するようになります。

2.7.1 url_forでURLを生成する

テンプレートでurl_forを用いて生成されるURLは、デフォルトでフルパスになります。

:hostオプションをグローバルに設定していない場合は、url_for:hostオプションを明示的に渡す必要があることにご注意ください。

<%= url_for(host: 'example.com',
            controller: 'welcome',
            action: 'greeting') %>
2.7.2 名前付きルーティングでURLを生成する

メールクライアントはWebサーバーのコンテキストから切り離されているので、メールに記載するパスではWebのアドレスのベースURLは補完されません。従って、名前付きルーティングヘルパーについても*_pathではなく常に*_urlを使う必要があります。

:hostオプションをグローバルに設定していない場合は、「*_url」ヘルパーに:hostオプションを明示的に渡す必要があることにご注意ください。

<%= user_url(@user, host: 'example.com') %>

GET以外のリンクが機能するにはrails-ujsまたはjQuery UJSが必須ですが、これらはメーラーテンプレートでは機能しません(通常のGETリクエストが出力されます)。

2.8 Action Mailerのビューに画像を追加する

コントローラの場合と異なり、メーラーのインスタンスには受け取ったリクエストのコンテキストが一切含まれません。このため、:asset_hostパラメータを自分で指定する必要があります。

:asset_hostが多くの場合アプリケーション全体で一貫しているのと同様、config/application.rbでグローバルな設定を行えます。

config.action_mailer.asset_host = 'http://example.com'

このプロトコルはリクエストから推測できないため、:asset_hostコンフィグではhttp://https://などのプロトコルを指定する必要があります。

これで、以下のようにメール内で画像を表示できます。

<%= image_tag 'image.jpg' %>

2.9 マルチパートメールを送信する

あるアクションに複数の異なるテンプレートがあると、Action Mailerによって自動的にマルチパート形式のメールが送信されます。UserMailerを例にとって説明します。app/views/user_mailerディレクトリにwelcome_email.text.erbwelcome_email.html.erbというテンプレートがあると、Action MailerはそれぞれのテンプレートからHTMLメールとテキストメールを生成し、マルチパート形式のメールとして1つにまとめて自動的に送信します。

マルチパートメールに挿入されるパートの順序は、ActionMailer::Base.defaultメソッドの:parts_orderによって決まります。

2.10 メール送信時に配信オプションを動的に変更する

SMTP認証情報などのデフォルトの配信オプションをメール配信時に上書きしたい場合、メーラーのアクションで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

2.11 テンプレートをレンダリングせずにメール送信する

メール送信時にテンプレートのレンダリングをスキップしてメール本文を単なる文字列にしたい場合は、:bodyオプションを使えます。このオプションを使う場合は、必ず: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

3 Action Mailerのコールバック

Action Mailerには以下のコールバックがあります。

メッセージの設定: before_actionafter_actionaround_action

配信の制御: before_deliverafter_deliveraround_deliver

  • コントローラと同様、メーラークラスのメソッドにもフィルタ付きのブロックまたはシンボルを渡せます。

  • before_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} invited you to their 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_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_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_deliverthrow :abortで中止できます。

4 Action Mailerヘルパーを使う

Action MailerはAbstractControllerを継承しているので、Action Controllerと同様に一般的なヘルパーメソッドを使えます。

Action Mailer固有のヘルパーメソッドはActionMailer::MailHelperで利用できます。たとえば、mailerを用いてビューからメーラーインスタンスにアクセスすることも、messageでメッセージにアクセスすることも可能です。

<%= stylesheet_link_tag mailer.name.underscore %>
<h1><%= message.subject %></h1>

5 Action Mailerを設定する

以下の設定オプションは、environment.rbやproduction.rbなどの環境設定ファイルのいずれかで利用するのが最適です。

設定オプションの完全な説明については「Rails アプリケーションを設定する」ガイドのAction Mailerを設定するを参照してください。

5.1 logger

可能であればメール送受信に関する情報を生成します。nilを指定するとログ出力を行わなくなります。Ruby自身のLoggerロガーおよびLog4rロガーのどちらとも互換性があります。

5.2 smtp_settings

:smtpの配信メソッドの詳細設定を行います。

  • :address: リモートメールサーバーを利用可能にします。デフォルトは"localhost"で、必要に応じて変更します。

  • :port: メールサーバーが万一ポート25番で動作していない場合はここで変更できます。

  • :domain: HELOドメインを指定する必要がある場合はここで設定できます。

  • :user_name: メールサーバーで認証が必要な場合はここでユーザー名を指定します。

  • :password: メールサーバーで認証が必要な場合はここでパスワードを指定します。

  • :authentication: メールサーバーで認証が必要な場合はここで認証の種類を指定します。以下のいずれかのシンボルを指定します。

    • :plain(パスワードを平文で送信)
    • :login(パスワードをBase64でエンコードする)
    • :cram_md5(チャレンジ/レスポンスによる情報交換と、MD5アルゴリズムによる重要情報のハッシュ化の組み合わせ)
  • :enable_starttls: SMTPサーバーへの接続でSTARTTLSを利用します(サポートされていない場合は失敗します)。デフォルトはfalseです。

  • :enable_starttls_auto: SMTPサーバーでSTARTTLSが有効かどうかを検出して有効にします。デフォルトはtrueします。

  • :openssl_verify_mode: TLSを利用する場合にOpenSSLが認証をチェックする方法を指定できます。自己署名証明書やワイルドカード証明書でバリデーションを行う必要がある場合に非常に有用です。 OpenSSL検証定数の名前('none'、'peer'、'client_once'、'fail_if_no_peer_cert')を用いることも、OpenSSL::SSL::VERIFY_NONEOpenSSL::SSL::VERIFY_PEER定数を直接用いることも可能です。

  • :ssl/:tls: SMTP接続でSMTP/TLS(SMTPS: SMTP over direct TLS connection)を有効にします。

  • :open_timeout: 接続オープン試行のタイムアウトを秒で指定します。

  • :read_timeout: read(2)呼び出しのタイムアウトを秒で指定します。

5.3 sendmail_settings

:sendmailの配信オプションを上書きします。

  • :location: sendmailの実行可能ファイルの場所を指定します。デフォルトは/usr/sbin/sendmailです。

  • :arguments: sendmailに渡すコマンドライン引数を指定します。デフォルトは["-i"]です。

5.4 raise_delivery_errors

メール配信に失敗した場合にエラーを発生するかどうかを指定します。このオプションは、外部のメールサーバーが即時配信を行っている場合にのみ機能します。デフォルトはtrueです。

5.5 delivery_method

配信方法を指定します。以下の配信方法を指定可能です。

5.6 perform_deliveries

Mailのメッセージにdeliverメソッドを実行したときに実際にメール配信を行なうかどうかを指定します。デフォルトでは配信が行われます。機能テストなどで配信を一時的にオフにしたい場合に便利です。

5.7 deliveries

delivery_method :testを用いてAction Mailerから送信されたメールの配列を保持します。単体テストおよび機能テストで最も便利です。

5.8 delivery_job

deliver_laterで使われるジョブクラスです。デフォルトはActionMailer::MailDeliveryJobです。

5.9 deliver_later_queue_name

デフォルトのdeliver_laterで使われるキュー名です。デフォルトのActive Jobキューがデフォルトです。

5.10 default_options

mailメソッドオプション (:from:reply_toなど)のデフォルト値を設定します。

5.11 Action Mailerの設定例

適切な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' }

5.12 Gmail用のAction Mailer設定

Action MailerはMail gemを利用して同様の設定を受け取れます。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:       '<username>',
  password:        '<password>',
  authentication:  'plain',
  enable_starttls: true,
  open_timeout:    5,
  read_timeout:    5 }

古いバージョンのMail gem(2.6.x以前)を使っている場合は、enable_starttlsの代わりにenable_starttls_autoをお使いください。

Googleは、安全性が低いと判断したアプリからのサインインをブロックしています。 Gmailの設定をここで変更することで、サインイン試行を許可できます。Gmailアカウントで2要素認証が有効になっている場合は、アプリケーションのパスワードを設定し、通常のパスワードの代わりにそれを使用する必要があります。

6 メーラーのテスト

メーラーのテスト方法の詳細についてはテスティングガイドのメーラーをテストするを参照してください。

7 メールのインターセプタとオブザーバー

7.1 メールをインターセプトする

インターセプタを使うと、メールを配信エージェントに渡す前にメールを加工できます。インターセプタクラスは以下のように、メールが送信される前に呼び出される::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環境を作成するを参照してください。

7.2 メールのオブザーバー

オブザーバーを使うと、メールが送信された後でメールのメッセージにアクセスできるようになります。オブザーバークラスは以下のように、メール送信後に呼び出される: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ガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。

  1. Star
  2. このエントリーをはてなブックマークに追加