Twilio SendGridライブラリで送信リクエストとレスポンスを取得する方法 ~Ruby編~

Twilio SendGridライブラリで送信リクエストとレスポンスを取得する方法 ~Ruby編~
メール送信リクエストを実行したのに、ActivityEvent Webhookにイベントが記録されていない!という経験はありませんか?イベントが発生しない主な原因として、Twilio SendGridに送信リクエストが届いていない可能性が考えられます。問題が発生した際に原因をしっかり特定できるよう、実際に送ったJSON形式の送信リクエストとそのHTTPレスポンスを必ずログに出力しましょう。

SMTPやWeb APIで送信する場合は、TelnetやcURLなどのツールによって簡単に送信リクエストとレスポンスが取得できるので、チュートリアルをお試しください。今回のブログでは、Ruby向けのSendGridライブラリ(以降、sendgrid-rubyと表記)における取得方法を紹介します。

今回は、Ruby 3.4.4で確認しました。利用したライブラリは以下のとおりです。

  • sendgrid-ruby
  • base64(sendgrid-ruby内部で利用)
  • dotenv(環境変数の管理に利用)

sendgrid-rubyを使った送信処理のサンプルコード

ライブラリはRubyのパッケージ管理ツールであるgemを利用して取得します。

gem install sendgrid-ruby dotenv base64

sendgrid-rubyを使った送信コードは次のとおりです。

require 'sendgrid-ruby'
require 'dotenv/load'
require 'json'
include SendGrid

mail = Mail.new

# 差出人
mail.from = Email.new(email: 'kozotaro@example.com', name: '構造太郎')
# 宛先
personalization = Personalization.new
personalization.add_to(Email.new(email: 'kozohanako@example.com', name: '構造花子'))
mail.add_personalization(personalization)
# 件名
mail.subject = 'Rubyのライブラリを使ったメール送信'
# 本文:テキストパート
mail.add_content(Content.new(
  type: 'text/plain',
  value: <<~TEXT
    構造さん
    お元気ですか。
  TEXT
))
# 本文:HTMLパート
mail.add_content(Content.new(
  type: 'text/html',
  value: <<~HTML
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
    </head>
    <body>
        <p>構造さん</p>
        <p>お元気ですか。</p>
    </body>
    </html>  
  HTML
))

# 送信リクエストの取得
request_body = mail.to_json

puts "----- 送信リクエストを標準出力する -----"
puts JSON.pretty_generate(request_body)

# メールの送信
sg = API.new(api_key: ENV.fetch("SENDGRID_API_KEY"))
response = sg.client.mail._('send').post(request_body: request_body)

puts "----- レスポンスを標準出力する -----"
puts "#{response.status_code}"
puts "----------"
response.headers.each do |key, value|
  puts "#{key}: #{Array(value).join(', ')}"
end
puts "----------"
puts response.body  # 成功時(202)は空

.envファイルにはダッシュボードで作成したAPIキーを定義します。

SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxxxxxxx

送信リクエストとレスポンスを取得する部分を詳しくみていきましょう。

送信リクエストの取得方法

送信リクエストは次の方法で取得できます。


# 送信リクエストの取得
request_body = mail.to_json

puts "----- 送信リクエストを標準出力する -----"
puts JSON.pretty_generate(request_body)

JSON.pretty_generateメソッドで整形して出力すると次のようになります。

----- 送信リクエストを標準出力する -----
{
  "from": {
    "email": "kozotaro@example.com",
    "name": "構造太郎"
  },
  "subject": "Rubyのライブラリを使ったメール送信",
  "personalizations": [
    {
      "to": [
        {
          "email": "kozohanako@example.com",
          "name": "構造花子"
        }
      ]
    }
  ],
  "content": [
    {
      "type": "text/plain",
      "value": "構造さん\nお元気ですか。\n"
    },
    {
      "type": "text/html",
      "value": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1\">\n</head>\n<body>\n    <p>構造さん</p>\n    <p>お元気ですか。</p>\n</body>\n</html>  \n"
    }
  ]
}

続いて、レスポンスを取得する方法について紹介します。

レスポンスの取得方法

送信リクエストに対するレスポンスは次の方法で取得します。

response = sg.client.mail._('send').post(request_body: request_body)

puts "----- レスポンスを標準出力する -----"
puts "#{response.status_code}"
puts "----------"
response.headers.each do |key, value|
  puts "#{key}: #{Array(value).join(', ')}"
end
puts "----------"
puts response.body  # 正常応答時(202)は空

