【Rails】 Action Mailerとdeviseをつかって登録完了メールを自動送信してみる

deviseのユーザー認証機能を利用することを前提に、ユーザーの新規登録完了後にActionMailerを使って登録完了メールを送信する方法をまとめています。

# 大まかな流れ #
1. メール送信用サーバーの設定
1. アプリパスワードの取得
1. WelcomeMailerを生成
1. ApplicationMailerとWelcomeMailerの編集
1. deviseのcontrollerのcreateアクションをオーバーライドして、WelcomeMailerを呼び出す
1. メール本文の作成
1. おまけ：dotenv-railsでメールアドレスやパスワードをGitHubにあげないようにする

### 前提 ###
 
- deviseでUserモデルを作成した、かつusersテーブルにはnameとemailカラムがあることを前提としています
- deviseの設定については、[こちら](https://qiita.com/kskumgk63/items/aa581b6b3f8c66fa82e2)の記事等を参考に設定できればOKかと思います（上記の記事を参考にする場合：メール認証についてはこの記事でもSTEP1でまとめていきますが、どちらの記事を参照していただいても構いません）
- STEP1の「メール送信用サーバの設定」ではGmailを使用するので、Googleアカウントを一つ用意してください。練習用の場合は、サブのアカウントや練習用アカウントで試される方が安心かと思います


# 実装手順 #
では実装を進めていきましょう！

## STEP1. メール送信用サーバーの設定 ##

Gmailアカウントからメールを送れるようにするために、メール送信用のサーバーを設定します。以下のsmtpというのがメール送信に必要なSMTPサーバーのことですね。

（余談ですが、メール送信周りのサーバーについては[こちら](https://www.kagoya.jp/howto/rentalserver/smtpserver/#:~:text=SMTP%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E5%BD%B9%E5%89%B2,%E9%85%8D%E9%80%81%E3%82%92%E4%BE%9D%E9%A0%BC%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)がコンパクトでわかりやすかったです）

```Ruby:config/environments/development.rb

Rails.application.configure do
  #　-----　中略 -----  #
  config.action_mailer.raise_delivery_errors = true
  #　-----　中略 -----  #

  #　 以下を末尾に追記   #
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    port:                 587,
    address:              'smtp.gmail.com',
    domain:               'smtp.gmail.com',
    user_name:            '送信元となるGmailアドレスを記入',
    password:             'STEP2で取得するアプリパスワードを記入',
    authentication:       'login',
    enable_starttls_auto: true
  }
end
```

上記について、具体的に見ていきましょう：

 - まず、```development.rb```に記述されている、```config.action_mailer.raise_delivery_errors```が```false```になっていれば、```true```に変更する
 - 「以下を末尾に追記」とコメントした部分は、コピペする
 - ```user_name```と```password```には、個々のGmailアドレスなりアプリパスワードの入力が必要。アプリパスワードはSTEP2で取得するので、ここではまず```user_name```に、新規登録完了メールの送信元となる（自分や運営組織の）Gmailアドレスをシングルクオテーション内に記述


## STEP2. アプリパスワードの取得 ##

STEP1で指定したGmailのGoogleアカウントページから、アプリパスワードを取得します👇

① Googleのトップページ右上のアカウントアイコンをクリック。「Googleアカウントを管理」をクリックして、Googleアカウントページにいく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/0c4339b5-b395-ac53-91b1-9fc623c5dd85.png)

② サイドバーから「セキュリティ」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/527a3621-5501-2cd5-f404-d7bb82b0c602.png)

③「Googleへのログイン」セクションの「2段階認証プロセス」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/8e86c521-24d2-0239-668f-d1e3daf7b104.png)

④「使ってみる」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/f6f7bb9a-80a1-9e16-a98e-7038fd657e70.png)

⑤ Googleアカウントへのパスワードを要求されたら入力してログイン。「ログインの2つ目の手順としてスマートフォンを使用」画面が表示されたら、適当な方法を選択し「続行」をクリック（私は「他のオプションを表示」→「テキストメッセージまたは音声通話」を利用しました）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/29e0b918-9840-0e82-7ae6-3f826953a2b0.png)

⑥ 指示に従って進めていき「2段階認証プロセスを有効にしますか？」が出たら「有効にする」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/689b8f3e-6412-08c0-bf59-a81d74961c3b.png)

