
Twilio SendGridのActivity feedとEmail Logsを比較し、CSVとJSONを確認する
はじめに
本記事では、Twilio SendGrid の Email Activity Feed (以降 Activity feed) と Email Logs の用途差を説明します。あわせて、両機能を実際に操作し、CSV と JSON の出力を確認する手順を示します。
Twilio SendGrid とは
Twilio SendGrid は、メール送信を API として提供するサービスです。アプリケーションから HTTP リクエストでメール送信を行い、配送状況を追跡できます。
対象読者
- Activity feed と Email Logs の違いを、運用設計や提案資料の根拠として把握したい方
- 送信トラブル時に、コンソールと API の両方で状況を確認したい方
- 取得したログを CSV や JSON として扱い、社内連携や二次利用を検討している方
参考
- Email Activity Feed | SendGrid Docs
- Email Logs (UI) | SendGrid Docs
- Email Logs API Overview | SendGrid Docs
- Email Logs: Filter all messages | SendGrid Docs
- Email Logs: Filter messages by ID | SendGrid Docs
- Mail Send | SendGrid Docs
Activity feed と Email Logs について
Activity feed は、直近のメールイベントを一覧し、メッセージ単位の配送フローを追跡するための機能です。一覧は CSV でエクスポート可能です。保持期間のデフォルト日数はプランによって異なり、一般に 3 日または 7 日です。また Email Activity history add-on を購入すると、保持期間が最大 30 日になります。
一方で、 2025 年 11 月に新たにリリースされた Email Logs は、メールの配送経路や問題発生箇所を調べるための機能です。イベント単位のデータを JSON で取得でき、トラブルシュートや検証結果の保存に使えます。保持期間は 30 日で、延長はできません。
実際に使ってみた
Email Logs の UI フィルタは完全一致が前提であるため、検証では検索しやすいように件名を固定します。また、Email Logs API で取得する場合は API Key を用意します。
セットアップ
まず、作業用ディレクトリで依存関係を用意します。
npm init -y
npm i dotenv
.env を作成する
プロジェクト直下に .env を作成します。
SENDGRID_API_KEY=YOUR_SENDGRID_API_KEY_HERE
TO_EMAIL=your.address@example.com
FROM_EMAIL=verified.sender@example.com
SUBJECT=SG-LOGS-TEST-2026-01-15T1100+0900
Node.js スクリプトを作成する
sendgrid-tools.js を作成します。
sendgrid-tools.js 全文
/* sendgrid-tools.js */
const dotenv = require("dotenv");
dotenv.config();
function requireEnv(name) {
const v = process.env[name];
if (!v) {
throw new Error(`${name} が未設定です。.env を確認してください。`);
}
return v;
}
function parseArgs(argv) {
const args = { _: [] };
for (let i = 0; i < argv.length; i += 1) {
const a = argv[i];
if (a.startsWith("--")) {
const key = a.slice(2);
const next = argv[i + 1];
if (!next || next.startsWith("--")) {
args[key] = true;
} else {
args[key] = next;
i += 1;
}
} else {
args._.push(a);
}
}
return args;
}
async function sgFetch(url, { method, bodyObj } = {}) {
const apiKey = requireEnv("SENDGRID_API_KEY");
const res = await fetch(url, {
method: method ?? "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: bodyObj ? JSON.stringify(bodyObj) : undefined,
});
const text = await res.text();
const xMessageId = res.headers.get("x-message-id");
return {
ok: res.ok,
status: res.status,
headers: {
"x-message-id": xMessageId ?? "",
},
text,
json: (() => {
try {
return text ? JSON.parse(text) : null;
} catch {
return null;
}
})(),
};
}
function buildDefaultQuery() {
const subject = requireEnv("SUBJECT");
const toEmail = requireEnv("TO_EMAIL");
return `subject = '${subject}' AND to_email = '${toEmail}'`;
}
async function cmdSend() {
const toEmail = requireEnv("TO_EMAIL");
const fromEmail = requireEnv("FROM_EMAIL");
const subject = requireEnv("SUBJECT");
const body = {
personalizations: [
{
to: [{ email: toEmail }],
},
],
from: { email: fromEmail },
subject,
content: [{ type: "text/plain", value: "SendGrid logs test." }],
};
const r = await sgFetch("https://api.sendgrid.com/v3/mail/send", {
method: "POST",
bodyObj: body,
});
const out = {
status: r.status,
ok: r.ok,
"x-message-id": r.headers["x-message-id"],
};
console.log(JSON.stringify(out, null, 2));
if (!r.ok) {
console.error(r.text);
process.exitCode = 1;
}
}
async function cmdSearch(args) {
const limitRaw = args.limit ?? "10";
const limit = Number(limitRaw);
if (!Number.isFinite(limit) || limit < 1 || limit > 1000) {
throw new Error("--limit は 1 から 1000 の範囲で指定してください。");
}
const query = args.query ? String(args.query) : buildDefaultQuery();
const r = await sgFetch("https://api.sendgrid.com/v3/logs", {
method: "POST",
bodyObj: { query, limit },
});
const out = r.json ?? { status: r.status, ok: r.ok, raw: r.text };
console.log(JSON.stringify(out, null, 2));
if (!r.ok) {
process.exitCode = 1;
}
}
async function cmdDetail(args) {
const sgMessageId = args._[0];
if (!sgMessageId) {
throw new Error("sg_message_id を指定してください。例: node sendgrid-tools.js detail <sg_message_id>");
}
const url = `https://api.sendgrid.com/v3/logs/${encodeURIComponent(sgMessageId)}`;
const r = await sgFetch(url);
const out = r.json ?? { status: r.status, ok: r.ok, raw: r.text };
console.log(JSON.stringify(out, null, 2));
if (!r.ok) {
process.exitCode = 1;
}
}
async function main() {
const argv = process.argv.slice(2);
const sub = argv[0];
const args = parseArgs(argv.slice(1));
try {
if (sub === "send") {
await cmdSend();
return;
}
if (sub === "search") {
await cmdSearch(args);
return;
}
if (sub === "detail") {
await cmdDetail(args);
return;
}
console.log(
[
"使い方:",
" node sendgrid-tools.js send",
" node sendgrid-tools.js search --limit 10",
" node sendgrid-tools.js search --query \"subject = '...' AND to_email = '...'\"",
" node sendgrid-tools.js detail <sg_message_id>",
].join("\n"),
);
process.exitCode = 2;
} catch (e) {
console.error(e?.message ?? e);
process.exitCode = 1;
}
}
main();
Mail Send API でテストメールを送信する
node sendgrid-tools.js send
出力例:
{
"status": 202,
"ok": true,
"x-message-id": "****"
}
Activity feed をコンソールで確認し CSV をダウンロードする
Activity feed はメッセージを選択すると、当該メッセージの詳細や履歴を確認できます。

