sendgridを使ってメールを送信 Rails

## SendGridとは
sendgirdはメールのインフラサービスです。SaaSっぽいです。
従来はメールを送るにはsmtpサーバーを立ててとか結構面倒なことがいっぱいあるらしいです。（わたしは自分で用意したことないのでありがたみが分からず）
にも関わらず、メールが相手に届かないことも20%ほどはあるらしいです。(^_^;)
ビジネスだと大きな機会損失につながりますね。
なので、面倒なことと、機会損失を取っ払ってくれるのが、sendgridだと認識しています。👏

![sendgrid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417196/9857e28f-caa6-7e09-8d38-bb1bab8af4b8.png)

## 導入背景
パスワードを忘れた人向けに、「パスワード忘れました」ボタンを押せば自動でメールが配信されるようにしたい。
でも事情があってソースコードは共有できないので、ここでは[「公式ページ RubyonRailsでメールを送信」](https://sendgrid.kke.co.jp/docs/Integrate/Frameworks/rubyonrails.html)を参考に導入方法を記載しています。参考というかほぼそれ、、、、笑

## 環境
Ruby 2.4.2
Rails 5.2.1
MacOS Mojave

## 導入方法
railsだとactionmailerを使って導入します。まずはmailerクラスを生成します。

```terminal
$ rails generate mailer User
Running via Spring preloader in process 7688
      create  app/mailers/user_mailer.rb
      invoke  erb
      create    app/views/user_mailer
      invoke  test_unit
      create    test/mailers/user_mailer_test.rb
      create    test/mailers/previews/user_mailer_preview.rb
```
 mailerのuser_mailer.rbにメソッドを追記する

```rb:app/mailers/user_mailer.rb 
class UserMailer < ActionMailer::Base
  default :from => 'any_from_address@example.com'

 # ここから下を追記 このメソッドが呼び出されると @user.emailにメールが送信される
  def send_signup_email(user)
    @user = user
    mail( :to => @user.email,
    :subject => 'Thanks for signing up for our amazing app' )
  end
end
```

アクションとHTML出力に対応したViewを生成する。これがメールとして届く文書になる。
  

```rb:app/views/user_mailer/send_signup_email.erb 

    <h1> <%= @user.name %>　様、ご連絡いただきありがとうございます。</h1>
    <p>パスワードを配信するまで少々お時間がかかります。もうしばらくお待ちください。</p>
```

user_mailer.rbに記載した `send_signup_email` を**コールする必要がある**ため、アクションにdelverメソッドを記載する。


```rb:app/controllers/users_controller.rb
class UsersController < ApplicationController
  def create
    # Create the user from params
    @user = User.new(params[:user])
    if @user.save
      # ↓の一文でuser_mailer.rbのsend_signup_emailがコールされメールが送信される
      UserMailer.send_signup_email(@user).deliver
    end
  end
end
```

最後に、sendgridを使用するためのactionmailerを設定する。
config/enviroment.rbに以下を記載

```rb:config/environment.rb 
ActionMailer::Base.smtp_settings = {
  :user_name => 'your_sendgrid_username',
  :password => 'your_sendgrid_password',
  :domain => 'yourdomain.com',
  :address => 'smtp.sendgrid.net',
  :port => 587,
  :authentication => :plain,
  :enable_starttls_auto => true
}
```
user_nameはsendgridに登録した時に与えられる。
passwordはsendgridに登録する時に自分で設定するやつ。
domainは自分は指定しなくてよかったので、test.comとかにしといた。練習用とかだったら、yourdomain.comのままで良さそう。
あとは触らなくて大丈夫。

これで、userをcreateアクションが実行されれば、sendgridを通じてメールは送信できるようになる。

## 環境変数を設定する
もちろんこのままgithubにあげたりすると、enviroment.rbに記載しているパスワードやuser_nameがダダ漏れなので、環境変数に入れてあげます。


## ハマったポイント
createアクションが実行されても、なぜかメールが届かなくて、コンソールで確認したら以下のようなエラーが発生していた。

```terminal
$ @user = User.create(name:〇〇,email:〇〇)
$ UserMailer.send_signup_email(@user).deliver
Rendering user_mailer/send_signup_email.html.erb within layouts/mailer
  Rendered user_mailer/send_signup_email.html.erb within layouts/mailer (0.6ms)
UserMailer#send_signup_email: processed outbound mail in 387.6ms
objc[5386]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called.
objc[5386]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
```

わけわかめと思いながら、色々調べていると[こちら](https://github.com/darkskyapp/forecast-ruby/issues/13)にたどり着き、最終的に
`OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES rails s`を実行すればいけました。
その前に、bash_profileの中に `export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES` も記載しました。この辺良く分かってないです。:thinking:
原因はMacOS上のruby特有の汎用的なエラーであること、また解決方法としてはOBJC_DISABLE_INITIALIZE_FORK_SAFETYという環境変数をyesで設定すれば良いと書いてありました。

## 最後に
本当はsendgridのwebAPIが公開されているので、こちらで実装したかったのですが（推奨されている）、エラーに悩まされて、自分の力では解決できず、公式ページを参考に直接コードを書いて実装しました。
今までactionmailerも環境変数も勉強してこなかったので、非常に勉強になりました。sendegrid便利！！なはず笑

## 参考

[sendgrid公式ページ、Ruby on Railsで送信する。](https://sendgrid.kke.co.jp/docs/Integrate/Frameworks/rubyonrails.html)
[Not work on macOS Mojave: may have been in progress in another thread when fork() was called.](https://github.com/darkskyapp/forecast-ruby/issues/13)
[Ruby on Railsで環境変数を設定する](https://qiita.com/yuichir43705457/items/7cfcae6546876086b849)
[NSPlaceholderDictionary initialize~というエラーが出て、railsがクラッシュする。](https://ja.stackoverflow.com/questions/46886/nsplaceholderdictionary-initialize%E3%81%A8%E3%81%84%E3%81%86%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E5%87%BA%E3%81%A6-rails%E3%81%8C%E3%82%AF%E3%83%A9%E3%83%83%E3%82%B7%E3%83%A5%E3%81%99%E3%82%8B)