Action Mailer でメール送信機能をつくる

##概要


**Action Mailer**を使ってメールの送信機能をつくります:speech_balloon:
今回は管理者がユーザーからのお問い合わせに対して、管理者画面から返事をすると、
ユーザーにメールで送信される機能を実装していきます。

学習メモとして記録 :writing_hand_tone4:

##参考

（１）[RAILS GUIDES: Action Mailer の基礎](https://railsguides.jp/action_mailer_basics.html)
（２）[【Ruby on Rails】メール送信の実装手順（ActionMailer）とはまったエラーなど](https://normalblog.net/system/rails-actionmailer/)
（３）[Railsでメール自動配信機能をつくるまでの道程](https://qiita.com/Yama-to/items/823baf26bba3193712ea)
（４）[Rails の ActionMailer でメール送信処理](https://qiita.com/hirotakasasaki/items/ec2ca5c611ed69b5e85e)
（５）[RailsのAction Mailerでメール送信](https://ruby-rails.hatenadiary.com/entry/20140828/1409236436)

## Action Mailerとは

**Ruby on Rails** に組み込まれているメール送信機能のこと。
**Action Mailer** を使うと、**Ruby on Rails** からメールを送信してくれます :envelope:

・メールマガジンの一斉送信
・ウェブサイトに会員登録した時のthank youメール
・お問い合わせフォームの記入内容が管理者にメールでも送信される

のような時にアプリケーションからメールを送信する機能と解釈してます。
アプリケーションのメーラークラスやビューからメールを送信することができる便利な機能です！

#導入手順
### 1. メイラーを生成

railsコマンド(`rails generate`)で生成します。 ContactMailer は任意クラス名。
今回はお問い合わせ関係のメール送信機能を作成したいためContactMailerです。

```terminal.生成
$ rails generate mailer ContactMailer
```

↓


```terminal.結果
Running via Spring preloader in process 1893
   create  app/mailers/contact_mailer.rb
   invoke  erb
   create    app/views/contact_mailer
   invoke  rspec
   create    spec/mailers/contact_mailer_spec.rb
   create    spec/mailers/previews/contact_mailer_preview.rb
```

無事に生成されましたね :v_tone3:

###2. サーバーを設定  

メールを送信するときは、送信するサーバーが必要。と言うことで、
`config/environments/development.rb`にメール送信設定を記述します。
今回はg-mailを使う記載方法です。

```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:               'gmail.com',
    user_name:            '<YOUR EMAIL ADDRESS>',
    password:             '<YOUR EMAIL PASSWORD>',
    authentication:       'login',
    enable_starttls_auto: true
  }
end
```

`port:`も上記の数のままで大丈夫です。

上から順々に見ていきます。
ここでは、`config.action_mailer`というパラメーターに色んなオプションを指定してます。

**1行目** `raise_delivery_errors`
メールの送信に失敗した時にエラーを出すかどうか （出したいので true）

**2行目** `delivery_method`
メールの送信方法。 デフォルトで `:smtd` なので気にする必要もないのですが、
わたしみたいに「なにそれ！？」ってなった方は以下の引用を読んでみてください。

>「SMTP」とは「Simple Mail Transfer Protocol（シンプル・メール・トランスファー・プロトコル）」の略で、あえて>訳せば「簡単なメールの送信の手順」というところだろうか。お約束ごとと考えてもいい。
>
>あなたがメールを書き、宛先のアドレスを入力して「送信」アイコンをクリックする。このとき、あなたのスマホやパソコン>は、この「SMTP」のお約束ごとに従って、あなたが契約しているメールサーバーと、こんなやり取りをするのである。
>「メールを送るよ〜」「ええで！」「宛先は〇◯だよ」「りょ」「本文はかくかくしかじかだよ」「受け取ったで！」――とまぁそんな具合。
>

出典： [メール設定で最初につまずく「SMTP」「POP」「IMAP」。その意味＆設定方法は？](https://time-space.kddi.com/ict-keywords/kaisetsu/20170824/2081)


**3行目** `smtp_settings`
smtpの詳細設定って感じです。

1. port => SMTPサーバーのポート番号
2. address => SMTPサーバーのホスト名
3. domain => HELOドメイン
4. user_name => メール送信に使用するgmailのアカウント
5. password => メール送信に使用するgmailのパスワード
6. authentication => 認証方法
7. enable_starttls_auto => メールの送信にTLS認証を使用するか


###3. メーラーを編集
メーラーってRailsのコントローラーと似てるんですね。
「アクション」と呼ばれるメソッドがあり、メールの内容をつくるのにビューを使います。

生成直後は、以下のような **application_mailer.rb** と

```app/mailer/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
  layout 'mailer'
end
```

空のメーラー

```app/mailer/contact_mailer.rb
class ContactMailer < ApplicationMailer
end
```

があるはずです。

`application_mailer`には全メーラー共通の設定を、
`sample_mailer`にはメーラー個別の設定をします。

###application_mailerを編集します

```app/mailer/contact_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from:    "管理人 <from@example.com>",
  layout 'mailer'
end
```

共通の処理・設定を記述する場合には`defaultメソッド`を使用します。

|  プロパティ  |  役割  |
| ---- | ---- |
|  to  |  送信先の指定  |
|  cc  |  一斉送信先の指定  |
|  bcc  |  非表示送信先の指定  |
|  from  |  メールの送信元名  |
|  subject  |  メールタイトル  |
|  date  |  メールの送信日時 |
|  reply_to  |  返信用アドレスの指定 |

などが指定できます。

#### contact_mailer.rb を編集します

今回は管理者の返信がユーザーのe-mailに届くようにします。
なのでメソッドを`send_when_admin_reply`と定義しました。

```app/mailer/contact_mailer.rb
class ContactMailer < ApplicationMailer

  def send_when_admin_reply(user, contact) #メソッドに対して引数を設定
    @user = user #ユーザー情報
    @answer = contact.reply_text #返信内容
    mail to: user.email, subject: '【サイト名】 お問い合わせありがとうございます'
  end

end

```
個別の設定には`mailメソッド`を使用します。
`send_when_replyedメソッド`を呼び出す時に渡されるユーザーの情報から、
emailアドレスだけを取り出してメールの送信先としてします。

`mailメソッド`が呼び出されると、メール本文が記載されているビューが読み込まれます。
インスタンス変数(@xxx)でメーラービューに値を渡してあげたいので、インスタンス変数を用意してる感じです。

次は、そのメールの本文を作成していきます :keyboard:


###４. メールの本文を作成する（メーラービューの作成）

`app/views/contact_mailerディレクトリ`下にファイルを2つ作成します。

１つはHTMLフォーマット、もう一つはテキストメール。
顧客によってはHTMLフォーマットのメールを受け取ることができない / 受け取りたくない人もいるので、テキストメールも作成しておくのが最善です。

#### HTMLファイルの作成

```views/contact_mailer/send_when_admin_reply.html.erb

  <h2><%= @user.name %> 様</h2>
　<p>この度は、お問い合わせありがとうございました。<br>
　以下でご質問の回答となっておりますでしょうか。</p>

  <p><%= @answer %></p>

  <p>今後とも XXX をよろしくお願いいたします。</p>

```

#### テキストファイルの作成

```views/contact_mailer/send_when_admin_replyd.text.erb

  ===============================
  <%= @user.name %> 様
  ===============================

  この度は、お問い合わせありがとうございました。
　以下でご質問の回答となっておりますでしょうか。

  <%= @answer %>

  今後とも XXX をよろしくお願いいたします。

```

###5. 実際に処理を走らせるアクションにメール送信処理をさせる

メールの設定を記述しただけではメールは送信できません。
メーラー（ここでは`application_mailer.rb` / `contact_mailer.rb`）は各コントローラーのアクションからの呼び出しによって起動します。

管理者がアプリケーション管理画面フォームより返信を送信し、その内容をメールでユーザーに送信します。
実際に処理を走らせるアクションは`admin/contacts_controller.rb`となります。


```app/controllers/contacts_controller.rb

class Admin::ContactsController < Admin::ApplicationController
  def update
   contact = Contact.find(params[:id]) #contact_mailer.rbの引数を指定
   contact.update(contact_params)
   user = contact.user
   ContactMailer.send_when_admin_reply(user, contact).deliver
  end
end

```

例えば、ユーザーが新規アカウント登録をしてメールを送信する場合は、


```app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :set_user

  def create
    if @user.save #ユーザーのインスタンスが新しく生成されて保存されたら
      NotificationMailer.send_when_signup(@user).deliver #確認メールを送信
      redirect_to @user
    else
      render 'new'
    end
  end
end
```

createアクションに処理を走らせることになります。

わたしのアプリケーションでは、DBの設計上
ユーザーが問い合わせをした時点で、Contactsテーブルの中に、
1つレコードが準備されていて、その中に'返信'というカラムが用意されています。

なので、updateアクションを使って
すでにあるレコードの中に管理者の返信のデータだけを更新してあげる形になります:sunflower:


### 6. テストしてみる

以上でメーラーができるはずです・・！
実際にアプリケーションを動かしてみて、メールを受信できたら成功 :ok_hand_tone3:

以上、学習メモでした :hatched_chick::writing_hand_tone4: