RailsとHerokuを利用してメールを自動的に定期配信する

Railsで作成したApplicationで、Mailをある条件で自動的に発行したかったので、その時の実装したことのメモです。
(※ 例. 誕生日におめでとうMailを自動的に送信する･･･等)
本番環境は、Herokuを利用してデプロイしました。

仮のサンプルアプリケーションを作成する要領でメモします。

#環境
- Ruby 2.4.1
- Rails 5.0.6
- Heroku
    - SendGrid(※ Mailを送信する為に使用したHerokuのadd-on)
    - Heroku Scheduler(※ Herokuでrakeタスクを定期的に実行させる為にadd-on)

## 仮定
朝10:00にUserモデルに登録されているユーザー1人1人に

「Hello, *user name*!!]」

とMailを送ってくれるアプリをつくってみます。

## 1. Railsアプリケーションを作成

```bash
$ rails new sample_application
```
## 2. Modelをつくる
*name*と*email*というcolumnを持つModelを作成します。

```bash
$ rails g model user name:string email:string
```
db:migrateします。

```bash
$ rails db:migrate
```
こんな感じのschemaファイルになるかと思います。

```rb:db/schema.rb
# 省略
create_table "users", force: :cascade do |t|
  t.string 'name'
  t.string 'email', 
end
# 省略
```

## 3. サンプルユーザーを作成
(※ 本題とはあまり関係のない内容になります。)
User Modelに登録が1名もいないとイメージが湧かないので3名くらい登録しようと思います。
FakerというGemを利用します。

```rb:Gemfile
group :development, :test do
  # 省略
  # 省略
  gem 'faker'
end
```
をGemfileに追加します。
※ 本番環境ではサンプルは必要無いかと思うのでgroupで制限をしています。

```
$ bundle install
```
bundle installしてgemを利用できるようにします。

```rb:db/seeds.rb
3.times do
  User.create!(name: Faker::Name.name, email: Faker::Internet.email)
end
```
seeds.rbファイルに上記の感じで3名、ユーザーを作ります。

```
$ rails db:seed
```
これで開発環境で3名のサンプルユーザーが登録されたかと思います。

## 4. Mailerをつくる
定期配信するMailをActionMailerで実装します。今回の名前は、"UserMailer"にして*#say_hello*というメソッドでメールを送れるようにしようと思います。

```bash
rails g mailer UserMailer say_hello
```
上記、ジェネレーターで生成されたファイルを調整します。

```rb:app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer

  def say_hello(user)
    @user = user

    mail to: "#{@user.email}", subject: "Hello, #{@user.name}"
  end
end
```

```erb:app/views/user_mailer/say_hello.html.erb
<h1>Hello, <%= @user.name %>!!</h1>
```

```erb:app/views/user_mailer/say_hello.text.erb
Hello, <%= @user.name %>
```
ジェネレーターで作成されている*test/mailers/previews/user_mailer_preview.rb*ファイルのコメントアウトされているURLをrails serverを起動し、ブラウザのアドレスバーに貼り付ければ送信するメール本文のプレビューが出来るのでおすすめです。

