+ 作るログイン
図を読み込んでいます…
1 / 13
メールのしくみ ― DNS から SPF・DKIM・DMARC、Resend の運用まで / 全11章

メールのしくみ 9:Resend と2つの入口

発行
アニメモ公式
版
第1版
改訂
コマ
全13

自分でメールサーバーを立てずに Resend を使う理由を、ここまでの話(身元確認・評判・配達の雑務)から説明します。借りられるものと借りられないもの、HTTP API と SMTP の2つの入口、Animemo が両方を使い分ける理由、API キーの置き場所、Supabase の組み込み送信を差し替える手順まで。

メールを届けるのに必要なものは、ここまでで出そろった

8本目までで、メールを確実に届けるために必要なものが出そろいました。

必要なもの中身詳しくは
身元確認SPF・DKIM・DMARC の3つをそろえる5〜7本目
評判送信元の番号とドメインの点数を高く保つ8本目
配達の雑務25番で相手に渡す、再送、バウンスの受け取り、記録3本目

どれも、メールを届けるには欠かせません。でも、Animemo の本業(動く説明を作って見せること)とは関係がありません。

これを全部、自分で用意するべきでしょうか。この作品では、自分でやった場合に何が大変かを確かめたうえで、Resend を使う理由と、その使い方の入口を見ていきます。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 1 / 13
  • メールを届けるのに必要なものは、ここまでで出そろった
  • 身元確認
  • 評判
  • 配達の雑務
  • SPF・DKIM・DMARC
  • 番号とドメインの点数
  • 再送・バウンス・記録
  • これを全部、自分で用意するべきか?
  • 身元確認・評判・配達の雑務。どれも自分の本業ではない。

自分でメールサーバーを立てると

まず、Resend を使わずに自分でメールサーバーを立てた場合を考えます。

出口が塞がれています。 3本目で見たとおり、AWS や Google Cloud などの多くのクラウドは、25番ポートからの外向きの通信を最初から塞いでいます。相手のサーバーに直接渡すことができません。解除の申請ができる場合もありますが、審査があります。

評判がゼロです。 8本目で見たとおり、新しく借りた IP アドレスには実績がありません。実績が無いどころか、その番号を以前使っていた誰かが迷惑メールを送っていて、最初から点数が低いことさえあります。

作るものが山ほどあります。 DKIM の鍵を作って安全に保管し、1通ずつ署名する仕組み。相手のサーバーが一時的に受け取れないときに、数日にわたって再送する仕組み。戻ってきたバウンスを受け取って、どの宛先が存在しないかを記録する仕組み。

どれも、一人で作って保守し続けるには重すぎます。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 2 / 13
  • 自分でメールサーバーを立てると
  • 自前のメールサーバー
  • クラウドでは25番が塞がれている
  • 新品の番号は評判ゼロ(むしろ疑われる)
  • DKIM の鍵の管理・署名を自作
  • 再送・バウンス処理・記録を自作
  • 塞がれた出口、評判ゼロの番号、自作の山。どれも一人では重い。

Resend は、評判の良い送信網を APIキー1本で貸してくれる

Resend は、この大変な部分をまとめて引き受けてくれる、メール送信のサービスです。

中身は Amazon の SES(Simple Email Service)という大規模な送信基盤です。Resend はその上に、開発者が使いやすい API と管理画面を載せています。

借りられるものは次のとおりです。

借りられるもの何が解決するか
25番で相手に渡す仕事出口の問題(3本目)
評判の良い共有の送信元評判ゼロの問題(8本目)
DKIM の鍵の保管と署名鍵を自分で管理しなくていい(6本目)
再送・バウンスの受け取り・配送の記録配達の雑務(3本目)

こちらが用意するのは、Resend の API キーと、次の作品で説明する DNS の設定だけです。無料の枠もあり、少量の送信なら費用もかかりません。

「メールを送る」ために本当に難しいのは、SMTP を話すことではなく、身元と評判の問題を解くことでした。Resend を使う理由は、そこを借りられることにあります。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 3 / 13
  • Resend は、評判の良い送信網を APIキー1本で貸してくれる
  • Resend
  • 25番で相手に渡すのは Resend
  • 中身は Amazon SES
  • 評判の良い共有の送信元
  • APIキー1本で使える
  • DKIM の秘密鍵を保管し、毎回署名
  • 再送・バウンス受け取り・配送の記録
  • 中身は Amazon SES。署名・再送・バウンス処理まで引き受けてくれる。

