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

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

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

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

今回は、Go 1.25.0で確認しました。

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

ライブラリはgo getコマンドを利用して取得します。環境変数に格納したAPIキーを取得するため、godotoenvライブラリも併せてインストールします。

go get github.com/sendgrid/sendgrid-go@latest
go get github.com/joho/godotenv@latest"github.com/joho/godotenv"

sendgrid-goを使った送信コードは次のとおりです。
Mail Helper Classを利用すると、より簡単にコードを書くことができます。


package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/sendgrid/sendgrid-go"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
	"github.com/joho/godotenv"
)
func main() {
	//環境変数の読み込み
	err_read := godotenv.Load()
 	if err_read != nil {
      		log.Fatalf("error: %v", err_read)
 	}
	// 差出人
	from := mail.NewEmail("構造太郎", "***")
	// 宛先
	to := mail.NewEmail("構造花子", "***")
	// 件名
	subject := "Goのライブラリを使ったメール送信"
	// 本文:テキストパート
	plain := "構造さん\r\nお元気ですか。"
	// 本文:HTMLパート
	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>`
	msg := mail.NewSingleEmail(from, subject, to, plain, html)

	// 送信リクエストの取得
	fmt.Println("----- 送信リクエストを標準出力する -----")
	requestBody := mail.GetRequestBody(msg)
	// JSONの整形と出力
	prettyJSON, err := json.MarshalIndent(json.RawMessage(requestBody), "", "  ")
	if err != nil {
		fmt.Println("JSON整形エラー:", err)
		return
	}
	fmt.Println(string(prettyJSON))

	# メールの送信
	client := sendgrid.NewSendClient(os.Getenv("SENDGRID_API_KEY"))
	resp, err := client.Send(msg)
	# エラー処理
	if err != nil {
        fmt.Println("=== ERROR ===")
        fmt.Println(err)
        return
	}

	fmt.Println("----- レスポンスを標準出力する -----")
	fmt.Println("\n=== RESPONSE STATUS ===")
	fmt.Println(resp.StatusCode)

	fmt.Println("\n=== RESPONSE BODY ===")
	fmt.Println(resp.Body)

	fmt.Println("\n=== RESPONSE HEADERS ===")
	for key, values := range resp.Headers {
		fmt.Printf("%s: %s\n", key, values)
	}
}	

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

export SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxxxxxxx

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

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

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


// 送信リクエストの取得
fmt.Println("----- 送信リクエストを標準出力する -----")
requestBody := mail.GetRequestBody(msg)
// JSONの整形
prettyJSON, err := json.MarshalIndent(json.RawMessage(requestBody), "", "  ")
if err != nil {
	fmt.Println("JSON整形エラー:", err)
	return
}
// JSONの出力
fmt.Println(string(prettyJSON))

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


{
  "from": {
    "name": "構造太郎",
    "email": "kentaro-ichimura@kentaroichimura.com"
  },
  "subject": "Goのライブラリを使ったメール送信",
  "personalizations": [
    {
      "to": [
        {
          "name": "構造花子",
          "email": "kentaro-ichimura@kke.co.jp"
        }
      ]
    }
  ],
  "content": [
    {
      "type": "text/plain",
      "value": "構造さん\r\nお元気ですか。"
    },
    {
      "type": "text/html",
      "value": "\u003c!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"\u003e\n\u003chtml xmlns=\"http://www.w3.org/1999/xhtml\"\u003e\n\u003chead\u003e\n    \u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1\"\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cp\u003e構造さん\u003c/p\u003e\n    \u003cp\u003eお元気ですか。\u003c/p\u003e\n\u003c/body\u003e\n\u003c/html\u003e"
    }
  ]
}


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

レスポンスの取得方法

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


resp, err := client.Send(msg)
# エラー処理
if err != nil {
        fmt.Println("=== ERROR ===")
        fmt.Println(err)
        return
}

fmt.Println("----- レスポンスを標準出力する -----")
fmt.Println("\n=== RESPONSE STATUS ===")
fmt.Println(resp.StatusCode)

fmt.Println("\n=== RESPONSE BODY ===")
fmt.Println(resp.Body)

fmt.Println("\n=== RESPONSE HEADERS ===")
for key, values := range resp.Headers {
	fmt.Printf("%s: %s\n", key, values)

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

正常応答の場合


----- レスポンスを標準出力する -----

=== RESPONSE STATUS ===
202

=== RESPONSE BODY ===


=== RESPONSE HEADERS ===
Date: [Wed, 08 Oct 2025 11:33:13 GMT]
X-Message-Id: [1FYDZv75TQimZ5llrutXIw]
Access-Control-Allow-Origin: [https://sendgrid.api-docs.io]
Access-Control-Allow-Headers: [Authorization, Content-Type, On-behalf-of, x-sg-elas-acl]
Access-Control-Max-Age: [600]
Referrer-Policy: [strict-origin-when-cross-origin]
Server: [nginx]
Content-Length: [0]
Strict-Transport-Security: [max-age=31536000; includeSubDomains]
Content-Security-Policy: [frame-ancestors 'none']
Cache-Control: [no-cache]
X-Content-Type-Options: [no-sniff]
Connection: [keep-alive]
Access-Control-Allow-Methods: [POST]
X-No-Cors-Reason: [https://sendgrid.com/docs/Classroom/Basics/API/cors.html]

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


----- レスポンスを標準出力する -----

=== RESPONSE STATUS ===
400

=== RESPONSE BODY ===
{"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"}]}

=== RESPONSE HEADERS ===
Content-Length: [204]
Access-Control-Allow-Headers: [Authorization, Content-Type, On-behalf-of, x-sg-elas-acl]
Access-Control-Max-Age: [600]
Content-Security-Policy: [frame-ancestors 'none']
Access-Control-Allow-Methods: [POST]
Server: [nginx]
Content-Type: [application/json]
Access-Control-Allow-Origin: [https://sendgrid.api-docs.io]
X-No-Cors-Reason: [https://sendgrid.com/docs/Classroom/Basics/API/cors.html]
Strict-Transport-Security: [max-age=31536000; includeSubDomains]
Referrer-Policy: [strict-origin-when-cross-origin]
Date: [Fri, 10 Oct 2025 06:46:50 GMT]
Connection: [keep-alive]
Cache-Control: [no-cache]
X-Content-Type-Options: [no-sniff]


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


----- レスポンスを標準出力する -----

=== RESPONSE STATUS ===
401

=== RESPONSE BODY ===
{"errors":[{"message":"The provided authorization grant is invalid, expired, or revoked","field":null,"help":null}]}

=== RESPONSE HEADERS (整形済) ===
Server: [nginx]
Content-Length: [116]
Access-Control-Allow-Origin: [https://sendgrid.api-docs.io]
X-No-Cors-Reason: [https://sendgrid.com/docs/Classroom/Basics/API/cors.html]
Content-Type: [application/json]
Connection: [keep-alive]
Access-Control-Max-Age: [600]
Strict-Transport-Security: [max-age=31536000; includeSubDomains]
Content-Security-Policy: [frame-ancestors 'none']
Cache-Control: [no-cache]
Date: [Wed, 08 Oct 2025 11:45:08 GMT]
Access-Control-Allow-Methods: [POST]
Access-Control-Allow-Headers: [Authorization, Content-Type, On-behalf-of, x-sg-elas-acl]
X-Content-Type-Options: [no-sniff]
Referrer-Policy: [strict-origin-when-cross-origin]

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


msg := mail.NewSingleEmail(from, subject, to, plain, html)

…

// ----------------------------------------------------
// ここでSandboxモードを有効にする設定を追加
// ----------------------------------------------------

ms := mail.NewMailSettings()
ms.SandboxMode = &mail.Setting{
Enable: func(b bool) *bool { return &b }(true),
}
msg.SetMailSettings(ms)
// ----------------------------------------------------

…

# メールの送信
client := sendgrid.NewSendClient(os.Getenv("SENDGRID_API_KEY"))
resp, err := client.Send(msg)
# エラー処理
if err != nil {
fmt.Println("=== ERROR ===")
fmt.Println(err)
return
}

fmt.Println("----- レスポンスを標準出力する -----")
fmt.Println("\n=== RESPONSE STATUS ===")
fmt.Println(resp.StatusCode)

fmt.Println("\n=== RESPONSE BODY ===")
fmt.Println(resp.Body)

fmt.Println("\n=== RESPONSE HEADERS ===")
for key, values := range resp.Headers {
	fmt.Printf("%s: %s\n", key, values)

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

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

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

アーカイブ

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

  • 無料利用の
    期限なし

  • 独自ドメイン
    利用OK

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

無料ではじめる