原因を特定する際、特に大事なのはステータスコードとボディの情報です。正常応答(ステータスコードが2xx系)であれば、SendGridに送信リクエストが届いています。レスポンスがエラーの場合(ステータスコードが2xx系以外)は、SendGridに送信リクエストが届いていない、もしくは受け付けられていないので、bodyの「errors」で示されたメッセージをもとに原因を確認しましょう。

正常応答の場合

----- レスポンスを標準出力する -----
202
----------
server: nginx
date: Wed, 27 Aug 2025 05:28:17 GMT
content-length: 0
connection: close
x-message-id: 17yjymcnS3GXcWPjX6kAyA
access-control-allow-origin: https://sendgrid.api-docs.io
access-control-allow-methods: POST
access-control-allow-headers: Authorization, Content-Type, On-behalf-of, x-sg-elas-acl
access-control-max-age: 600
x-no-cors-reason: https://sendgrid.com/docs/Classroom/Basics/API/cors.html
strict-transport-security: max-age=31536000; includeSubDomains
content-security-policy: frame-ancestors 'none'
cache-control: no-cache
x-content-type-options: no-sniff
referrer-policy: strict-origin-when-cross-origin
----------

エラ-の場合(正しくないメールアドレス形式を指定した場合)

----- レスポンスを標準出力する -----
400
----------
server: nginx
date: Wed, 27 Aug 2025 06:07:00 GMT
content-type: application/json
content-length: 204
connection: close
access-control-allow-origin: https://sendgrid.api-docs.io
access-control-allow-methods: POST
access-control-allow-headers: Authorization, Content-Type, On-behalf-of, x-sg-elas-acl
access-control-max-age: 600
x-no-cors-reason: https://sendgrid.com/docs/Classroom/Basics/API/cors.html
strict-transport-security: max-age=31536000; includeSubDomains
content-security-policy: frame-ancestors 'none'
cache-control: no-cache
x-content-type-options: no-sniff
referrer-policy: strict-origin-when-cross-origin
----------
{"errors":[{"message":"Does not contain a valid address.","field":"personalizations.0.to.0.email","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#message.personalizations.to"}]}

エラ-の場合(無効な認証情報が指定された場合)

----- レスポンスを標準出力する -----
401
----------
server: nginx
date: Wed, 27 Aug 2025 06:08:51 GMT
content-type: application/json
content-length: 116
connection: close
access-control-allow-origin: https://sendgrid.api-docs.io
access-control-allow-methods: POST
access-control-allow-headers: Authorization, Content-Type, On-behalf-of, x-sg-elas-acl
access-control-max-age: 600
x-no-cors-reason: https://sendgrid.com/docs/Classroom/Basics/API/cors.html
strict-transport-security: max-age=31536000; includeSubDomains
content-security-policy: frame-ancestors 'none'
cache-control: no-cache
x-content-type-options: no-sniff
referrer-policy: strict-origin-when-cross-origin
----------
{"errors":[{"message":"The provided authorization grant is invalid, expired, or revoked","field":null,"help":null}]}

レスポンスでエラーが返された場合は、送信リクエストに誤りがないかどうか確認しましょう。SendGridが用意するSandboxモードを利用することで、実際にメール送信を行うことなく、リクエストが正しいかどうかの検証ができます。

mail = Mail.new

…

# SandBoxModeで送信リクエストを検証する
ms = MailSettings.new
ms.sandbox_mode = SandBoxMode.new(enable: true)
mail.mail_settings = ms

# 送信リクエストの取得
request_body = mail.to_json

# メールの送信
sg = API.new(api_key: ENV.fetch("SENDGRID_API_KEY"))
response = sg.client.mail._('send').post(request_body: request_body)

puts "----- レスポンスを標準出力する -----"
puts "#{response.status_code}"
puts "----------"
response.headers.each do |key, value|
  puts "#{key}: #{Array(value).join(', ')}"
end
puts "----------"
puts response.body  # 成功時(202)は空

リクエストは正常に受け付けられたがメールへの差し込みがうまくいかない、指定したテンプレートが反映されないなど、お困りの場合は、弊社サポートチームがフォローいたします。送信リクエストとレスポンス、受信メールを添えてお問い合わせください。

コードの再確認をしましょう

SendGridでは送信後の状況をActivityやEvent Webhookで確認できるため、その手前の送信リクエストやレスポンスのログ出力を忘れがちです。今回のブログをきっかけに、しっかりログ出力できているかご自身のコードをもう一度見直してみてください。

アーカイブ

  • クレジットカード
    登録不要

  • 無料利用の
    期限なし

  • 独自ドメイン
    利用OK

クラウドサービスのため
インストールは一切不要。
SendGridの充実した機能をまずは
試してみませんか?

無料ではじめる