借りられないもの:自分のドメインと、その評判

Resend が何でも代わりにやってくれるわけではありません。借りられないものが2つあります。

1つ目は、DNS の設定です。SPF・DKIM・DMARC の宣言は、mail.animemo.app の掲示板に書かなければなりません。2本目で見たとおり、その掲示板に書けるのは持ち主だけです。Resend がどれほど親切でも、あなたのドメインの掲示板には書けません。だから Resend は「この値を DNS に入れてください」と案内するところまでしかできません。これは10本目で見ます。

2つ目は、ドメインの評判を守る運用です。8本目で見たとおり、共有の送信元の評判は Resend が守りますが、ドメインの評判は自分の送り方で決まります。存在しない宛先に送り続けたり、苦情が多いメールを送ったりすれば、評判は下がります。これは11本目で見ます。

逆に言えば、この2つさえきちんとやれば、残りは Resend に任せられます。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 4 / 13
  • 借りられないもの:自分のドメインと、その評判
  • Resend
  • あなた
  • 中身は Amazon SES
  • mail.animemo.app の持ち主
  • DNS に書けるのは 持ち主だけ。 ここは誰にも 代われない。
  • DNS に3〜4行を書く(10本目)
  • バウンス・苦情で止める(11本目)
  • DNS の設定と、届かない宛先に送らない運用は、こちらの仕事のまま。

Resend には入口が2つある

Resend に「このメールを送って」と頼む方法は2つあります。

入口使い方向いている場面
HTTP APIhttps://api.resend.com/emails に JSON を POST する自分で書いたコードから送る
SMTPsmtp.resend.com にポート 465 か 587 でログインして渡すSMTP しか話せない既存のソフトから送る

どちらの入口から入っても、その先で起きること(署名・配送・記録)は同じです。違うのは、頼み方だけです。

SMTP の入口があるのは、世の中には「SMTP の設定欄しか持っていないソフト」がたくさんあるからです。3本目で見たとおり、SMTP はメールの世界の共通語なので、SMTP さえ話せれば、どんなソフトからでも Resend を使えます。

次の2ページで、それぞれの入口を詳しく見ます。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 5 / 13
  • Resend には入口が2つある
  • SMTP
  • smtp.resend.com(465/587)
  • Resend
  • 中身は Amazon SES
  • HTTP API
  • POST api.resend.com/emails
  • 自分のコードから使うなら API。SMTP しか話せないソフトからなら SMTP。

入口①:HTTP API。JSON を1回 POST するだけ

HTTP API は、Web の API を呼ぶのと同じ形で使えます。

ts
const res = await fetch("https://api.resend.com/emails", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    from: "Animemo <[email protected]>",
    to: "[email protected]",
    subject: "招待が届いています",
    html: "<p>…</p>",
    text: "…",
  }),
});
const { id } = await res.json();

Authorization ヘッダーに API キーを載せることで、「この頼みは正当な持ち主から来た」ことを Resend に示します。

from には、Resend で確認済みのドメインのアドレスしか使えません。確認していないドメインを名乗れないことは、4〜7本目で見たなりすまし対策の考え方そのものです。

成功すると、送ったメールの `id` が返ってきます。この id は、後で Resend から「届いた」「戻ってきた」という知らせ(11本目の Webhook)が来たときに、どのメールの話かを照らし合わせるのに使います。DB に残しておきます。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 6 / 13
  • 入口①:HTTP API。JSON を1回 POST するだけ
  • POST https://api.resend.com/emails
  • 返事
  • Authorization: Bearer re_…(API キー)
  • {
  • { "id": "4ef9…" }
  • "from": "Animemo <[email protected]>",
  • "to": "[email protected]",
  • この id で、後から 届いたか・戻ったかを 照らし合わせる
  • "subject": "招待が届いています",
  • "html": "<p>…</p>"
  • }
  • 認証はヘッダーの API キー。返ってくる id を DB に残しておく。

入口②:SMTP。メールソフトと同じ設定欄に入れる

SMTP の入口は、メールソフトに送信サーバーを設定するのと同じ要領で使います。

