api-email-resend-react-email について
Resend と React Email でトランザクションメールを実装する開発者向けのスキルです。型付きテンプレート、サーバー側送信、再試行、バッチ送信、Webhook 検証を扱います。
主な機能
- 01型付き React Email テンプレート
- 02送信前の非同期レンダリング
- 03サーバー側送信とエラー処理
- 04指数バックオフによる再試行
- 05バッチ送信と Webhook 検証
活用シーン
- 01認証メールやパスワードリセットメールの作成
- 02領収書や通知メールの送信
- 03複数宛先へのメール一括送信
- 04Resend Webhook イベントの検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-email-resend-react-emailインストール後、Claude Code で/api-email-resend-react-emailを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.yamlreference.mdexamples/advanced-features.mdasync-batch.mdcore.mdpreferences.mdtemplates.mdwebhooks.md詳細
Resend と React Email を使ったメールのパターン
クイックガイド: Resend を React Email テンプレートと組み合わせて、トランザクションメールを送信します。送信前に必ず
render()をawaitしてください(Promise を返します)。サーバーサイドでのみ使用し、API キーをクライアントに公開しないでください。一時的な障害に備え、指数バックオフによる再試行を実装してください。トランザクションメール以外には、配信停止リンクを含めてください(CAN-SPAM)。2〜100 人の宛先にはresend.batch.send()を使用してください(バッチ送信では添付ファイルとスケジュール送信はサポートされません)。React Email 5.0+ ではrenderAsyncは非推奨です。代わりにrender()を使用してください。Webhook の検証には、リクエストボディの生データとwebhookSecretパラメーターが必要です。
<critical_requirements>
重要:このスキルを使用する前に
すべてのコードは CLAUDE.md のプロジェクト規約に従う必要があります(kebab-case、名前付きエクスポート、インポート順序、
import type、名前付き定数)
(resend.emails.send() に HTML を渡す前に、必ず render() を await してください。render は Promise を返します)
(Resend API のエラーを必ず処理し、一時的な障害に備えた再試行ロジックを実装してください)
(すべてのメール送信には必ずサーバーサイドを使用してください。RESEND_API_KEY をクライアントに公開しないでください)
(マーケティング/通知メールには必ず配信停止リンクを含めてください。CAN-SPAM 準拠のために必要です)
(すべてのメールテンプレートに型付き props インターフェースを必ず使用してください。コンパイル時の検証が可能になります)
</critical_requirements>
自動検出: Resend、React Email、@react-email/components、resend.emails.send、メールテンプレート、トランザクションメール、確認メール、パスワードリセットメール、通知メール、メールのレンダリング、resend.batch.send、resend.webhooks.verify
使用する場面:
- トランザクションメール(確認、パスワードリセット、領収書)の送信
- Tailwind スタイルを使った React Email テンプレートの作成
- メール配信を伴う通知システムの構築
- Webhook によるメールのトラッキングの実装
- 複数の宛先への一括送信
使用しない場面:
- マーケティングキャンペーンの管理(専用のマーケティングツールを使用)
- SMS またはプッシュ通知(別のサービスを使用)
- メールリストの管理(Resend Audiences またはマーケティングツールを使用)
基本方針
現代のアプリケーションにおけるメールは、サーバーサイドでテンプレートを使う方式が基本です。React Email はメール開発にコンポーネントのパターンを取り入れ、Resend は信頼性の高い配信を担います。
基本原則:
- サーバーサイドのみ - API キーをクライアントに公開しないでください
- 型付きテンプレート - props インターフェースにより、コンパイル時にエラーを検出できます
- 信頼性の高い配信 - 一時的な障害に備えた再試行ロジックでエラーを処理します
- ノンブロッキング - 重要度の低いメールには、完了を待たずに送信する方式を使います
メールを送信する場面:
- ユーザー認証に関するイベント(確認、パスワードリセット、2FA)
- トランザクションの確認(購入、登録、招待)
- 重要な通知(セキュリティ警告、アカウントの変更)
- チームでのコラボレーション(招待、メンション、更新)
メールを送信しない場面:
- 細かな操作のたびに送信する(メール疲れにつながります)
- 同意を得ずにマーケティングメールを送信する(スパムとなり、違法です)
- リアルタイムのアラートを送信する(プッシュ通知を使用してください)
- アプリ内の操作を通知する(代わりにアプリ内通知を表示してください)
基本パターン
パターン 1:メールテンプレートの構成
型付き props を定義し、React Email コンポーネントを使用して、開発サーバー向けに PreviewProps を追加します。
interface WelcomeEmailProps {
userName: string;
loginUrl: string;
features?: string[];
}
export function WelcomeEmail({ userName, loginUrl, features = [] }: WelcomeEmailProps) {
return (
<BaseLayout preview={`Welcome, ${userName}!`}>
<Heading>Welcome!</Heading>
<Text>Hi {userName},</Text>
<Button href={loginUrl}>Get Started</Button>
</BaseLayout>
);
}
WelcomeEmail.PreviewProps = { userName: "John", loginUrl: "..." } satisfies WelcomeEmailProps;
レイアウトとスタイルを含む完全なテンプレートについては、examples/core.md のパターン 1 を参照してください。
パターン 2:エラー処理を伴う送信
必ず render() を await し、{ data, error } のレスポンスを確認して、型付きの結果を返します。
const html = await render(options.react); // CRITICAL: must await
const { data, error } = await resend.emails.send({
from: `${DEFAULT_FROM_NAME} <${DEFAULT_FROM_ADDRESS}>`,
to: options.to,
subject: options.subject,
html,
});
if (error) {
return { success: false, error: error.message };
}
return { success: true, id: data?.id };
完全な送信ラッパーと指数バックオフによる再試行については、examples/core.md のパターン 2〜3 を参照してください。
パターン 3:非同期の送信(完了を待たない方式)
重要度の低いメール(ウェルカムメール、通知)では、レスポンスを待たせないようにします。
// Non-blocking - catches errors internally
sendEmailAsync(options);
return Response.json({ success: true }); // Returns immediately
正常なシャットダウンに備えて、処理中の Promise を追跡してください。examples/async-batch.md のパターン 1〜2 を参照してください。
### パターン 4:バッチ API
2~100 人の受信者には resend.batch.send() を使用します。すべてのテンプレートを並列でレンダリングします。
const rendered = await Promise.all(
emails.map(async (e) => ({
from,
to: e.to,
subject: e.subject,
html: await render(e.react),
})),
);
const { data, error } = await resend.batch.send(rendered);
バッチの制限: attachments と scheduledAt は使用できません。タグと冪等性キーはサポートされています。examples/async-batch.md のパターン 3~4を参照してください。
パターン 5:Webhook の検証
生のリクエスト本文を使って resend.webhooks.verify() を使用します。JSON を解析すると署名の検証に失敗します。
const payload = await request.text(); // Raw body, NOT .json()
const event = resend.webhooks.verify({
payload,
headers: {
id: request.headers.get("svix-id") ?? "",
timestamp: request.headers.get("svix-timestamp") ?? "",
signature: request.headers.get("svix-signature") ?? "",
},
webhookSecret: process.env.RESEND_WEBHOOK_SECRET!,
});
イベント処理と Svix の代替手段を含む完全なハンドラーについては、examples/webhooks.md を参照してください。
パターン 6:送信予約、冪等性キー、タグ
// Scheduled (up to 30 days, NOT supported in batch)
await resend.emails.send({ ...payload, scheduledAt: futureDate.toISOString() });
// Idempotency (256 char limit, expires 24h) — second argument to send()
await resend.emails.send(payload, {
idempotencyKey: `order-confirmation-${orderId}`,
});
// Tags (ASCII alphanumeric, underscores, dashes only)
await resend.emails.send({
...payload,
tags: [{ name: "campaign", value: "launch" }],
});
検証を含む完全な実装については、examples/advanced-features.md を参照してください。
パターン 7:配信停止と設定
トランザクションメール以外のメールには、配信停止リンクを必ず含める必要があります(CAN-SPAM)。セキュリティのため、署名付きトークンを使用してください。
// In every notification/marketing template:
<Link href={unsubscribeUrl}>Unsubscribe from these notifications</Link>
// Generate signed unsubscribe URLs
const token = jwt.sign({ userId, category }, UNSUBSCRIBE_SECRET, { expiresIn: "30d" });
const url = `${APP_URL}/api/email/unsubscribe?token=${token}`;
設定スキーマ、送信前の確認、配信停止エンドポイントについては、examples/preferences.md を参照してください。
詳細なリソース:
- examples/core.md - テンプレートの構造、エラー処理を伴う送信、再試行ロジック
- examples/async-batch.md - 非同期送信、バッチ API
- examples/webhooks.md - 署名検証を備えた Webhook ハンドラー
- examples/templates.md - パスワードリセット、通知テンプレート
- examples/preferences.md - 配信停止、メール設定
- examples/advanced-features.md - 送信予約、冪等性キー、タグ
- reference.md - 判断フレームワーク、アンチパターン
<red_flags>
要注意事項
優先度の高い問題:
render()を await していない - メール本文として"[object Promise]"が送信されます- API キーがクライアントに公開されている - セキュリティ上の脆弱性です
- エラー処理がない - 失敗が検知されません
- トランザクションメール以外のメールに配信停止リンクがない - CAN-SPAM 違反です
- ユーザー設定を確認せずに送信している - スパムになります
優先度が中程度の問題:
- 一時的な障害(レート制限、5xx エラー)に対する再試行ロジックがない
- 重要度の低いメールの同期送信によってリクエストハンドラーがブロックされる
- 環境変数の代わりに送信元アドレスがハードコードされている
- Webhook の署名検証チェックがない
- メール送信の結果をログに記録していない
よくある間違い:
- メールテンプレートで
GridやFlexboxを使用する(メールクライアントではサポートされていません) - メールで影やグラデーションが表示されることを想定する
rem単位を使用する(メールクライアントによって扱いが異なります)- 開発サーバー用の
PreviewPropsを忘れる
注意点とエッジケース:
- Resend SDK は
reactプロパティを直接受け付けます(内部でレンダリングします)が、事前にawait render()を使ってレンダリングし、htmlに渡すと出力を制御でき、Resend SDK の外部でも動作します - React Email 5.0 以降では
render()は非同期です(renderAsyncは非推奨です) - バッチ API は最大 100 通までで、
attachmentsとscheduledAtはサポートされていません - Webhook には生のリクエスト本文が必要です - JSON を解析すると署名の検証に失敗します
- Webhook の検証では
secretではなくwebhookSecretパラメーターを使用します - Webhook のヘッダーオブジェクトでは短いキーを使用します:
id、timestamp、signature - 冪等性キーはメールペイロードのヘッダーではなく、
resend.emails.send()の第 2 引数として渡します - 冪等性キーの有効期限は 24 時間で、最大 256 文字です
- タグに使用できるのは ASCII の英数字、アンダースコア、ダッシュのみで、キー/値ごとに最大 256 文字です
- メールで Tailwind を使用するには
@react-email/tailwindラッパーが必要です(React Email 5.0 以降では Tailwind 4 をサポートしています) - 画像には絶対 URL を使用する必要があります(相対パスは使用できません)
</red_flags>
<critical_reminders>
重大な注意事項
すべてのコードは、CLAUDE.md のプロジェクト規約に従う必要があります(kebab-case、名前付きエクスポート、インポートの順序、
import type、名前付き定数)
(HTML を resend.emails.send() に渡す前に、必ず render() を await してください。render は Promise を返します)
(Resend API のエラーを必ず処理し、一時的な障害に対するリトライロジックを実装してください)
(すべてのメールは必ずサーバー側で送信してください。RESEND_API_KEY をクライアントに公開してはいけません)
(マーケティングメール/通知メールには必ず配信停止リンクを含めてください。CAN-SPAM 準拠に必要です)
(すべてのメールテンプレートで、型付きの props インターフェースを必ず使用してください。これによりコンパイル時の検証が可能になります)
これらのルールに従わないと、メール配信の失敗、セキュリティ上の脆弱性、または法令遵守上の問題が発生します。
</critical_reminders>