Loading...

2023-11-23(木) 15:00

📭 ResendとSupaase Edge Function でメールを送信する

SupabaseResend
Supabase Edge Function で Resend を使ったメール送信処理を実装する手順を解説します。

目次

前提

この記事では以下を前提としています。

  • Supabase アカウントを作成済みであること
  • Supabase CLI をインストール済みであること
  • Resend アカウントを作成済みであること
  • Resend で独自ドメインの設定が完了していること。この記事ではexample.comを Resend に登録済みであるとします。
  • curlコマンドを使用します

もしまだ Resend のアカウント作成や独自ドメインの設定が完了していない場合は、よければ以下の記事を参考にしてみてください。

⚙️ Resendで独自ドメインを使うための設定手順

Resendで独自ドメインからのメールを送信するために独自ドメインを設定する手順を解説します。

ritaiz.com

この記事のゴール

この記事では、以下をゴールとします。

  • POST リクエストを受けて Resend を使ってメールを送信する Supabase Edge Function で 作成、デプロイする
  • curlコマンドを使って Supabse Edge Function を実行し、動作確認する

この記事は以下の Supabase 公式ドキュメントを参考にしました。

Sending Emails

Sending emails from Edge Functions using the Resend API.

supabase.com

Supabase Edge Function を作成する

ここでは、my-projectというプロジェクト用のディレクトリがあり、その中に Supabase Edge Function を作ります。 以下のようにsupabase functions newコマンドを実行します。 ここでは、resendという名前の Supabase Edge Function を作成します。

ターミナル
$ cd ~/my-project
$ supabase functions new resend
Created new Function at supabase/functions/resend

supabase functions newによってsupabase/functionsにresendが作成されます。 内容は以下のようにindex.tsがあるのみです。ここに Resend を使ったメール送信処理 の内容を記述していきます。

/my-project/supabase/functions
.
├── .vscode
│   ├── extensions.json
│   └── settings.json
└── resend
    └── index.ts

Resend を使ったメール送信処理

以下のように、Supabase Edge Function で Resend を使ったメール送信処理を実装します。

supabase/functions/resend/index.ts
import { serve } from 'https://deno.land/[email protected]/http/server.ts';
 
// Supabaseにセットしたシークレットを使用する
// シークレットの設定方法は後述
const RESEND_API_KEY = Deno.env.get('RESEND_API_KEY');
 
