railsでメール送信機能実装

# はじめに
<!-- 発端や概要を記載 -->
[現場で使える Ruby on Rails 5速習実践ガイド](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Ruby-Rails-5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E5%A4%A7%E5%A0%B4-ebook/dp/B07JHQ9B5T)でインプットを行っており、アウトプットで投稿しています。
サンプルは、タスク管理アプリです。今回の投稿では、ユーザーがタスクを登録したときに、「○○タスクが登録されました」というメールを送る機能を実装します。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [メイラーの作成](#Chapter1)
1. [メソッドを追加](#Chapter2)
1. [テンプレート作成](#Chapter3)
1. [送信処理実装](#Chapter4)
1. [動作確認](#Chapter5)
1. [テスト作成](#Chapter6)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# メイラーの作成
メイラーとは、ActionMailerのことで、railsに搭載されているメールを送る機能です。controllerが、templateに情報を渡し画面出力を行っているのと同様に、Mailerもtemplateに情報を渡しメールを送信します。
まずは、今回実装するTaskMailerを作成します。以下のコマンドを実行します。

```
rails g mailer TaskMailer
```

<a id="#Chapter2"></a>
# メソッドを追加
先程のコマンドで`app/mailer/task_mailer.rb`というファイルが作成されます。そこに、今回送信するメールのメソッド「creation_email」を定義します。

```app/mailer/task_mailer.rb
def creation_email(task)
  @task = task
  mail(
    subject: 'タスク作成完了メール',
    to: 'user@example.com',
    from: 'task@example.com'
  )
end
```

こちらのメソッドを呼び出すときに、追加されたタスクを引数として渡してもらいます。taskの内容をtemplateで表示するのでインスタンス変数に格納しています。

<a id="#Chapter3"></a>
# テンプレート作成
次にテンプレートを作成します。ユーザーの受信環境によっては、html形式のメールを表示できない可能性があります。text形式のファイルを合わせて作成し、html形式と合わせて送信しますのでファイルを二種類作成します。

```app/views/task_mailer/creation_email.html.slim
| 以下のタスクを作成しました

ul
  li
    | 名称：
    = @task.name
  li
    | 詳しい説明
    = simple_format(@task.description)

```

```app/views/task_mailer/creation_email.text.slim
| 以下のタスクを作成しました
= "\n"
| 名称：
= @task.name
= "\n"
| 詳しい説明
= "\n"
= @task.description

```

<a id="#Chapter4"></a>
# 送信処理実装
ここまで来たらあとは、送信する処理を記述するのみです！
今回は、タスクの保存処理と合わせてメールを送信するため、tasks_controllerのcreateメソッドに送信処理を書きます。

```app/controllers/tasks_controller.rb
  略
    if @task.save
      TaskMailer.creation_email(@task).deliver_now
      SampleJob.perform_later
      logger.debug "task:「#{@task.attributes.inspect}」を登録しました"
      redirect_to tasks_url, notice: "タスク「#{@task.name}」を登録しました。"
    else
      render :new
    end
  略
```

`deliver_now`は文字通り、即時に送信する命令です。５分後にメールを送りたいときは、`deliver_later(wait: 5minutes)`とします。

<a id="#Chapter5"></a>
# 動作確認
メールが送信されたか、メールの内容は意図したとおりになっているか。これを確かめるために、「mailcatcher」というgemを使用します。

```
gem install mailcatcher
```

上記のコマンドを実行し、railsの設定ファイルに以下の記述を行います。

```config/environments/development.rb
  # Don't care if the mailer can't send.
  config.action_mailer.raise_delivery_errors = false
  # 以下二行を追記
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = { address: '127.0.0.1', port: 1025}
```

上記は開発環境の設定ですが、本番環境の設定は、procuction.rbに記述をします。

設定ファイルの記述が完了したら、サーバーを再起動してください。
確認の手順は、

- ターミナルで`mailcatcher`を実行
- メール送信のフローを実行後、`http://127.0.0.1:1080/`にアクセス

そうすると、送信メールの確認ができます。

<a id="#Chapter6"></a>
# テスト作成
まずは、mailerのSpec用にディレクトリを作成します。

```
mkdir spec/mailers
```

作成したフォルダの中に`task_mailer_spec.rb`を作成し、以下のように記述します。

```spec/mailers/task_mailer_spec.rb
require 'rails_helper'
describe TaskMailer, type: :mailer do
end
```

これで枠組みは完成なので、実際にテストを書いていきます。

```spec/mailers/task_mailer_spec.rb
require "rails_helper"

RSpec.describe TaskMailer, type: :mailer do
  let(:task){FactoryBot.create(:task, name: 'メイラーSpecを書く', description: '送信したメールの内容を確認します')}
  let(:text_body) do
    part = mail.body.parts.detect{|part| part.content_type == 'text/plain; charset=UTF-8'}
    part.body.raw_source
  end
  let(:html_body) do
    part = mail.body.parts.detect{|part| part.content_type == 'text/html; charset=UTF-8'}
    part.body.raw_source
  end

  describe '#creation_email' do
    let(:mail){TaskMailer.creation_email(task)}

    it "想定通りのメールが生成されている" do
      expect(mail.subject).to eq('タスク作成完了メール')
      expect(mail.to).to eq(['user@example.com'])
      expect(mail.from).to eq(['taskleaf@example.com'])

      expect(text_body).to match('以下のタスクを作成しました')
      expect(text_body).to match('メイラーSpecを書く')
      expect(text_body).to match('送信したメールの内容を確認します')

      expect(html_body).to match('以下のタスクを作成しました')
      expect(html_body).to match('メイラーSpecを書く')
      expect(html_body).to match('送信したメールの内容を確認します')
    end
  end
end

```
以下のコマンドを実行し通るか確認します。

```
bundle exec rspec spec/mailers/task_mailer_spec.rb
```


<a id="#reference"></a>
# 参考文献
- [現場で使える Ruby on Rails 5速習実践ガイド](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Ruby-Rails-5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E5%A4%A7%E5%A0%B4-ebook/dp/B07JHQ9B5T)