⑦ 有効にできたら、画面上部の「←」をクリックし、「セキュリティ」画面に戻る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/9bdfbf53-464d-318b-d2b9-b17d980668ee.png)

⑧ 再び「Googleへのログイン」セクションを見ると、「アプリパスワード」の行が追加されているので、クリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/5335c586-8ede-187a-bf4e-a5b293881798.png)

⑨ 再びGoogleアカウントのパスワードを要求されるので、入力してログインし、「アプリパスワード」画面に遷移したら、まず「アプリを選択」から「その他（名前を入力）」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/cc17e3c4-6d8b-a16f-6c59-9d8504c625dc.png)

⑩ 作成しているアプリケーションの名前を記入し「生成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/fbd58092-f952-902d-a0ee-04e64fabc58f.png)

⑪ 黄枠内に生成されたアプリパスワードが表示されるので、コピーしてどこかメモなどに張り付けておく（なくすとアプリパスワードを生成し直すことになるのでメモしておいた方が良いです）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1215197/ed0a6ee7-9dcf-60a9-85f4-d7a218ab86e6.png)

⑫ 開発環境に戻って、```development.rb```の```password```に、⑪で取得したアプリパスワードをペースト

⑬ ```devise.rb```の```config.mailer_sender ```に、送信元となるGmailアドレス（```development.rb```の```user```に記述したのと同じアドレス）を記入

```Ruby:config/initializers/devise.rb
  #　-----　前略 -----  #

  config.mailer_sender = '送信元となるGmailアドレスを記入'

  #　-----　後略 -----  #
```


## STEP3. WelcomeMailerを生成 ##

ターミナルで以下のコマンドを実行し、```WelcomeMailer```と```send_when_signup```メソッドを一緒に生成します。Mailer名とメソッド名は好きなものを指定してOKです。

```ruby:terminal
$ rails g mailer WelcomeMailer send_when_signup
# rails g mailer   <Mailer名>     <メソッド名>
```
これにより、以下が生成されます：

- ```app/mailers```配下に、```application_mailer.rb```と```welcome_mailer.rb```
- ```app/views/welcome_mailer```配下に、viewファイル（ ```html.erb```ファイルと```text.erb```）

※メソッドは、Mailerと一緒に生成しなくても大丈夫ですが、STEP6でメール本文を作成する際に自分でviewファイルを作成する工程が発生するので、この段階でメソッドごと生成してしまう方が手間がないかと思います。


## STEP4. ApplicationMailerとWelcomeMailerの編集 ##

まず、```application_mailer.rb```には、すべてのMailerに共通の設定を記述します。これに対し、```welcome_mailer.rb```には、WelcomeMailerに固有の設定を記述します。

なお、```application_mailer.rb```はデフォルトの記述のままでも動作するので、単に練習用・勉強用ということであれば、```welcome_mailer.rb```の編集に進んでもOKです

**```application_mailer.rb```を編集**

```Ruby:app/mailers/application_mailer.rb
#デフォルトの記述
class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
  layout 'mailer'
end

#編集例
class ApplicationMailer < ActionMailer::Base
  default from:     "〇〇事務局",
          cc:       "hogehoge@gmail.com"
          bcc:      "hoge_hoge@gmail.com"
  layout 'mailer'
end
```

👆の```defalut```メソッドは、共通の設定を記述する際に使用するもので、以下のような項目についてデフォルト値の指定が可能です：

|  項目  |  内容  |
| ---- | ---- |
|  to  |  メインの送信先  |
|  cc  |  メインではないが、共有しておきたい送信先  |
|  bcc |  他の人に見られずに共有しておきたい送信先  |
|  subject |  メールのタイトル  |
|  from |  メールの送信元の名前  |
|  reply_to |  返信先のメールアドレス  ​
|  date |  メールの送信日時  ​|


**```welcome_mailer.rb```を編集**

```Ruby:app/mailers/welcome_mailer.rb

def send_when_signup(email, name) 
    @name = name
    mail to: email, subject: 'Registration Complete! Thanks for Joining!'
end
```

ここで何をしているかですが…

