SendGridとは
sendgirdはメールのインフラサービスです。SaaSっぽいです。
従来はメールを送るにはsmtpサーバーを立ててとか結構面倒なことがいっぱいあるらしいです。(わたしは自分で用意したことないのでありがたみが分からず)
にも関わらず、メールが相手に届かないことも20%ほどはあるらしいです。(^_^;)
ビジネスだと大きな機会損失につながりますね。
なので、面倒なことと、機会損失を取っ払ってくれるのが、sendgridだと認識しています。👏
導入背景
パスワードを忘れた人向けに、「パスワード忘れました」ボタンを押せば自動でメールが配信されるようにしたい。
でも事情があってソースコードは共有できないので、ここでは「公式ページ RubyonRailsでメールを送信」を参考に導入方法を記載しています。参考というかほぼそれ、、、、笑
環境
Ruby 2.4.2
Rails 5.2.1
MacOS Mojave
導入方法
railsだとactionmailerを使って導入します。まずはmailerクラスを生成します。
$ 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にメソッドを追記する
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を生成する。これがメールとして届く文書になる。
<h1> <%= @user.name %> 様、ご連絡いただきありがとうございます。</h1>
<p>パスワードを配信するまで少々お時間がかかります。もうしばらくお待ちください。</p>
user_mailer.rbに記載した send_signup_email
をコールする必要があるため、アクションにdelverメソッドを記載する。
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に以下を記載
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アクションが実行されても、なぜかメールが届かなくて、コンソールで確認したら以下のようなエラーが発生していた。
$ @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.
わけわかめと思いながら、色々調べているとこちらにたどり着き、最終的に
OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES rails s
を実行すればいけました。
その前に、bash_profileの中に export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
も記載しました。この辺良く分かってないです。
原因はMacOS上のruby特有の汎用的なエラーであること、また解決方法としてはOBJC_DISABLE_INITIALIZE_FORK_SAFETYという環境変数をyesで設定すれば良いと書いてありました。
最後に
本当はsendgridのwebAPIが公開されているので、こちらで実装したかったのですが(推奨されている)、エラーに悩まされて、自分の力では解決できず、公式ページを参考に直接コードを書いて実装しました。
今までactionmailerも環境変数も勉強してこなかったので、非常に勉強になりました。sendegrid便利!!なはず笑
参考
sendgrid公式ページ、Ruby on Railsで送信する。
Not work on macOS Mojave: may have been in progress in another thread when fork() was called.
Ruby on Railsで環境変数を設定する
NSPlaceholderDictionary initialize~というエラーが出て、railsがクラッシュする。