次に、Export CSV を実行します。

ダウンロードした CSV の中身を確認します。カラム構成や値の粒度を見て、運用で使える情報量かどうかを判断します。
"processed","message_id","event","api_key_id","recv_message_id","credential_id","subject","from","email","asm_group_id","template_id","originating_ip","reason","outbound_ip","outbound_ip_type","mx","attempt","url","user_agent","type","is_unique","username","categories","marketing_campaign_id","marketing_campaign_name","marketing_campaign_split_id","marketing_campaign_version","unique_args"
"2026-01-15 04:47:02.000","****","processed","","****","","SG-LOGS-TEST-2026-01-15T1100+0900","****@example.com","****@example.com","","","***.***.***.***","","","","",0,"","","","","","[]","","","","","{}"
"2026-01-15 04:47:04.000","****","delivered","","****","","","","****@example.com","","","","250 2.0.0 OK DMARC:Quarantine **** - gsmtp","***.***.***.***","dedicated","gmail-smtp-in.l.google.com",0,"","","","","","[]","","","","","{}"
Email Logs をコンソールで検索する
Email Logs は、Recipient Email Address、Subject、Date、Category、Status などで検索できます。


Email Logs API で一覧を取得し、sg_message_id を得る
Email Logs の Filter all messages は POST /v3/logs です。query 文字列で条件を指定し、limit は 1 から 1000 の範囲です。
node sendgrid-tools.js search --limit 10
出力例 (実行結果のプレースホルダー):
{
"messages": [
{
"from_email": "****@example.com",
"sg_message_id": "****",
"subject": "SG-LOGS-TEST-2026-01-15T1100+0900",
"to_email": "****@example.com",
"reason": "250 2.0.0 OK DMARC:Quarantine **** - gsmtp",
"status": "delivered",
"sg_message_id_created_at": "2026-01-15T04:47:02Z"
}
]
}
必要なら、クエリを明示して実行できます。
node sendgrid-tools.js search --limit 10 --query "subject = 'SG-LOGS-TEST-...' AND to_email = '...'"
Email Logs API で 1 通のイベント詳細を取得する
Filter messages by ID は GET /v3/logs/{sg_message_id} です。Filter all messages で得た sg_message_id を指定すると、そのメッセージの full event timeline を取得できます。
node sendgrid-tools.js detail '先に取得した sg_message_id'
出力例 (実行結果のプレースホルダー):
{
"from_email": "****@example.com",
"sg_message_id": "****",
"subject": "SG-LOGS-TEST-2026-01-15T1100+0900",
"to_email": "****@example.com",
"status": "delivered",
"api_key_id": "****",
"events": [
{
"event": "received",
"recv_msgid": "****",
"sg_event_id": "****",
"timestamp": 1768452422,
"api_key_id": "****",
"api_version": "3",
"client_ip": "***.***.***.***",
"protocol": "HTTP",
"recipient_count": 1,
"reseller_id": "****",
"size": 616,
"useragent": "node",
"v3_payload_details": {
"customarg_count": 0,
"substitution_bytes": 0,
"substitution_count": 0,
"content_bytes": 19,
"recipient_count": 1,
"sender_count": 1,
"customarg_largest_bytes": 2,
"text/plain": 1,
"personalization_count": 1,
"attachments_bytes": 0
}
},
{
"event": "processed",
"email": "****@example.com",
"sg_message_id": "****",
"sg_event_id": "****",
"timestamp": 1768452422,
"smtp-id": "<****>"
},
{
"event": "delivered",
"email": "****@example.com",
"sg_message_id": "****",
"sg_event_id": "****",
"timestamp": 1768452424,
"smtp-id": "<****>",
"ip": "***.***.***.***",
"response": "250 2.0.0 OK DMARC:Quarantine **** - gsmtp",
"tls": 1
}
],
"client_ip": "***.***.***.***",
"outbound_ip": "***.***.***.***",
"outbound_ip_type": "dedicated"
}
考察 - それぞれのユースケースについて
Email Logs は、特定メッセージの配送経路を追い、トラブルシュートする目的に向きます。UI で個別メッセージの詳細画面を確認でき、API でもイベント履歴を JSON として取得できます。「探し方が分かっている前提」の調査に強く 、たとえば 1/10 の 15:00 ごろに A さんへ送った件名 X のような形で、日付・宛先・メッセージ ID などの手がかりがあれば追いやすいです。
一方、Email Logs API はページング未対応であり、limit で件数を抑える前提です。このため、たとえば ログを漏れなく吸い上げて CSV 化し、AI に入力する といった用途では、期間の分割取得、重複排除、再試行、保存先の確保など、追加の設計・実装が必要になりやすいです。こうした用途では、コンソール操作で CSV をダウンロードし、関係者や AI へ共有できる Activity feed のほうが向いていると考えられます。
まとめ
Activity feed は、コンソールで網羅性の高い CSV をダウンロードし共有したい場面に向きます。Email Logs は、特定メッセージのトラブルシュートと、API によるイベント取得に向きます。ただし、大量データの長期保管や分析が必要な場合は、Event Webhook などの併用も考えるとよいでしょう。