- ```send_when_signup```メソッドの引数として、```email```と```name```を定義
- ```mail```メソッドが実行されると、メールの内容が記述されたviewファイル（ ```html.erb```ファイルと```text.erb```）が読まれる
-  ```@name```はviewファイル上に、userの登録氏名(```name```）を表示するために定義したインスタンス変数
-   ```subject```には任意の件名を指定できる

ちょっとこの段階ではわかりづらいかもしれませんが、controllerとviewの記述を見ていけば、```send_when_signup```メソッドで定義した内容もわかりやすくなると思うので、先に進めていきましょう！


## STEP5. deviseのcontrollerのcreateアクションをオーバーライドして、WelcomeMailerを呼び出す ##

STEP4で定義したWelcomeMailerは、controllerから呼び出してあげないと実行されません。

ユーザーの新規登録処理はdeviseのregistrations_controllerのcreateアクションに定義されています。そして、WelcomeMailerを呼び出す記述をcreateアクションに加えるには、「オーバーライド」が必要です。

<details>
<summary>**そもそも「オーバーライド」とは…？**</summary>
　『プロを目指す人のためのRuby入門』（伊藤淳一著）の定義をかりると、「サブクラスではスーパークラスと同名のメソッドを定義することで、スーパークラスの処理を上書きすること」ができ、「これをオーバーライドと言います」。
　オーバーライドを伴う処理の実装には「クラスの継承」に関する理解が必要になってきます。[こちら](https://www.sejuku.net/blog/9598)の記事や、上述の本の第7章にとてもわかりやすく整理されているので、「継承？？スーパークラス？？オーバーライド？？」な方にも理解しやすいかと思います。
</details>

### やっていきましょう ###

**① deviseのregistrations_controllerクラス（スーパークラス）を継承した、```users/registrations_controller.rb```（サブクラス）を作成**

 - ```app/controllers```配下に、```users```フォルダを作成（手動で、右クリック→フォルダ作成でOK）
 - ```users```フォルダ配下に、```registrations_controller.rb```を作成し、以下のように記述して、usersのregistraions_controllerに継承させる


```Ruby:app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController

end
```

**② createアクションをオーバーライドする**
　①で作成した```users/registrations_controller.rb```にcreateメソッドを追記

```Ruby:app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController
  
  def create
    #スーパークラス(devise)のcreateアクションを呼ぶ 
    super 
    #WelcomeMailerクラスのsend_when_signupメソッドを呼び、POSTから受け取ったuserのemailとnameを渡す
    WelcomeMailer.send_when_signup(params[:user][:email],params[:user][:name]).deliver
  end

end
```

どうなっているかというと…

- ```super```メソッドは、スーパークラスであるdeviseのregistrations_controllerのcreateアクションを呼んでいる（ちなみにdevise側のcreateアクションの定義がどうなっているかは、オーバーライドする前に確認しておいた方がいいと思います。[こちら](https://github.com/heartcombo/devise/blob/5d5636f03ac19e8188d99c044d4b5e90124313af/app/controllers/devise/registrations_controller.rb#L136)から確認できます）
- POSTから受け取ったuserの```email```と```name```の値は、```welcome_mailer.rb```で```send_when_signup```メソッドに定義した引数にそれぞれ渡る
- ```send_when_signup```メソッドの最終結果が、```deliver```メソッドで送信される


**③ ```users/registrations_controller```を呼び出す記述をルーティングに追加**

```Ruby:config/routes.rb
  
devise_for :users, controllers: {
  registrations: "users/registrations"
}

# ---- 後略 ---- #
```

👆 もともとdeviseを導入したときに```devise_for :users```は記述されているはずですが、それ以降の部分を追記して、deviseの```registrations_controller```を継承した```users/registrations_controller```へのルーティングが行えるようにしてあげましょう。


## STEP6. メール本文の作成 ##

ここまでくればもう少しです！
まだメールのviewファイルを編集できていないので、記述していきましょう。
（viewファイルの記述内容は適宜変更してください）

HTMLファイルで受け取れない/受け取りたくないuserがいる可能性もあるので、テキストファイルもあわせて用意しておくのが推奨されているようです。

```:app/views/welcome_mailer/send_when_signup.html.erb

<h2><%= @name %> さま</h2>

<p>この度は、〇〇へのご登録ありがとうございました。</p>
<p>今後とも 〇〇 をよろしくお願いいたします。</p>

<p>〇〇事務局</p>

```

```:app/views/welcome_mailer/send_when_signup.text.erb
-------------------------------
      <%= @name %> さま
-------------------------------

この度は、〇〇へのご登録ありがとうございました。
今後とも 〇〇 をよろしくお願いいたします。

〇〇事務局
```

これでユーザーの新規登録後にメールが送信されるはずです。
メールが届くかどうか、実際に確認してみてください。


## おまけ：dotenv-railsでメールアドレスやパスワードをGitHubにあげないようにする ##

GitHubにpushする前に、ここまで記述してきたメールアドレスやパスワードが、GitHubにあがらないように環境変数とを定義しておいた方がセキュアかと思います。

ここでは一例だけ取り上げますが、<font color=red>**どこに環境変数の定義が必要かは、必ずご自身で確認されてから、push**</font> するようにしてくださいね。ということで、やっていきましょう！

👇```dotenv-rails```を入れる

```Ruby:Gemfile
# ---- 前略 ---- #
gem 'dotenv-rails'
end
```

```:terminal
$ bundle install
```

👇 アプリケーションのフォルダ直下に、```.env```ファイルを作成

```:terminal
$ touch .env
```

👇 ```.env```ファイルに環境変数を定義
　「xxx」の部分には、元々ソースコードに記述していた値を記入

```Ruby:.env
WELCOME_MAILER_ADDRESS=xxx
WELCOME_MAILER_PASSWORD=xxx
```

👇 ソースコードで ```.env```に記述した環境変数を使用

```Ruby:config/environments/development.rb

Rails.application.configure do
  #　-----　中略 -----  #
  config.action_mailer.raise_delivery_errors = true
  #　-----　中略 -----  #

  #　 以下を末尾に追記   #
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    port:                 587,
    address:              'smtp.gmail.com',
    domain:               'smtp.gmail.com',
    user_name:            ENV['WELCOME_MAILER_ADDRESS'],
    password:             ENV['WELCOME_MAILER_PASSWORD'],
    authentication:       'login',
    enable_starttls_auto: true
  }
end
```


👇 ```.gitignore```に```.env```を追加

```Ruby:.gitignore

# ---- 前略 ---- #
/.env
```

👇 ```.env```ファイルがGit管理から外れたか確認（```.env```が表示されなければOK）

```:Terminal
$ git status
```

👇 環境変数が正しく設定できているか一応確認

```Ruby:Terminal
#rails c を起動
$ rails c

#以下を記述
> ENV['WELCOME_MAILER_ADDRESS']

#クオテーション内に.envに定義した値が出力されていればOK
=> "xxxxx@gmail.com"

#rails c を終了
>exit
```

他にも環境変数として定義しておきたい箇所は👆を繰り返します。
全部問題なくgit管理から外れたら、pushしましょう。




# 参考文献・資料 #

- [『プロを目指す人のためのRuby入門』](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AERuby%E5%85%A5%E9%96%80-%E8%A8%80%E8%AA%9E%E4%BB%95%E6%A7%98%E3%81%8B%E3%82%89%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA%E3%83%BB%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E6%8A%80%E6%B3%95%E3%81%BE%E3%81%A7-Software-Design-plus%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/4774193976)（伊藤淳一著）
- [Railsガイド: Action Mailer の基礎](https://railsguides.jp/action_mailer_basics.html)
- [deviseを使ったログイン機能を実装する！メール認証機能付き](https://qiita.com/kskumgk63/items/aa581b6b3f8c66fa82e2)
- [SMTPサーバーとは？IMAPやPOPとの違い＆基本の設定方法](https://www.kagoya.jp/howto/rentalserver/smtpserver/#:~:text=SMTP%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E5%BD%B9%E5%89%B2,%E9%85%8D%E9%80%81%E3%82%92%E4%BE%9D%E9%A0%BC%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)
- [オブジェクト指向「継承」とは？わかりやすく解説してみた ](https://www.sejuku.net/blog/9598)
- [Railsでメール自動配信機能をつくるまでの道程](https://qiita.com/Yama-to/items/823baf26bba3193712ea) 
- [【Rails】deviseでURL認証付きのメールを送信してみる](https://qiita.com/ozackiee/items/21fcad4a1564136b9510#%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%A9%E3%82%A4%E3%83%89%E3%81%99%E3%82%8B)
- [【Rails】deviseの使い方をマスターしてログイン認証機能を実装しよう！](https://pikawaka.com/rails/devise#%E3%83%A1%E3%83%BC%E3%83%AB%E8%AA%8D%E8%A8%BC%E6%A9%9F%E8%83%BD%E3%82%92%E3%81%A4%E3%81%91%E3%82%88%E3%81%86)