Railsでsendgridのmessage_idを取得したい

こんにちは!kossyです!



さて、今回はRailsでsendgridをメール配信サービスとして使用していた時に、
message_idを取得する方法についてブログに残してみたいと思います。




環境
Ruby 2.5.1
Rails 5.2.3
MacOS Mojave




なお、sendgridの設定周りについての説明は割愛します。
configは下記の記事が参考になるかと思います。
https://sendgrid.kke.co.jp/docs/Integrate/Frameworks/rubyonrails.html



ActionMailer::DeliveryJobではなくNet::SMTP::Responseを返り値にする

通常、RailsでActionMailerを使ってメールを送信するときは、
deliver_nowかdeliver_laterを使うと思いますが、
https://edgeapi.rubyonrails.org/classes/ActionMailer/MessageDelivery.html

上記2つのメソッドでメールを送信した場合、返り値がActionMailer::DeliveryJobになります。

これだと、sendgridのmessage_idを受け取ることができないので、
smtp_configと実行するメソッドを変更する必要があります。

まずは config/environment/各環境のenvファイル のsmtpのセッティングを変更します。

  config.action_mailer.smtp_settings = {
    user_name: ENV['sendgrid_user_name'],
    password: ENV['sendgrid_password'],
    domain: 'hogehoge.com',
    address: 'smtp.sendgrid.net',
    port: 587,
    authentication: :plain,
    enable_starttls_auto: true,
    return_response: true # 追加
  }

return_responseをtrueにすると、サーバーからのresponseをそのまま返すようになります。

参考: http://aligach.net/diary/20180725.html

mail gem内でreturn_responseの値を見て分岐しているようでした。

github.com




そして、deliver_later(またはdeliver_now)ではなく、deliver_now!を使うようにします。

すると、

response = UserMailer.notify_private_announcement(user).deliver_now!

response.class
=> Net::SMTP::Response

ActionMailer::DeliveryJobではなくNet::SMTP::Responseを返り値にすることができます。

Net::SMTP::Responseインスタンスはattrとして、

response
=> #<Net::SMTP::Response:0x005652f6301890 @status="250", @string="250 Ok: queued as 1dMBeSp6Rj-Uh5TdzJKgmq\n">

statusとstringを持っています。
内、sendgridのmessage_idは、1dMBeSp6Rj-Uh5TdzJKgmq の部分になります。

この文字列を取得するには、

# この書き方なんとかしたい、、、

response.string[18..39]
=> "1dMBeSp6Rj-Uh5TdzJKgmq"

とすることで取得できます。

このmessage_idを取得し、sendgridのEventWebhookのsg_message_idと前方一致させることで、
メールの開封状況を取得することもできるようになります。

EventWebhookについては、
https://sendgrid.kke.co.jp/docs/API_Reference/Webhooks/event.html
https://sendgrid.kke.co.jp/docs/Tutorials/C_Manage_Events/using_event_webhook.html

が参考になるかと思います。