```rb:test/mailers/previews/user_mailer_preview.rb
# Preview all emails at http://localhost:3000/rails/mailers/user_mailer
class UserMailerPreview < ActionMailer::Preview

  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/say_hello
  def say_hello
    UserMailer.say_hello(User.first)
  end

end
```
![quita_say_hello.png](https://qiita-image-store.s3.amazonaws.com/0/67173/9690cd87-77c9-d8cb-b8ea-dacc2cff668e.png)

## 5. Rakeタスクをつくる
Mailを送信する為のRakeタスクを作ります。
名前空間は、*greeting*にします。

```
$ rails g task greeting
```
上記、ジェネレーターで自動生成されたファイルにタスクを記述します。

```rb:lib/tasks/greeting.rake
namespace :greeting do
  desc '挨拶するメールを発行する。'
  task say_hello: :environment do
    users = User.all

    users.each do |user|
      UserMailer.say_hello(user).deliver
    end
  end
end
```
これで、後は、Herokuへデプロイし、Herokuのアドオンを利用して上記、rake taskを定期的に走らせればメールが自動的に定期配信されます。

## 6. Herokuへのデプロイ
Herokuへのデプロイする為にとりあえずGitを利用します。

```
$ git init
$ git add .
$ git commit -m 'sample application'
```
とりあえず、上記でGitのmasterブランチにコミットします。

Herokuでは、PostgreSQLを使用するので、本番環境に*pg gem*をインストールします。また、*sqlite3 gem*が本番環境に導入されないように気をつけます。

```rb:Gemfile
# 省略
group :development, :test do
  # 省略
  gem 'faker'
  gem 'sqlite3' # <- ここのgroup内に移動させたかたいです。
end

# 省略

group :production do
  gem 'pg'
end
# 省略
```
上記、Gemfileに追加したら*--without production*オプションをつけて*bundle install*します。
本番用のgemをローカル環境にはインストールしないためです。

```
$ bundle install --without production
```
Gitを更新します。

```
$ git commit -a -m 'update Gemfile for Heroku'
```

*Heroku create*コマンドを事項してSample_applicationの実行場所を作成します。
※ HerokuのCLIのインストールは完了しているものとします。

```
$ heroku create
```
そして、デプロイします。

```
$ git push master
```
本番環境での*db:migrate*を実行します。

```
$ heroku run rails db:migrate
```
これで、Herokuへのデプロイ完了です。

## 7. HerokuのアドオンSendGridを追加
Herokuのアドオンのひとつ"SendGrid"を利用して本番環境でメールの送信をおこなえるようにします。
※SendGridの利用にはクレジットカードの登録が必要になりますが、メール数が一定数までは無料で利用できます。

```
$ heroku addons:create sendgrid:starter
```
Railsの本番用のconfigファイルに情報を記入します。

```rb:config/environments/production.rb
Rails.application.configure do
# 省略
config.action_mailer.raise_delivery_errors = true
↓↓↓↓↓↓↓ あなたの記事の内容
  config.action_mailer.delivery_method       = :smtp
───────
  config.action_mailer.delicery_method       = :smtp
↑↑↑↑↑↑↑ 編集リクエストの内容
  config.action_mailer.default_url_options   = { host: '<Herokuのアプリ名>.herokuapp.com' }
  ActionMailer::Base.smtp_settings           = {
      address:              'smtp.sendgrid.net',
      port:                 '587',
      authentication:       :plain,
      user_name:            ENV['SENDGRID_USERNAME'],
      password:             ENV['SENDGRID_PASSWORD'],
      domain:               'heroku.com',
      enable_starttls_auto: true
  }
# 省略
end
```
上記、設定が完了したらgit commitしてHerokuへpushします。

```
$ git commit -a -m 'Send Grid setting'
$ git push heroku master
```
以上で、SendGridを利用してメールを送信できるようにしました。

## 8. HerokuのアドオンHeroku Schedulerを追加してrakeタスクを実行させる

Herokuのアドオン"Heroku Scheduler"を利用すれば、設定した時間にrakeタスクを実行させることができます。
※ Schedulerの利用にもクレジットカードの登録が必要です。一定までは無料で利用できるようですが、Dyonsがworkerである必要があるようです。

HerokuにHeroku Schedulerを追加します。

```
$ heroku addons:create scheduler:standard
```

Schedulerに実行するrakeタスクと時間を設定します。
下記コマンドを実行することでブラウザで設定画面が立ち上がります。

```
$ heroku addons:open scheduler
```
![Screenshot-2017-9-30 Heroku Scheduler.png](https://qiita-image-store.s3.amazonaws.com/0/67173/6369e6ea-6167-ef62-033c-60c0065eb4bd.png)

- 実行するコマンド: bundle exec rake greetig:say_hello
- FREQUENCY: Daily
- NEXT DUE: 1:00  
  ※ Heroku Schedulerは、UTC「世界協定」の時間になります。日は、9時間早く進んでいる為、設定したい時間より9時間引いた時間をセットすることになります。

上記を設定して"Save"実行。

これで、rakeタスクが定期的に実行され毎朝メールを送信することができました。

### 参照
- [neutligenの日記 開発のわだち（９）：リマインダメールを実装](http://neutligen.hatenadiary.com/entry/2016/04/27/225324#chap_2)
- [OneDay Railsでメール配信してみる。　Action Mailer](http://nograve.hatenadiary.jp/entry/2015/10/30/162526)
- [RailsでRakeタスクの作成](https://qiita.com/suzuki_koya/items/787b5562d2ae1a215d94)
- [Ruby on Rails チュートリアル](https://railstutorial.jp/)