const handler = async (_request: Request): Promise<Response> => {
  // _requestから送信先メールアドレスと送信内容を取得する
  const _requestBody = await _request.json();
 
  // このSupabase Edge Functionでは以下のjsonを受け取ることを想定している
  // {
  // body: {
  //       to: string,
  //       message: string,
  //       subject: string,
  //   },
  // }
 
  const res = await fetch('https://api.resend.com/emails', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${RESEND_API_KEY}`,
    },
    body: JSON.stringify({
      from: 'resend edge function <[email protected]>',
      to: [_requestBody.to],
      subject: _requestBody.subject,
      html: `<h1>以下のお問い合わせを受け付けました。</h1></br>${_requestBody.message}`,
    }),
  });
 
  const data = await res.json();
 
  return new Response(JSON.stringify(data), {
    status: 200,
    headers: {
      'Content-Type': 'application/json',
    },
  });
};
 
serve(handler);

上記の Supabase Edge Function では、以下のフォーマットのデータを受け取ることを想定しています。

Supabase Edge Functionが受信するデータのフォーマット
{
  "body": {
    "to": "送信先メールアドレス",
    "message": "送信内容",
    "subject": "件名"
  }
}

Supabase Edge Function が POST リクエストを通して受け取ったデータを元に、Resend の API を使ってメールを送信します。
なお、メールの送信元はfromの部分で例としてresend edge function <[email protected]>を指定していますが、 ここで指定できるメールアドレスのドメインは Resend に登録完了している独自ドメインのみになります。それ以外の独自ドメインを指定した場合はエラーとなります。

Supabase Edge Function 用のシークレットを設定する

前節のコードの中では、const RESEND_API_KEY = Deno.env.get("RESEND_API_KEY");の部分で Resend 用の API キーを Supabase Edge Function のシークレットから取得して使用しています。 Supabase の Edge Function の中で使用するシークレット(または環境変数)は、Supabase CLI のsupabase secrets set コマンドを使用して設定します。 具体的には、以下を実行することでシークレットを設定できます。

/my-project/supabase
$ supabase secrets set RESEND_API_KEY=re_123456789

supabase secrets setコマンドは以下の構文で使用します。

ターミナル
$ supabase secrets set 環境変数名=値

環境変数の設定が成功すると以下のようなレスポンスが返ってきます。

/my-project/supabase
$ supabase secrets set RESEND_API_KEY=re_123456789
Finished supabase secrets set.

もし上記を実行した時にEnter your project ref:と表示される場合は、自身のプロジェクトの Reference ID を入力する必要があります。

supabase secrets listを実行して設定済みのシークレットを確認することができます。

/my-project/supabase
$ supabase secrets list
 
 
         NAME      │                              DIGEST
  ─────────────────┼───────────────────────────────────────────────────────────────────
    RESEND_API_KEY │ 2c91d2a82x1pa8bba6bc4b438db52811486794916fb1ea14da7d051dd28172d0

デプロイする

以下を実行することで Supabase Edge Function をデプロイします。

supabase/functions/resend
$ supabase functions deploy resend --no-verify-jwt

以下が実行結果です。

supabase/functions/resend
$ supabase functions deploy resend --no-verify-jwt
Version 1.30.3 is already installed
Bundling resend
Deploying resend (script size: 21.26kB)
Deployed Function resend on project xxxxxxxxxx
You can inspect your deployment in the Dashboard: https://supabase.com/dashboard/project/xxxxxxxxxx/functions/resend/details

デプロイが正常に完了すると、以下のように Supabase の管理画面の Edge Function の一覧にデプロイした Edge Function が表示されます。

デプロイしたSupabase Edge Function

上記に表示されているように、デプロイした Supabase Edge Function の URL に対して POST リクエストを送ることで実行します。

動作確認する

動作確認としてデプロイした Supabase Edge Function にcurlコマンドを使って POST リクエストを送信します。 例えば、以下を実行すると、送信した内容に応じたメールを Resend で送信できます。

curlを使ってSupabase Edge Functionを実行する
$ curl -X POST 'https://xxxxxxxxxxxxxxx.supabase.co/functions/v1/resend' \
  -d $'{
    "to": "[email protected]",
    "subject": "Hello World from Supabase Edge Function",
    "message": "メール送信テスト"
  }'

以下が実行結果です。送信したメールの Resend の ID が返ってきます。

curlを使ってSupabase Edge Functionを実行する
$ curl -X POST 'https://xxxxxxxxxxxxxxx.supabase.co/functions/v1/resend' \
  -d $'{
    "to": "[email protected]",
    "subject": "Hello World from Supabase Edge Function",
    "message": "メール送信テスト"
  }'
  {"id":"3b00111a-2918-9312-kj3e-888cc3c3729f"}%

もし Supabase Edge Function の中でfromに指定したメールアドレスのドメインが Resend に登録されていない場合は、以下のようなレスポンスが返ってきます。

Resendに未登録の独自ドメインのメールアドレスをfromに指定した場合
$ curl -X POST 'https://xxxxxxxxxxxxxxx.supabase.co/functions/v1/resend' \
  -d $'{
    "to": "[email protected]",
    "subject": "Hello World from Supabase Edge Function",
    "message": "メール送信テスト"
  }'
{"statusCode":403,"message":"The example.com domain is not verified. Please, add and verify your domain on https://resend.com/domains","name":"validation_error"}%

--no-verify-jwt を付与しない場合

以下のように--no-verify-jwtを付与せずにデプロイした場合は、

supabase/functions/resend
$ supabase functions deploy resend

以下のようにリクエスト元でAuthorizationヘッダーに Supabase の JWT を含めることで Supabase Edge Function を実行できます。

curlを使ってSupabase Edge Functionを実行する
$ curl -X POST 'https://xxxxxxxxxxxxxxx.supabase.co/functions/v1/resend' \
  -H 'Authorization: Bearer eyJhb**********************' \
  -H 'Content-Type: application/json' \
  -d $'{
    "to": "[email protected]",
    "subject": "Hello World from Supabase Edge Function with Auth",
    "message": "認証メール送信テスト"
  }'

JWT がない場合はMissing authorization header、間違っている場合はInvalid JWTというエラーが返ってきます。 ここで指定する JWT は、Supabase のプロジェクトの設定画面(サイドメニューの歯車マークからアクセス)内のAPIタブページ、Project API keysの中にあるanon publicキーを使用できます。

Supabaseのプロジェクトの設定画面のProject API keysのanon publicキー

まとめ

Supabase Edge Function で Resend を使ってメール送信処理を実装する手順を解説しました。
Supabase Edge Function を使うことで HTTP リクエスト経由でメール送信処理を実行したり、他にも Supabase 内のデータベースに新しいデータが追加されたり、更新されたりしたことをトリガに実行もできます。