設定欄入れる値
ホストsmtp.resend.com
ポート465(最初から暗号化)または 587(STARTTLS で暗号化)
ユーザー名resend
パスワードAPI キー(re_…)
差出人確認済みのドメインのアドレス([email protected])

ポートが 25 ではなく 465 や 587 なのは、3本目で見たとおり、これが「送信を頼むための入口」だからです。ログインと暗号化が付いています。

パスワード欄に API キーを入れる点に注意してください。HTTP API のときと同じキーで、同じように秘密です。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 7 / 13
  • 入口②:SMTP。メールソフトと同じ設定欄に入れる
  • ホスト
  • smtp.resend.com
  • ポート
  • 465(最初から暗号化)/ 587(STARTTLS)
  • ユーザー名
  • resend
  • パスワード
  • API キー(re_…)
  • 差出人
  • [email protected](確認済みのドメイン)
  • ユーザー名は resend、パスワードは API キー。

Animemo は、2つの入口を両方使う

Animemo が送るメールは2種類あり、入口を使い分けます。

Supabase Auth が送るメール(登録確認・パスワード再設定)は SMTP です。 これらのメールを送っているのは Supabase で、Animemo のコードではありません。Supabase は世の中のあらゆるメールサービスの API を知っているわけではないので、どこでも通じる共通語として SMTP の設定欄だけを用意しています。そこに Resend の SMTP を差し込みます。

Animemo 独自の招待メール(作品・組織への招待)は API です。 こちらは自分たちの Fastify から送るので、細かく扱える API を選びます(次のページ)。

Animemo の手順書(docs/operations/smtp-and-invitation-email.md)では、Resend を呼ぶ処理を server/src/lib/email.ts の1か所に閉じ込め、各ルートから直接呼ばない方針になっています。送信サービスを差し替えることになっても、直す場所が1つで済むようにするためです。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 8 / 13
  • Animemo は、2つの入口を両方使う
  • Supabase Auth
  • SMTP
  • 登録確認・パスワード再設定
  • smtp.resend.com(465/587)
  • Resend
  • 中身は Amazon SES
  • Fastify(自前)
  • HTTP API
  • 作品・組織への招待
  • POST api.resend.com/emails
  • Supabase は SMTP しか話せない。自前の招待メールは API で細かく扱う。

自前のメールで API を選ぶ理由

自分のコードから送るなら、SMTP ではなく API を選ぶ理由があります。

冪等キーを付けられる。 通信が途中で切れて「送れたか分からない」とき、同じキーで送り直せば二重に届きません(11本目)。

送ったメールの id が手に入る。 DB に記録しておけば、後から届いた「届いた」「戻ってきた」の知らせと照らし合わせられます。

失敗の理由が分かる。 確認していないドメインを from に使った、宛先の形がおかしい、などの失敗が、JSON で理由付きで返ってきます。

SMTP の会話を実装しなくていい。 SMTP のライブラリを入れて接続を管理する必要がなく、fetch 1回で済みます。

Resend は公式の SDK(resend パッケージ)も用意していますが、中でやっていることは前のページの fetch と同じです。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 9 / 13
  • 自前のメールで API を選ぶ理由
  • Idempotency-Key を付けて、二重送信を防げる(11本目)
  • 送ったメールの id が返り、DB に記録できる
  • 失敗したとき、理由が JSON で返ってくる
  • SMTP の会話を実装しなくていい
  • 冪等キーを付けられる・送ったメールの id が手に入る・失敗の理由が分かる。

API キーはサーバーにだけ置く

API キーは、それを持っている人が、あなたのドメインの名前でメールを送れる鍵です。

もしブラウザ側のコード(Animemo なら client/)に書いてしまうと、ページを開いた誰もが開発者ツールでキーを読めます。読んだ人は、[email protected] を名乗って好きなメールを送れます。しかも SPF・DKIM・DMARC はすべて合格します。本物の送信網から送られるからです。

だから API キーは、サーバーの環境変数(`RESEND_API_KEY`)にだけ置きます。これは、CLAUDE.md の「SERVICE_KEY・STRIPE_SECRET_KEY は server/ のみ」と同じ考え方です。

