Ruby on RailsとSendGridでのメール送信に関する記事はたくさんあるのですが、受信の記事は少なかったのでまとめました。
SendGridとは
SMTPプロバイダ、つまり自分でメールサーバを用意せずにSendGridのSMTPサーバーを使って送受信ができるサービスを提供しています。
さらにエラー通知や開封率の確認といった機能も提供しているので、APIを使えばメール関連の機能がほぼ全てカバーできます。また、基本的に無料で日本語ドキュメントや公式ブログが充実しているのも嬉しいポイントです。
SMTP(Simple Mail Transer Protocol)とは
メールの送信受信に主に使われるプロトコル。一般的にメールを送信する際には設定されたSMTPサーバーに接続してSMTPプロトコルで通信する。
今回はこのSendGridを使って、Railsアプリでメール受信するまでをまとめました。
自分のメモを兼ねてRailsアプリの作成から途中で使うツールの解説まで出来る限り丁寧に書いています。
これを作ります
自分のドメイン名宛のメールをSendGrid経由で受信してリストにするところまで作ります。
フレームワーク: Ruby on Rails
データベース: PostgreSQL
その他使うもの: Heroku, ngrok, PG Commander, GitHub
事前準備:
① Rails, Heroku, GitHubが使えるようにしておく(Railsチュートリアルが終わっていればOK)
② ドメインを一つ取得しておく(今回はお名前ドットコムを使用)
Railsアプリの作成
アプリケーション生成
$ rails _5.1.6_ sendgrid_app
Gem file 設定
$ bundle install
(あらかじめGitHubでリポジトリを作成しておく)
ローカルでGitの設定
$ git init
$ git add -A
$ git commit -m 'Initialize repository'
$ git remote add origin <GitHubのリポジトリ>
$ git push -u origin --all
Hello Worldを表示
controller/application_controller.rb
config/routes.rb
Herokuにpush
$ heroku create
$ git push heroku master
PostgreSQLの設定
Homebrewでインストール
$brew install
$brew update postgresql
試しに起動(エラーが出る)
$postgres
エラーが出たらpostgresが入っているのでOK
環境変数の設定
postgresqlをインストールした時に作成された/usr/local/var/postgresを環境変数に入れる
~/.bashrcに以下を追加
export PGDATA='/usr/local/var/postgres'
$ source ~/.bashrc
database.ymlの設定
config.database.yml
設定に合わせてDBとUSER作成
$ createdb sendgrid_development
$ createdb sendgrid_production
$ createuser xxxxxx
development用の環境をマイグレーションする
$ rails db:migrate RAILS_ENV=development
作ったDBの確認
$ psql -l
Name | Owner | Encoding | Collate | Ctype | Access privileges
----------------------+-------------+----------+-------------+-------------+-----------------------------
postgres | <ユーザー名>| UTF8 | en_US.UTF-8 | en_US.UTF-8 |
sendgrid_development | <ユーザー名> | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
sendgrid_production |<ユーザー名> | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
PG CommanderでDBの中身を確認
インストールする
https://eggerapps.at/pgcommander/
アプリを開いて設定
Nickname: 自分が分かればOK。アプリの名前とか
Host: localhost
User: database.ymlに設定したユーザーネーム
Password: database.ymlに設定したパス
Database: database.ymlに設定したdatabase
Connectをクリックして接続されればOK
Userの作成
$rails generate controller Users new
$rails generate model User name:string email:string
$rails db:migrate
controller/users_controller.rb
models/user.rb
views/users/new.html
config/routes.rb
nameとemailを持ったユーザー登録が出来るようになりました!
SendGridの設定
SendGridに登録(無料)
ReceiveMessageモデルの作成
ReceiveMessageモデルとして受け取ったメールのデータを保管していきます。
$ rails generate model ReceiveMessage from:string subject:string body:text
$ rails g controller ReceiveMessages
$ rails db:migrate
controllers/receive_messages_controller.rb
models/receive_message.rb
views/receive_messages/index.html.erb
メールのデータをDBに直接入れて表示を確認
PG Commanderを開いて左下のNew Rowをクリック
確認用なので適当にデータを入れます。
迷ったらcreated_at, updated_atはフォームの右端をクリックして今日の日付を入れればOKです。
http://localhost:3000/receive_messagesを開くとこんな感じ
今は直接DBにデータを入れましたが、ここからメールを受信したら自動的に一覧に表示されるようにしていきます。
GitHubとHerokuにPush
$ git add -A
$ git commit -m "add: receive_messages"
$ heroku run rails db:migrate
HerokuとPostgreSQLを接続
$ heroku pg:psql
テーブルを確認
<herokuのアプリ名>::DATABASE=> select * from receive_messages;
id | from | subject | body | created_at | updated_at
----+------+---------+------+------------+------------
(0 rows)
空っぽなのでこちらにも手動でデータを入れます。
Heroku用のDBをPG Commanderに接続
Herokuのダッシュボードから現在のアプリケーション→Resources→Heroku Postgres :: Database→Settings→View Credentials
ここに載っている情報をPG Commanderに入力します。
登録できたら同様にPG Commanderからデータを手で入力、保存します。
自分のドメインをSendGridで使えるようにする
SendGridのDomain Whitelabel設定
SendGridを受信用サーバーとして扱うために、SendGridがユーザー(自分)から許可を得てメールの受信をしているという証明が必要となります。
SendGrid公式の解説が詳しいので詳しくはこちらをどうぞ(お名前ドットコムが例で使われています)
https://sendgrid.kke.co.jp/docs/Tutorials/D_Improve_Deliverability/using_whitelabel.html
流れとしては
① Sender Authentication画面で2つの質問に答える
1.の質問はお名前.comを利用している場合は何も選択せず、2.はNoを選びましょう。
② 自分が取得したドメイン名を入力
右側のプレビューの@より後ろが自分のドメイン名になっていればOK。Advanced Settingは不要です。
③ 設定に必要なDNSのレコードが3つ生成される
これらをお名前.com画面でCNAMEレコードとして登録するとSendGridは自分のドメイン宛のメールを受信する許可を得ているという証明になります。
SendGridは開いたまま、お名前.comの「DNSレコード設定」を開いてこれらのCNAMEレコードを設定します。
ホスト名→SendGridからコピー
TYPE→CNAME
TTL→3600
VALUE→SendGridからコピー
ちなみにSendGrid上ではHOSTをコピーするとドメイン名まで丸ごとコピーされますが、お名前.comの画面では自分のドメイン名はあらかじめ入力されているのでコピペするときは注意しましょう。
④ 同じ画面でMXレコードも登録。
ホスト名→自分のドメイン
TYPE→MX
TTL→3600
VALUE→mx.sendgrid.net
全て登録するとこんな感じです。
DNSレコード
サーバーがフルサービスリゾルバ(DNSキャッシュサーバー)にIPアドレスとドメイン名の紐付けについて問い合わせた際、フルサービスリゾルバはさらに権威DNSサーバーに問い合わせます。この際、権威DNSサーバーが自分が管理するドメイン名のDNSレコードを見て応答します。
DNSレコードにはMXレコード、Aレコード、CNAMEレコードなどが含まれます。
MXレコード
ドメイン名と配送先のメールサーバーが書かれています。複数のメールサーバーが指定されているときは"IN MX.."に続く数字が小さい方が優先です。
Aレコード
ドメイン名とそれに対するIPアドレスが書かれています。
CNAMEレコード
ドメイン名とそれに対する別名のドメイン名(あだ名)が書かれています。
④ DNSレコードを登録したら"Verify"を押して、情報が正しく入力されていることを確認します。5分ほどかかったので、黄色の文字でエラーが出るときは何度かVerifyを押してみるとよいかもしれません。
それでも認証ができない場合はコピペのミスかお名前.com上のTYPEがCNAMEになっているかを再度確認してください。
この画面でVerifyの横に自分のドメイン名が表示されればOK
⑤ Address Whitelistの設定
Mail SettingsのAddress WhitelistをONにして自分のドメインを設定する
ngrokの設定
SendGridから受信したメールをHTTPでPOSTしてもらう際には一意のURLを用意してエンドポイントを作る必要があります。
最終的にはHerokuのアドレスにPOSTしますが、開発環境でもngrokを使えば確認が可能です。
ngrokとは
ローカルホストで実行されている内容を...ngrok.ioのアドレスで外部に公開できるサービス。
↑この記事がとても分かりやすいのでここに従いダウンロードと設定を行います。
ちなみにこの記事の「nginxのインストール」の後にngrokのインストールも必要な場合があります。
nginxの起動後に$ ngrok http <自分が現在作業中のローカルホストのポート番号>を入力して"ngrok: command not found"と言われた場合は
$ brew install ngrok
もしくは
$ brew cask install ngrok
でngrokをインストールしましょう。
brew caskはhomebrewの拡張であるhomebrew-caskのコマンドです。homebrew-caskを使うとgoogle-chromeなどのアプリケーションもターミナル上でコマンドにより管理が可能です。
準備が完了したら、現在ローカルホストは3000なので
$ ngrok http 3000
と入力すると..
このForwardingに続くURLでローカルホストの内容が公開されています。
では先程作ったメール一覧画面にアクセスすると...
ローカルの内容に外部からアクセスできるようになりました!!
では"....ngrok.io/receive_messages/create"のエンドポイントを作り、ここに受信したメールのデータをPOSTするしてもらいましょう。
ちなみにこのngrok.ioのURLはngrokを再起動する度に変わってしまうので注意してください。
エンドポイントの設定
エンドポイント
APIにアクセスするためのURLのこと。今回はParse Webhook APIを使い、あらかじめ決めたエンドポイント(.../receive_messages/create)にJSON形式にメール情報をPOSTしてもらいます。POSTされた情報の処理はreceive_messagesコントローラーのcreateアクションに書いていきます。
Inbound Paeseの設定
ダッシュボードのSettings→Inbound Parseを選択
Add Host & URLから先程Domain Whitelabel設定をしたドメインが選択できるので入力
subdomain...空欄
Domain...Whitelabelに設定したドメインが選択肢に出てくるので選択
Destination URL...エンドポイントを入力
エンドポイントを作る
これでSendGridに登録されたドメイン宛にメールが来たらエンドポイント(.../receive_messages/create)にJSON形式にメール情報をPOSTされるようになりました。
POSTされた情報の処理をreceive_messagesコントローラーのcreateアクションに書いていきます。
config/routes.rb
controllers/receive_messages.rb
届いたメールの本文、差出人などの情報がJSONに含まれています。メールが届く度に新しいReceiveMessageモデルを作成して取り出したデータをDBに保管していきます。
この部分はクロスサイトリクエストフォージェリ(CSRF)の対策用にあらかじめRailsに組み込まれている設定を無効にするコードです。
クロスサイトリクエストフォージェリと必須セキュリティトークン
ログインが必要なサイトなどでcookieベースのセッションを使用している場合、ブラウザはリクエストを送信する度にcookieも自動的に送信しています。これを利用して別のサイトからのリクエストをユーザーが閲覧しているサイトに仕込み、別のサイトへのリクエストに対してもcookieを送信させるのがクロスサイトリクエストフォージェリです。
これに対してRailsは必須セキュリティトークンというそのサイトしか知らないトークンを生成してトークンに含めています。リクエストが正しいサイトから送信されているかは必須セキュリティトークンの有無で判断が可能です。
そのためSendGridなど外部のサイトからPOSTリクエストを送信した場合、必須セキュリティトークンを含まないためエラーが発生します。これを防ぐために"protect_from_forgery except: :create"と書くことでReceiveMessageControllerのcreateアクションにおけるリクエストでは必須セキュリティトークンが不要となります。
メール送信してみよう!
さっそく先程設定したドメイン宛にメールを送信してみます。
届いた!!
ちなみにメール送信したのに届かない場合はSendGridのActivity Feedを確認しましょう。
Activity Feedに「Parse」とドメイン名が書かれていればSendGridまではメールが到達していることが確認できるので、ターミナル上でエラーを確認すると良いかもしれません。ここにも表示されていない場合はSendGridにも届いていないのでMXレコードなどを確認してください。
GitHubとHerokuへデプロイ
ここは先程と同じです
$ git add -A
$ git commit -m 'Receive Email'
$ git push
$ git heroku push
SengGridにHerokuを登録
このままでは送信されたメールが全てローカルにPOSTされます。
そこで、Send GridのInbound Parse画面から今度はHerokuのアドレスをPOST先に設定しましょう。
では再度メールを送信!
Herokuのアプリ上でメールを受信できました!!
これでSendGridを使ってRailsアプリ上でメールを受信できるようになりました。
今回はメールの受信ボックスをイメージして、件名と差出人のみ表示してみました。ここから件名をクリックするとメール全文が表示されたり、差出人ごとにボックスを分けたりと工夫してみてください。