【Rails】EC2にsorcery認証メールをgemを使わずにSES(Simple Email Service) で配置

## 概要
ポートフォリオの一環として、EC2上のインスタンスにPuma, NginxでRailsアプリケーションを動作させています。
また、ログイン機能としてgemの`sorcery`を配備させています。

ログイン機能の流れとしては、`アカウント新規登録`→`確認メールが送信される`→`送信元メールのリンクをクリック`→`アカウント有効化`といった流れで当然ですがメールをSESが送信します。

なお、本記事ではメールの送信のみを扱い、受信については実装しなかったので割愛します。

ちなみにAWSのSESを使って、`device`のgemを使ったやり方を見かけたものの、`aws-sdk-rails`といったgemを使ったやり方を見かけました。
> [Rails 6+Devise+AWS SESで簡単なログイン認証を実装する手順](https://zenn.dev/yukito0616/articles/3f224d68382c0d)

しかし、一方でgemを使わないでハンズオンコ－ドで簡単に実装できる以下の記事も見かけたので、そちらに倣ってエラーが散々出たものの、うまくいったやり方をご紹介します。

なお前提として、後で出てくる制限解除の申請するためにRoute53などでウェブサイトがURLとして公開ができていることが条件です。

> [【Rails】ActionMailer + AWS SES](https://qiita.com/syukan3/items/7f33a8cbd3c0301cd6f1)

## AWS側の初期設定
大まかな流れとして
Route53で登録した`ドメイン`をSESに登録 → `検証用メールアドレスを登録(任意)` 
→ `SMTPメール送信で権限作成` → `アプリ内に認証情報等を実装`
※SMTP(SimpleMailTransferProtocol)
となっています。

具体的には`SESダッシュボード` > `Create identity(必要事項入力)`

|  項目  |  内容  |
| ---- | ---- |
|  Identity type  |  Domainを選択  |
|  Domain  |  ドメインを入力(***.com)  |
|  Assign a default configuration set  | チェックしなかった  |
|  Use a custom MAIL FROM domain  | チェックしなかった   |
|  Verifying your domain  | ここにRoute53と連携できる |

もろもろの設定を終えると`Verified identities`の項目にドメインが表示されるとともにステータスが`Verified`となっているはずです(Route53を使ったら検証がしやすい)。

## サンドボックスによる制限
SESはサンドボックスといって初期設定は機能の制限された環境に置かれています。
その制限としては
・ 200通/24時間、1通/1秒に制限
・ 送信できる送信/宛先は検証済メールに限る  
といった点が特徴です。

:::note info
制限されるメール数については、ポートフォリオ程度ならまだなんとか運用できそうですが、外部送信ができないとなると、レビュアーのEメール先に送信できませんし、わざわざSESに手動で追加するわけにもいきませんね。
:::

というわけでポートフォリオを作るのならサンドボックス抜け申請が必須と言えます。

では早速サンドボックスを抜ける申請をおこなって行きましょう。
筆者はサンドボックスから抜けてしまって、詳細な手順は説明できないためすみませんが概要にとどめておきます

## サンドボックスによる送信制限解除を申請する

 ではSESのダッシュボードより、アカウント詳細ページに移ると、サンドボックスの解除を申請するフォームが出てくるかと思います。必須事項を入力して申請しましょう。



そちらからAWSのスタッフに解除申請する文面を作成します。
入力する項目
申請内容には必須かどうかは定かではないですが、EC2などで公開がすんでいるかたは先にアプリケーションをメッセージに共有すると確実かもしれません。

|  項目  |  内容  |
| ---- | ---- |
|  Enable Production Access  |  本番用かどうか、○を選択する  |
|  Mail Type  |  SESの使用範囲、業務用を選択した  |
|  Website URL  | メールサーバーと紐づくサイトURL   |
|  Use case description  | 使用用途の説明(記述式)   |
|  Additional contact addresses  | コンタクトの取れるメール(ここに審査結果がくる)  |
|  Preferred contact language  | ナビゲーターとのやりとり言語、日本語を選択  |

:::note warn
この文面の内容を単純に「使用したいです」みたいな文面で申請してしまうと、申請が下りずに再度作り直すハメになります。文面にはSESの制限枠を超える必要のある理由と、実装するアプリケーションで取り扱うメールの管理方法について具体的に記載するようにしましょう。筆者も記事にあった簡易的な文面を申請したところ見事却下されました。
:::

早くて半日〜1日以内に返答がありました。結果的には2回メッセージを送ってサンドボックスの制限から抜けられましたが、あらかじめきちんと文面も整えておきましょう。

## SMTP認証権限の作成
SESを扱うIAMユーザーを作成します。このユーザーのIDとパスワードをアプリケーションに埋め込むことでメールが送信される仕組みになっています。
`SESダッシュボード` > `SMTP Settings` > `CreateMySMTPCredentials`ボタンを押します。
そうするとSESで管理する、**SES側の**IAMユーザーを作成しますのでわかりやすい名前を設定しましょう。

> IAM User Name: no-reply

これで`作成`ボタンを押すとSESを扱う　IAMユーザー権限の作成が完了されました。この後すぐに認証情報のIDとパスードが出てくるのでcsvをダウンロードするなり、コピペしてメモっておきましょう。

## アプリ側の実装
さて、アプリ側では新規ファイルやgemは必要にならないので、先に取得したID、パスワードを環境変数に反映してコードに落とし込んでいきます。
編集するファイルはgemの`sorcery`の場合は
`config/environments/production.rb` と
`app/mailers/application_mailer.rb` です。

### config/environments/production.rb
該当部分の記載になります。

```ruby
# SorceryによるメールサーバーにSESを指定
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.perform_caching = true
  config.action_mailer.default_url_options = { host: 'https://www.アプリ名.com/' }
  ActionMailer::Base.smtp_settings = {
      :address =>        'email-smtp.ap-northeast-1.amazonaws.com',
      :port =>           587,
      :domain =>         'amazonaws.com',
      :authentication => :login,
      :user_name =>      ENV["SES_USER"],
      :password =>       ENV["SES_PASSWORD"]
  }
```
`action_mailer.default_url_options`の`host`にはURLに入力するルートURLを入れてください。
`ActionMailer::Base.smtp_settings`の`:address`には

`application_mailer.rb`には`SESダッシュボード` > `Account dashboard内の` > `Simple Mail Transfer Protocol (SMTP) settings` > `SMTP endpoint` のアドレスを、リージョンに紐づくアドレスになっています。
`:user_name`と`:password`には先に取得したIDとパスワードです、
ここではdotenv_railsを使って環境変数化しています([使い方](https://qiita.com/ryosuketter/items/ceb592dc6b23a20e51b5))。

### app/mailers/application_mailer.rb

```ruby
class ApplicationMailer < ActionMailer::Base
  default from: '検証用@gmail.com'
  layout 'mailer'
end
```
さて、筆者の場合新規ユーザー登録を押すとそのメール宛に送信されるのですが、internal_server_error(500)がおきてしまいました。
調べてみるとどうやらSESでは送信元のメールアドレスを上の`application_mailer.rb`で記載しますが、この`default from`が**検証されたアドレス(Verified identities)**でないとアプリがエラーになってしまうみたいです。

> [制限緩和してサンドボックス外にいるSESから「Email address is not verified.」エラーが発生する](https://bbh.bz/2019/08/31/ses-not-verified-err/)

具体的に検証用のメールアドレスとは、先のサンドボックスのセクションで話した、制限枠のころにメールを送信宛として飛ばしたメールなどがそれにあたります。

なので検証用のメールがまだの人は登録しておきましょう。
`SESダッシュボード` > `Verified identities` を押すとRoute53などで登録したドメインが出てきます。
そこに`Create Identity`とボタンがあるのでそちらに通信ができるスマホのメールアドレスなどを入れておきます。

それを登録するとSESから認証URLが送られてくるのでスマホなどからタップすると検証済の`Verified identities`として登録されます。

そうしたら先ほどのコードの`default from: '検証用@gmail.com'`にそのままアドレスを差し替えておきましょう。

### あとがき

Qiita記事の初投稿ですがSESに関するリソースが断片的にしかなかったので、全体的なストーリーが俯瞰しやすいように解説をいたしました。食い違う点があるかもしれませんが、ポートフォリオにSESを導入されたい方の参考になれば幸いです。