1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby on RailsでSendgrid(Web API)メール送信を実装

Posted at

業務でSendgridのSMTPを用いてメールをユーザー宛に送信していたが、送信されるメール毎にカテゴリーを付与し、コンバージョン率を調査したいとの社内マーケからの要望を受けた。

そのため、SMTPでカテゴリーを付与しようとしたが、カテゴリー設定がSMTPではできないことが判明し、Web APIにて実装しようと思ったところ、意外と参考文献が少なかったので備忘録も兼ねて記事とした🚬
ちなむと今回は、Web APIを用いてメール送信するところが難所なのではなく、カテゴリー付与するところで詰まりました。

また、今回APIの呼び出しに使用したのはsendgrid-rubyというgemである。

SendgridのAPI取得

APIの取得に関しては公式ドキュメントを参照して取得して欲しい。
メール送信など単純な使用目的で取得する場合はfull accessを選択してAPI生成すれば問題なし✌️

コード実装

ここからの実装の流れは以下2つの記事を参照した。

最終的なコード

RailsはデフォでAction Mailer(smtp)を使用するので、新規でdelivery methodを追加してあげる。

今回実装したファイルは以下。

# config/initializers/sendgrid.rb

ActionMailer::Base.add_delivery_method :sendgrid, Mail::SendGrid,
  api_key: Settings.sendgrid_api #settings.local.ymlの中にあるAPIキーを呼び出す。
# app/mailers/application_mailer.rb

class ApplicationMailer < ActionMailer::Base
  def set_sendgrid_settings(category)
    ActionMailer::Base.delivery_method = :sendgrid
    headers['category'] = category
  end
end
# lib/mail/send_grid.rb

class Mail::SendGrid
  def initialize(settings)
    @settings = settings
  end

  def deliver!(mail)
    sg_mail = set_mail_information(mail)
    add_content_and_category(sg_mail, mail)
    sg = SendGrid::API.new(api_key: @settings[:api_key])
    sg.client.mail._('send').post(request_body: sg_mail.to_json)
  end

  private

    def set_mail_information(mail)
      from = SendGrid::Email.new(email: mail.from.first)
      to = SendGrid::Email.new(email: mail.to.first)
      subject = mail.subject
      content = SendGrid::Content.new(type: 'text/plain', value: mail.body.parts[0].body.raw_source)
      SendGrid::Mail.new(from, subject, to, content)
    end

    def add_content_and_category(sg_mail, mail)
      sg_mail.add_content(SendGrid::Content.new(type: 'text/html', value: mail.body.parts[1].body.raw_source))
      sg_mail.add_category(SendGrid::Category.new(name: mail[:category].value))
    end
end

メールが送られるまでの流れ

  • app/mailers/application_mailer.rbで定義したメソッドset_sendgrid_settings('カテゴリー名')をmailerファイルの中で呼び出す。

例 )

以下test_mailer.rbのアクション内で定義したset_sendgrid_settings('カテゴリー名')を呼び出すことで、「test_mailerメソッドのdelivery_methodはsendgridのWeb APIを通して送信しますよ。」と指示する。
※引数でカテゴリー名を渡すことで、sendgridへカテゴリー名も付与することができる。

# app/mailers/test_mailer.rb
class TestMailer < ApplicationMailer
  def test_mail
    set_sendgrid_settings('This is test category')
    mail(from: 'from@example.com', to: 'to@example.com', subject: 'テストメール')     
  end
end
# app/views/test_mailer/test_mail.text.erb
SendGrid送信テスト

  • set_sendgrid_settings('カテゴリー名')によって、lib/mail/send_grid.rbで定義したdeliver!メソッドが使用できる。

以下のinitializeによって、config/initializers/sendgrid.rbが呼び出されAPIを使用することができ、@settingsにAPIキーが代入される。

# lib/mail/send_grid.rb
class Mail::SendGrid

  def initialize(settings)
    @settings = settings
  end
~

  • mailerから渡ってきたmail変数をsendgrid-rubyの所定のフォーマットに則って代入する。

以下のset_mail_information(mail)プライベートメソッドにてgemのフォーマットに則って代入する。
SendGrid::Email.new()はgem特有のもの。詳しくは公式まで。

# lib/mail/send_grid.rb
class Mail::SendGrid

~

  private

    def set_mail_information(mail)
      from = SendGrid::Email.new(email: mail.from.first)
      to = SendGrid::Email.new(email: mail.to.first)
      subject = mail.subject
      content = SendGrid::Content.new(type: 'text/plain', value: mail.body.parts[0].body.raw_source)
      SendGrid::Mail.new(from, subject, to, content)
    end

~

以上の流れでメールは送信できる。


詰まった問題点

そもそも業務でsendgridを使用しているので、text/plain形式だけではなく、html形式のメールも送信するマルチパートメールを採用している。(というかどこの企業もそうだと思うが…)

上記までだと、text/plain形式のメールだけしか送れず、なんならhtml.erbファイルもある場合はエラーが出て送信できない。

あと、カテゴリーに関してもaction mailerのMail::Messageに含まれる引数しか渡せないため、独自に変数を渡すことは不可能だったので、別の方法で実装するしかなかった。

  • マルチパートメールどうやって送るの?
  • カテゴリー名どうやって付与するねん…

解決方法

結論、gemの特性なのか知らないが、先にtext/plain形式のメールを指定しなければならないらしい。なので、html形式はadd_categoryというgemのメソッドを使用して追加することに成功した。

カテゴリーは、mailerのactionごとに指定したい場合には、header[:category]として含める必要があることがわかった。
※カテゴリー名はUS-ASCII文字セットのみ対応(日本語不可)ということにも注意。

該当箇所

html形式のメールはmail.body.partsの2番目に含まれているので、mail.body.parts[1]で指定してあげる。(1番目に格納されているのはtext/plain形式。)

# lib/mail/send_grid.rb

class Mail::SendGrid

~

    def add_content_and_category(sg_mail, mail)
      sg_mail.add_content(SendGrid::Content.new(type: 'text/html', value: mail.body.parts[1].body.raw_source))
      sg_mail.add_category(SendGrid::Category.new(name: mail[:category].value))
    end
end

以上でmailerのアクション毎にカテゴリー名を付与した上で、Web APIを経由しメール送信することが可能になった。

Sengridのダッシュボード上でもカテゴリー分け毎のコンバージョン率も確認できて、Webマーケからも感謝されました。めでたしめでたし。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?