actionmailer/rake/wheneverを使ってメールの定期配信を実現

# 今回やりたいこと
rakeとwheneverについては、以下の記事で説明しています。

https://qiita.com/F_Yoko/items/e751fe0b38601ca06cb3

また、actionmailerについても、以下の記事で説明しています。

https://qiita.com/F_Yoko/items/afdb07b166a635f6d179

今回はこれらを組み合わせてメールの定期配信を実現したいと思います。
具体的には朝の９時にユーザーに対して「hello」とメールが送られるようにしたいと思います。

では、いきましょう！


# mailerを準備
まずは、mailerの準備からやっていきましょう。
mailerの名前は何でもいいですが、わかりやすくGoodMorningとしておきましょうか。
```
rails g mailer GoodMorning      
      create  app/mailers/good_morning_mailer.rb
      invoke  haml
      create    app/views/good_morning_mailer
      create    app/views/layouts/mailer.text.haml
      create    app/views/layouts/mailer.html.haml
      invoke  test_unit
      create    test/mailers/good_morning_mailer_test.rb
      create    test/mailers/previews/good_morning_mailer_preview.rb
```
## クラスにメソッドを定義
では、以下のように簡単に宛先を記述しましょう。今回は、userを引数で渡す形にしたいと思います。

```app/mailers/good_morning_mailer.rb
class GoodMorningMailer < ApplicationMailer
  def good_morning(user)
    mail to: user.email, subject: 'good morning!!'
  end
end
```
## メール内容を編集
では、次に送るメールの内容を編集していきましょう。
以下のディレクトリとファイルを作成して、
```app/views/good_morning_mailer/good_morning.html.haml
!!!
%html
  %head
    %meta{ 'http-equiv': 'Content-Type', content: 'text/html; charset=utf-8' }
    %style{ type: 'text/css' }
      /* Email styles need to be inline */
  %body
    = hello
```

必要に応じて'good_morning.text.haml'も編集してください。

ここまでできたら、railsコンソールを立ち上げて、メールが送れるか確認してみましょう。
前提条件として、ユーザーは既に作成しています。最初に紹介したactionmailerの記事を見てください。メール設定などもこちらに書いているので、確認をお願いします。

```
user = User.first
GoodMorningMailer.good_morning(user).deliver_now
```

すると、以下のようなメールが送られてきます。
![IMG_F90493EF5A75-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324306/097cffa6-04af-4db8-aa01-ca2f2c83374d.jpeg)

無事メールは送れたので、次はこれを自動化できるようにしていきます。

余談ですが、
deliver_nowは同期的な送信方法で、delver_laterは非同期の送信方法です。
rails4.2まではdeliverメソッドがありましたが、4.2からは非推奨、rails5以降は使用できないので注意しましょう。

## rakeタスク
:::note 
rakeタスクとは
Rubyプログラムを自動化するためのフレームワークであるrakeを使って定義された、Railsアプリケーションで利用できるコマンドラインのタスクのことを指します。rakeタスクを作成することで、例えばデータベースの初期化や定期的なバッチ処理、ファイルの生成や削除などの定型的な作業を簡単に自動化することができます。
:::

要は、このタスクを作成して、作業を自動化できるようになるわけですね。
したがって、メール送信のためのタスクを今回は作成していきます。

# task作成
以下のように実行するとタスクを作成できます。
```
rails generate task good_morning
```
すると、lib配下のtasksディレクトリにgood_morningタスクが作成されます。
ちなみにtasks配下にディレクトリを作成してその中に作成することもできるので、状況に合わせて作成してください。
```
lib/tasks/good_morning.rake
```

このファイルを開いてみると、以下のようになっています。
```lib/tasks/good_morning.rake
namespace :good_morning do
end
```

tasks直下の場合は`namespace`はなくても構いませんが、今後さらに増えるのであればnamespaceをつけておく方が衝突を避けられるので無難だと思います。

:::note
namespaceを作成すると、その名前空間内でタスクをまとめることができ、`rake namespace_name:task_name`のように呼び出すことができます。

一方で、namespaceを作成しない場合は、`rake task_name`で直接タスクを呼び出すことができます。
:::

## rakeファイルの編集
話がそれましたが、作成したrakeファイルを編集していきましょう。
とは言っても今回の場合は簡単で、以下のように書きます。
テストなので`user = User.first`にしておきます。

```lib/tasks/good_morning.rake
namespace :good_morning do
  desc '朝の9時になったらユーザーにおはようメールを送信'
  task good_morning_task: :environment do
    user = User.first
    GoodMorningMailer.good_morning(user).deliver_now
  end
end
```

では、これをコンソールで呼び出してみます。
namespaceを使用しているので`rake good_morning:good_morning_task`で呼び出せるはずです。
ちなみに、`rake -T`でrakeタスクの一覧も見れます。


# wheneverで定期実行
最後にこのrakeタスクをwheneverで定期実行していきましょう。
wheneverは、時間に応じてタスクやコマンドを実行できるようにするgemの１つです。
例えば、朝の９時に実行するとか１週間ごとに実行するとかを設定できます。

こちらも冒頭の記事で説明していますが、要点だけ。

以下のgemをインストールして、`wheneverize .`を実行すると、`config/schedule.rb`が作成されます。
```
gem 'whenever', require: false
```

最初は全てコメントアウトされていますが、具体例が書かれているのでそちらを真似して書いていくこともできます。

今回は朝の9時に定期実行したいので、先ほどコンソールで送れることを確認したrakeタスクを記述します。
以下のように書くと、毎朝９時にrakeタスクを実行することができます。

余談ですが、`タスク名をクオーテーションで囲まないとエラーが出ます。`

```config/schedule.rb
every 1.day, at: '9am' do
  rake 'good_morning:good_morning_task'
end
```

これが終わったら以下のコマンドを実行しましょう。
```
# wheneverの設定更新
bundle exec whenever --update-crontab   
# 設定内容にエラーが無いか確認
bundle exec whenever  
```

次にきちんと設定できたかは以下のコマンドで確認できます。
```
# 設定されているcronを確認
crontab -l  
```

設定を削除する場合は以下のコマンドです。
```
# crontabの設定を削除
bundle exec whenever --clear-crontab  
```

# まとめ
以上がメールの定期配信の実現でした。
基本的な使い方は難しくありませんでしたが、複雑なことをしようとすると難しくなりそうですね。
また別の定期実行したいことが出てきたら記事にしたいと思います。