Resend の API キーには、被害を小さくする工夫もあります。キーの権限を「送信だけ」に絞れます。さらに、送れるドメインを限定することもできます。万一漏れたときは、Resend の画面でそのキーを削除して作り直せば、古いキーは使えなくなります。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 10 / 13
  • API キーはサーバーにだけ置く
  • サーバー(server/)
  • ブラウザ(client/)
  • 環境変数 RESEND_API_KEY
  • ここに置くと全員に見える
  • キーの権限は「送信だけ」に絞れる。さらにドメインも限定できる
  • 漏れたら、Resend の画面でそのキーを消して作り直す
  • 漏れたら、誰でもあなたのドメインの名前でメールを送れる。

Supabase の組み込み送信のままではいけない理由

Supabase には、最初から組み込みのメール送信が付いています。何も設定しなくても登録確認メールが届くのはそのおかげです。ただし、これはお試し用です。

1時間に送れる数がごく少なく、送れる宛先もプロジェクトのチームメンバーのアドレスに限られます。開発中に自分で試すには十分ですが、本番で利用者が増えると、ある日突然、登録確認メールが届かなくなります。

しかも、組み込みの送信では、身元確認や評判について、こちらから何も手を打てません。Supabase のドメインから送られるので、利用者から見ても Animemo のメールだと分かりにくくなります。

Animemo のデプロイ手順書(docs/operations/deploy.md)にも、太字で「ここを飛ばすと、ある日突然メールが届かなくなる」と書いてあります。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 11 / 13
  • Supabase の組み込み送信のままではいけない理由
  • Supabase 組み込みの送信
  • Custom SMTP
  • お試し用
  • ここに Resend を登録する
  • 1時間に数通まで
  • チームメンバー宛てにしか送れない
  • 組み込みはお試し用。本番で放置すると、ある日突然届かなくなる。

Supabase に Resend の SMTP を登録する

対策は、Supabase の管理画面の Authentication → SMTP Settings で Custom SMTP を有効にし、Resend の SMTP を登録することです。

設定欄入れる値
Hostsmtp.resend.com
Port465
Usernameresend
PasswordResend の API キー
Sender email[email protected](Resend で確認済みのドメイン)
Sender nameAnimemo

登録後に気をつけることが3つあります。

送信数の上限。 Custom SMTP にした直後も、Supabase 側の送信数の上限(Authentication → Rate Limits)は低い値から始まります。必要に応じて引き上げます。

メールの文面。 Authentication → Email Templates で、登録確認などの文面を Animemo 向けに書き換えます。

リンクの追跡。 認証用のリンクが書き換えられないよう、Resend 側でリンクの追跡を有効にしないでおきます(11本目)。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 12 / 13
  • Supabase に Resend の SMTP を登録する
  • Host
  • smtp.resend.com
  • Port
  • 465
  • Username
  • resend
  • Password
  • API キー
  • Sender email
  • [email protected]
  • Sender name
  • Animemo
  • ※ Rate Limits(送信数の上限)は Custom SMTP にした直後も低い値から始まる
  • Authentication → SMTP Settings。登録後も送信数の上限は別に調整する。

まとめ:Resend と2つの入口

この作品で見たことをまとめます。

項目内容
なぜ借りるか出口・評判・署名・配達の雑務を自分で用意するのは重い
借りられないものDNS の設定(持ち主しか書けない)と、ドメインの評判を守る運用
入口① HTTP API自分のコードから。冪等キー・id・失敗の理由が使える
入口② SMTPSMTP しか話せないソフトから。ユーザー名 resend、パスワードは API キー
Animemo ではSupabase Auth は SMTP、自前の招待は API
API キーサーバーの環境変数にだけ置く。権限は送信だけに絞る
Supabase組み込み送信はお試し用。Custom SMTP に Resend を登録する

次の作品では、「借りられないもの」の1つ目、Resend のための DNS の設定を1行ずつ見ていきます。

  • メールのしくみ 9 / 11 ― Resend と2つの入口
  • 13 / 13
  • まとめ:Resend と2つの入口
  • Supabase Auth
  • SMTP
  • 登録確認・パスワード再設定
  • smtp.resend.com(465/587)
  • Resend
  • 中身は Amazon SES
  • Fastify(自前)
  • HTTP API
  • 作品・組織への招待
  • POST api.resend.com/emails
  • 次の作品で、Resend にドメインを登録し、DNS に書く行を1つずつ見る。

0 件のコメント

読み込み中…

権利侵害・不適切な内容の連絡: [email protected]