Ruby on Rails

【Rails】Action Mailerチュートリアル

今回はAction Mailerを使ったことがない人向けにチュートリアルを書いていきます。この記事はパーフェクトRuby on Railsを参考にさせていただきました。さらに詳細なことが知りたい場合、この本に丁寧に説明されています。ぜひ読んでみてください。

Action Mailerの機能を実装

まずはscaffoldで元となるアプリを作っていきます。

$ rails new action_mailer_tutorial
$ cd action_mailer_tutorial
$ bin/rails g scaffold user name email
$ bin/rails db:create
$ bin/rails db:migrate

Action Mailerで使うファイルをmailerのサブコマンドで生成します。

bin/rails g mailer UserMailer

メール送信時は先程生成したUserMailerクラスから送信します。メイラークラスの設計はコントローラーと似ていて、次のような特徴を持っています。

  • paramsオブジェクトを経由して渡されたデータを取得する
  • メイラークラスのメソッド内で処理した内容をインスタンス変数に代入してビューへ渡す

もぐくん
もぐくん
コントローラーみたいなものって考えればよさそうだね!

コントローラにおけるApplicationControllerに相当するメイラークラスが継承しているクラスがApplicationMailerで、そのファイルがapp/mailers/application/mailer.rbにあります。これを編集します。

class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com' # ここで指定したアドレスからメールが送信される
  layout 'mailer'
end

次にUserMailerクラスにメール送信処理を実装します。@nameにparamsで送られてくるnameがセットされ、params[:to]宛にメールを送信します。

class UserMailer < ApplicationMailer
  def welcome
    @name = params[:name]
    mail(to: params[:to], subject: "登録完了")
  end
end

次にViewを作っていきます。Action Mailerでは、mailメソッドを呼び出すとHTMLとテキストの2種類のテンプレートを探して、multipart/alternative形式のメールを作成します。これはHTMLとテキストの両方のフォーマットを持ったメールを送信し、受信側でフォーマットを選択する形式です。

<p><%= @name %>様</p>
<p>ユーザ登録完了!</p>
<%= @name %>様
ユーザ登録完了!

次にメーラーを使ってメールを送信する機能を実装します。ここでは、ユーザ登録が成功したらメールを送信するようにします。

respond_to do |format|
  if @user.save
    UserMailer.with(to: @user.email, name: @user.name).welcome.deliver_now
    format.html { redirect_to @user, notice: "User was successfully created." }
    format.json { render :show, status: :created, location: @user }

UserMailerクラスのwelcomeメソッドを実行します。withメソッドを使うことでparamsを一緒に送ることができます。((注)場所に注意です。) また、deliver_nowで同期的にwelcomeメソッドを実行しています。deliver_laterを使うと非同期に送ることも可能ですが、ここでは割愛します。

次にメールを送信する設定を行っていきます。開発環境ではメールをファイルとして保存する形式をとります。(実際にメールは送信されず、送信命令があったときに宛先ごとにファイルを作成し保存します。)

Rails.application.configure do
  config.action_mailer.delivery_method = :file
  # デフォルトではtmp/mails以下に保存される
# 略
end

これで、rails sでサーバーを起動してhttp://localhost:3000/usersにアクセスし、ユーザーを作成してみてください。tmp/mails以下にメールが作られているのが確認できるはずです。

Date: Tue, 16 Mar 2021 08:14:47 +0900
From: from@example.com
To: test@example.com

これで、一通りAction Mailerを使う準備ができました。

さかい
さかい
あと少し!

メール送信設定

次に実際にメール送信する設定を行います。ここでは、SMTPサーバとしてSendGridを利用します。(無料で使えます)

SendGridのアカウントを登録して、ユーザ名とパスワードをcredentialsを使って保存します。

$ bin/rails credentials:edit

はじめて開こうとするとこのような画面になるかと思います。

No $EDITOR to open file in. Assign one like this:

EDITOR="mate --wait" bin/rails credentials:edit

For editors that fork and exit immediately, it's important to pass a wait flag,
otherwise the credentials will be saved immediately with no chance to edit.

エディターを登録してくださいと言われているので登録します。ここではVimを使います。

$ EDITOR="vim" bin/rails credentials:edit

エディターが立ち上がるので、SendGridのユーザ名とパスワードを登録していきましょう。escして:wqとすれば保存できます。

# 略
smtp_user_name: ***************
smtp_password: **************

次にSMTP接続する設定を行います。

Rails.application.configure do
  config.action_mailer.smtp_settings = {
    user_name: Rails.application.credentials.smtp_user_name,
    password: Rails.application.credentials.smtp_password,
    domain: 'from@example.com',
    address: 'smtp.sendgrid.net',
    port: 587,
    authentication: :plain,
    enable_starttls_auto: true
  }
end

また、次の設定をコメントアウトしておいてください。

  # config.action_mailer.delivery_method = :file

これで、ユーザ登録後メールが届いているはずです。

もぐくん
もぐくん
届いてた!

Action MailerをRSpecでテストする

まずは、RSpecが使えるよう準備します。

$ bin/rails g rspec:mailer UserMailer

次に設定を行います。この設定を行うことで、テストを行う際に実際のメール送信は行わず、ActionMailer::Base.deliveries配列へ送信されたメールが格納されます。

Rails.application.configure do
  config.action_mailer.delivery_method = :test
  # 略
end

それではテストを書いていきます。長くなりましたが、難しいことはしてません。まずはUserMailerクラスからwelcomeメソッドを実行します。そうすると、上に書いた設定により、メールが配列となってActionMailer::Base.deliveriesに入るので、それを取り出して中身を確認しています。

require "rails_helper"

RSpec.describe UserMailer, type: :mailer do
  describe 'send_mail' do
    it '指定したアドレスからメールが送信されていること' do
      UserMailer.with(name: 'さかい', to: "to@example.com").welcome.deliver_now
      expect(ActionMailer::Base.deliveries.last.from.first).to eq ('from@example.com')
    end

    it '指定した送信先のアドレスであること' do
      UserMailer.with(name: 'さかい', to: "to@example.com").welcome.deliver_now
      expect(ActionMailer::Base.deliveries.last.to.first).to eq ('to@example.com')
    end

    it '正常にメールが送信されていること' do
      UserMailer.with(name: 'さかい', to: "to@example.com").welcome.deliver_now
      expect(ActionMailer::Base.deliveries.last.subject).to eq ('登録完了')
    end

# DRYに書くと・・
    subject(:mail) do
      described_class.with(name: 'さかい', to: "to@example.com").welcome.deliver_now
      ActionMailer::Base.deliveries.last
    end

    context 'when send_mail' do
      it { expect(mail.from.first).to eq('from@example.com') }
      it { expect(mail.to.first).to eq('to@example.com') }
      it { expect(mail.subject).to eq('登録完了') }
    end
  end
end

きちんとテストがパスすれば成功です。

$ bin/rspec

さかい
さかい
お疲れさまでした!

まとめ

少し長くなりましたが、お疲れさまでした。これでAction Mailerについてざっくり分かったのではないでしょうか。僕自身、実務で使ったことがないので使い次第分かったことなどを共有できればと思います。

GitHubにレポジトリを上げておくので、詰まった人はこちらを参考にしてみてください。
ここまで読んでくださりありがとうございました。

ABOUT ME
sakai
三重出身の28歳。前職はメーカーで働いていて、プログラミングスクールに通って未経験からWeb業界に転職しました。Railsをメインで使っていて、AWSも少しできます。音楽を聞くこととYoutubeを見るのが好きです。最近はへきトラ劇場にハマってます