【Firebase】Next.jsアプリでメールを送信する方法|Trigger Email Extensionの使い方(Firebase Extension)

firebase-prograshi(プロぐらし)-kv Firebase
記事内に広告が含まれていることがあります。

Webアプリにメール送信機能を実装したいけれど、サーバーの構築や外部APIとの連携はハードルが高いと感じていませんか?

Next.jsとFirebaseを組み合わせた開発なら、「Trigger Email Extension(拡張機能)」を使うことで、簡単にメール送信システムを構築できます。

Firestoreに特定のデータを保存するだけで、自動的にメールが送信されるため、面倒なバックエンドの実装は一切不要です。

本記事では、Firebase Extensionの導入からNext.jsアプリとの連携、具体的な実装手順を開設しています。


FirebaseにTrigger Email Extension をインストールする

プロジェクトに入り右上の検索窓で「Extension」を検索します。


「拡張機能を探す」をクリックします。


「Trigger Email」を検索し、「Install」をクリックします。


発生する料金の確認

Trigger Emailの利用で発生するコスト

小規模開発やテストであれば、基本は0円に収まりますが、念のためコストも把握しておくことが重要です。

注意点1:待機コスト

Trigger Emailを導入すると、実際に使っていなくても、動かすための待機場所を作るだけで、最低でも毎月1円〜2円($0.01)ぐらいのコストがかかります。ただし、無料枠が残っていれば相殺されます

注意点:パスワード保管コスト

Secret Managerは、メールサーバーにログインするための「パスワードやAPIキー(秘密情報)の安全な保管場所」です。

保管料(アクティブ シークレット バージョン)として、1つの保管(1バージョン)につき、月額 $0.06(約9円) かかります

Google Cloudの公式ルールとして、Secret Managerの保管料の無料枠があります。毎月 6バージョンまで無料です。

注意点:メール送信時のパスワードアクセスコスト

メールを送るために金庫を開けて「パスワードを確認しに行く(アクセスする)回数」に応じた従量課金が発生します。

10,000回アクセスするごとに $0.03(約4.5円) と安いです。

なお、手数料の毎月 10,000回アクセスの無料枠があるので、個人利用や小規模なサービスであればほぼ無料で利用できます。

注意点:イベント有効で発生するコスト

メールが『送信された時』や『失敗した時』に、別のプログラムに通知を送る機能をONにすると、その通知サービス(Eventarc:イベントアーク)の利用料が別途かかります。

イベントを 100万回 配信するごとに $1.00(約150円) ほどかかります

なお、毎月 10万回までタダ で使える無料枠があります

(補足)通常だと「Firestore にデータが書き込まれたらメールを送る」という一方通行の動きしか動しません。


有効化されるリソースの確認

Trigger Emailを有効化すると、以下のリソースが有効化されます。


Eventarc API

前の画面で説明があった、メールの成功・失敗を実況中継するシステム(Eventarc)を使うための許可です。

あくまで「使える状態にするだけ」なので、設定でイベントを有効にしなければお金はかかりません。


Cloud Functions v2(プログラムの本体)

指定したコレクション(例えば mail)に新しいデータが書き込まれたら、それを読み取ってメールを送信し、終わったら「送信完了」と Firestore にステータスを書き戻す仕事をします。


Cloud Secret Manager シークレット

以下の 4 つの重要なパスワードや鍵が、先ほど説明したSecret Managerの中に自動で暗号化されて保管されます。

  1. SMTP_PASSWORD: メールサーバー(SendGridなど)のパスワード
  2. CLIENT_ID: (OAuth2という高度な認証を使う場合の)クライアントID
  3. CLIENT_SECRET: (OAuth2用の)シークレット鍵
  4. REFRESH_TOKEN: (OAuth2用の)リフレッシュトークン
補足

通常のメールサーバーのパスワード(SMTPパスワード)を使う場合は 1番 だけに値が入り、2〜4番は空っぽ(または使わない設定)になります。使わない分にはお金はかかりません。


Eventarc Channel

イベント機能を有効にした場合に作られる、実況中継の「有線ルーター(チャンネル)」のようなものです。ここに送信結果のイベントが流れます。

手動で有効化しなければいけないリソース

なお、「Compute Engine」と「Secret Manager」は有効にするをクリックする必要があります。


Compute Engine(コンピュート エンジン)

拡張機能の本体である「メールを送るプログラム(Cloud Functions v2)」を裏側で動かすための、ベースとなる計算サーバーの機能です。

実際にプログラムがデータを処理してメールを組み立てるための「CPU」や「メモリ」といった、コンピューターの基礎体力を借りるために有効化する必要があります。


Secret Manager(シークレット マネージャー)

メールサーバーのパスワードを安全に保管する「デジタル金庫」の機能です。

いきなり課金はされない

有効化(ONにすること)自体には料金は発生しません。これらを有効にした上で、実際に拡張機能をインストールし、先ほど説明した「無料枠」を超えて使った場合に初めて課金が発生します。


2つとも「有効」にして「次へ」進みます。



サービスアカウントへのアクセス権付与

システムがFirestoreやSecret managerにアクセスするための権限を付与します。


「付与」をクリックします。


設定

Trigger Emailを使うための設定をしてきます。

Cloud Functions location

基本はそのままで大丈夫ですが、もしユーザーや Firestore のデータが日本にあるなら Tokyo (asia-northeast1) を選ぶと、ほんの少し処理が早くなります。(後から変更できません)


Firestore Instance ID

基本は最初から入っているデフォルト((default) など)のままでOKです。


Firestore Instance Location

データベースと同じロケーションを選択します。


Authentication Type

Authentication Typeには「Username & Password」と「OAuth2」があります。

「Username & Password」を使う場合

SendGrid、Mailgun、あるいは通常のメールサーバー(ロリポップやさくら等)の接続情報を使う場合です。

「SMTP connection URI」「SMTP password」が必須となります。(※OAuth2系の設定は不要です)


「OAuth2」を使う場合

Google Workspace(Gmail)などを経由して高度な認証で送る場合です。

「OAuth2 SMTP Host」「OAuth2 SMTP Port」など、OAuth2関連の入力項目が必須になります。(SMTP系の入力は不要です。)


なお、今回はレンタルサーバーのメールアドレスを使うので「Authentication Type」は「Username & Password」とします。


SMTP connection URI

メールサーバーの情報を URL のような1行のテキストにまとめたものです。

基本の形(テンプレート)は以下のようになります。

smtps://ユーザー名@暗号化サーバーのアドレス:ポート番号


例えば、さくらのレンタルサーバーだと以下のようになります。

smtps://your-name@example.com@smtp.sakura.ne.jp:465


SMTP password

メールアドレスのパスワードを入力します。入力したら「シークレット作成」をクリックします。


Email documents collection

メール送信のトリガーになる Firestore のコレクション名です通常、Firebase では mail という名前を設定することが多いです。

firestore.rulsのセキュリティルールを忘れずに!

クライアント側から指定したコレクションへの書き込みを行う場合はセキュリティルールを設定してください。これを怠ると、不正利用されて高額請求が来るリスクがあります。

なお、クライアント側からの書き込みが無い場合は、Trigger Email Extension は独自のセキュリティルールを管理しており、インストール時に mail コレクションへの書き込みを Extension のサービスアカウント経由のみに制限するので、firestore.rulesへの追記は不要です。


Default FROM address

メールが届いたときに、相手の画面に表示される「送信元(差出人)のメールアドレス」のことです。実在する(または所有している)ドメインのアドレスで設定します。

注意点

適当に test@gmail.com や admin@example.com と入力しても、拡張機能の設定自体は完了しますが、実際にはメールが届かない(迷惑メールに分類される)原因になります。必ず、ご自身が所有しているドメインのメールアドレスを入力してください。

システムが自動送信するメール(パスワードリセット、会員登録完了通知など)であれば、noreply@yourdomain.com や info@yourdomain.com にするのが一般的です。


Default FROM address(省略可)

メールを受け取ったユーザーが「返信」ボタンを押したときに、自動的に入力される「返信先のメールアドレス」のことです。

こは空欄のままでも進められます。空欄にした場合は、送信元(FROM)と同じアドレスが自動的に返信先になります。
「ユーザーからの返信は一切受け付けない(返信されても困る)」という運用の場合は、空欄のままで大丈夫です。


Users collection(省略可)

ユーザーのメールアドレスが保存されている Firestore のコレクション(例: users)を登録しておく場所」です。既存のコレクション(あるいは使う予定のコレクション)を指定します。

コレクション名をここで指定すれば、ユーザーID(UID)を使ってメールを送る機能(toUids, ccUids, bccUids)が使えるようになります。

使用条件は、指定したコレクションのデータ構造のドキュメント名がuidで、その中にemailフィールドがあること

具体的には、toUidsなどでuidを指定すると、TriggerEmailが自動的に、指定したコレクション(例:usersコレクション)の中の指定したuidの中のemailフィールドの値を参照します。

// Firestore の mail コレクションに書き込むデータの例
{
  "toUids": ["user_A"],  // 宛先(TO)をユーザーIDで指定
  "ccUids": ["user_B"],  // 同報送信(CC)をユーザーIDで指定
  "bccUids": ["user_C"], // 隠し同報(BCC)をユーザーIDで指定
  "message": {
    "subject": "重要なお知らせ",
    "text": "..."
  }
}
省略した場合は?

省略した場合(空欄にした)場合は、シンプルに「直接メールアドレスを指定する方法」だけを使ってメールを送ることになります。

// Users collection を指定しない場合の書き方
await addDoc(collection(db, 'mail'), {
  to: 'customer@example.com', //  ※「toUids」ではなく「to」を使い、アドレスを直接書く
  message: {
    subject: 'こんにちは',
    text: '...'
  }
});


Templates collection(省略可)

メールの定型文(デザインテンプレート)を保存しておく Firestore のコレクション名(フォルダ名)のことです。

これを使うと、アプリのコード(.ts)側から毎回長い本文や HTML を送る必要がなくなり、「テンプレートAを使って、〇〇さんの名前をはめ込んで送って」というスマートな指示だけで、デザインされた綺麗なメールが送れるようになります。

例えば、設定画面でこの項目に email_templates と入力したとします。事前に Firestore の email_templates コレクションの中に、以下のようなテンプレートを1つ作っておきます。

// Firestore の 「email_templates/welcome」 ドキュメント
{
  "subject": "【重要】{{username}}様、ご登録ありがとうございます",
  "html": "<h1>Welcome, {{username}}!</h1><p>アプリをお楽しみください。</p>"
}

テンプレートを設定しておけば、アプリ側(lib/firestore/~.ts)から送るデータはこれだけで済むようになります。

// テンプレートを使ってメールを送る場合
await addDoc(collection(db, 'mail'), {
  to: 'customer@example.com',
  template: {
    name: 'welcome', //  使うテンプレートのドキュメント名
    data: {
      username: '山田 太郎' //  {{username}} の部分に自動で当てはまる文字
    }
  }
});
Templates collectionを使うメリット

アプリのプログラムの中に直接長い HTML コードを書き込んでしまうと、「メールのデザイン(文言)をちょっと変えたいだけなのに、アプリのプログラムを書き換えて、再デプロイ(リリース)しなきゃいけない」という非常に面倒なことになります。

Templates collectionを使って Firestore 上でテンプレートを管理しておけば、Firebaseの画面から文字やデザインを修正するだけで、アプリを触ることなく一瞬で届くメールの内容を変更できるようになります

※firestore.rules のように firebase deploy コマンド一発でテンプレートを自動的にローカルから Firestore へ同期(アップロード)する仕組みは、デフォルトの Firebase には用意されていません。


Firestore TTL type(省略可)

TTL とは、Time To Live(有効期限) の略です。Firestore に溜まっていくメールの送信履歴(データ)を、一定期間が過ぎたら自動的にゴミ箱にポチッと消去してくれるタイマー機能のことです。

メールを何千通、何万通と送っていると、Firestore の中に送信済みのデータがどんどん溜まっていきます。これは、ストレージ容量(お金)の圧迫を防ぐための仕組みです。

TTL(自動削除)ルールを使うために、Firestoreのデータ(レコード)に expireAt という「有効期限フィールド」を自動で書き加得るかを設定します。

1. Never(デフォルト:何もしない)

expireAt という項目はデータに追加されません。なので、データを自動削除しません。

送信したメールの履歴はずっと Firestore に残り続けます。「過去の送信履歴をずっとログとして残しておきたい」という場合はこれを選びます。


2. Never以外(削除する)

Hour / Day などを選んだ場合は、次の項目(Firestore TTL value)で指定した数字と組み合わせて、「メールが作成されてから〇〇時間後/〇〇日後」という消去期限の日時をデータに自動で書き込みます。

もしここで Day を選び、次の項目(Firestore TTL value)に 30 と入力した場合:

アプリからメールデータを Firestore に追加する。

拡張機能がメールを送信する。

送信完了後、拡張機能がデータの中に自動で expireAt: 2026年6月23日(30日後) というスタンプを押す。

こうしておくことで、後からFirestore側がそのスタンプを見て、30日後にデータを自動でゴミ箱に消去してくれるようになります。


実際、どれを選べばいい?

開発の初期段階や、初めてこの拡張機能を使うのであれば、デフォルトの Never(自動削除しない)のままで進めるのが一番おすすめ です。

  • 最初のうちは「本当にメールが送れたか?」「エラーが起きていないか?」を Firestore の画面(コンソール)を見て確認することが多いため、勝手に消えない方がデバッグしやすい。
  • Firebase の無料枠(Firestore のストレージ容量)の範囲内であれば、数千通程度の履歴が残っていてもお金はほぼかからない。

アプリを正式にリリースして、毎日大量のメールを自動送信するようになってから、「容量節約のために、送信から30日経ったデータは消そう」と Created field などに切り替える、という進め方が一番安全でスマートです。これも後からいつでも設定変更できます。


TLS Options(省略可)

メールサーバーと通信する際の「セキュリティ(暗号化)に関する細かいルールを、JSONという形式のテキストで指定する場所」です。

結論から言うと、ここは完全に空欄(何も入力しない)のままで大丈夫です。

以下のような「超マニアックなセキュリティ設定をカスタマイズしたい時」だけ使います。

  • 自社で独自に構築した、少し古い(あるいは特殊な)メールサーバーを使っている。
  • 安全性の証明書(SSL証明書)のチェックを、あえて「エラーにせず無視して強制送信したい(rejectUnauthorized: false)」。
  • 特定の古い暗号化方式(TLSv1.1など)をあえて許可したい。


詳細パラメータの構成(省略可)

Trigger Emailには、さらに「詳細パラメータ」というマニアックな設定があります。

これらは、メール送信ロボット(Cloud Functions)の「パワー(性能)や、ネットワークの通信経路をどれくらい制限するか」を決める、インフラの細かいチューニング画面です。

基本的には、最初から入っている初期値のままで全く問題ありません


1. 処理時間とパワーに関する設定
  • Function timeout seconds(省略可)
    • 意味: メール送信プログラムが動き出してから、何秒で「タイムアウト(強制終了)」させるかの時間です。
    • 目安: 空欄(デフォルトの60秒)のままで大丈夫です。メール送信は通常1〜2秒で終わるため十分です。
  • Function memory(省略可): 256MiB
    • 意味: ロボットが動くときの「メモリの割り当て量」です。
    • 目安: 256MiB(または初期値)のままで十分です。大量の画像処理などをするわけではないので、これ以上増やすとサーバー費用が無駄に高くなってしまいます。


2. 同時実行数に関する設定(コストとパフォーマンス)
  • Minimum function instances(省略可)
    • 意味: 「最低でも何台のロボットを常に待機(起動)させておくか」です。
    • 目安: 空欄(0)のままにしてください。 ここを 1 以上にすると、メールを1通も送っていない時間でも「常時起動の基本料金」が発生してしまいます。空欄にしておけば、メールが来たときだけ起動する「完全従量課金(無料枠あり)」になります。
  • Maximum function instances(省略可)
    • 意味: 「最大で同時に何台までロボットを増やしていいか」の上限です。
    • 目安: 空欄(自動調整)で構いません。もし「急激なアクセス集中でサーバー代が跳ね上がるのを防ぎたい」という場合は、1020 などの上限数を入れておくと安心です。


3. ネットワークとセキュリティに関する設定
  • VPC Connector / VPC Connector Egress settings(省略可)
    • 意味: 社内ネットワークや、Google Cloud 内の閉じられた安全なネットワーク(VPC)を経由して通信させたい場合に使います。
    • 目安: 通常は使いません。Unspecified(未指定)のままでOKです。
  • Function ingress settings(省略可)
    • 意味: このロボットへのアクセスを「インターネット全体から許可するか」「特定の内部からだけにするか」の制限です。
    • 目安: 空欄(または Allow all / 全て許可)のままで大丈夫です。拡張機能が安全に動くよう自動調整されます。


4. その他の管理用設定
  • Function labels(省略可)
    • 意味: Google Cloud の管理画面で、このロボットに「メール用」「本番環境用」などの「タグ(付箋)」を貼る機能です。
  • KMS key name(省略可)
    • 意味: Googleが用意した暗号化の鍵ではなく、自社で用意した独自の暗号化キー(Key Management Service)を使ってデータを強固に守りたい場合に使用します。
  • Docker repository(省略可)
    • 意味: プログラムのソースコードをビルド(製品化)したデータを保存しておく場所を指定します。


イベントを有効にする(しなくてもいい)

イベントを有効にするにチェックをいれると、メールが送られたタイミング(またはエラーになったタイミング)で、拡張機能が「今、メールを送ったよ」「送信エラーが起きたよ」というシグナル(通知)を周囲に発信するようになります。

もしこのシグナルを受け取りたい場合は、自分で別のプログラム(Cloud Functions など)を書いて待ち構えておく必要があります。

イベントを発信する裏側の仕組み(Eventarc)が動くため、微量ですが追加の費用が発生します

将来的に後からいつでもONにできるので無効のままで問題ありません


拡張機能のインストール

ここまでの設定が終わったらようやく拡張機能のインストールです。

ボタンをクリックするとExtensionsのTrigger Emailがインストールされます。



Trigger Emailデプロイ時のエラー(再インストールで解決)

Permission denied while using the Eventarc Service Agent.(Eventarcサービスエージェントの使用中に権限エラーが発生しました)と言うエラーが発生しました。

これは、Google Cloud側でイベントを配送するロボット(Eventarc)に、「処理を実行するための適切な権限(ロール)」がまだ付与されていない、あるいは反映が追いついていないことが原因で発生しています

おそらく、直前の設定画面で「イベントを有効にする」にチェックを入れた(ONにした)か、拡張機能が内部的に使う Eventarc の初期設定が Google Cloud 側でまだ完了していない状態です。

再インストールで解決

一度アンインストールし、同じ設定で再インストールで解決しました。


エラーの詳細

エラーの内容

下記の詳細を参照してこのエラーを解決してから、拡張機能をもう一度インストールしてください。エラーが引き続き発生する場合は、拡張機能をアンインストールして、デプロイされた可能性のあるすべての拡張機能リソースを削除することをおすすめします。

; RESOURCE_ERROR at /deployments/firebase-ext-firestore-send-email/resources/processQueue: {“ResourceType”:”gcp-types/cloudfunctions-v2beta:projects.locations.functions”,”ResourceErrorCode”:”400″,”ResourceErrorMessage”:{“code”:400,”message”:”Validation failed for trigger projects/stg-slp-app/locations/asia-northeast1/triggers/ext-firestore-send-email-processqueue-340731: Invalid resource state for \”\”: Permission denied while using the Eventarc Service Agent. If you recently started to use Eventarc, it may take a few minutes before all necessary permissions are propagated to the Service Agent. Otherwise, verify that it has Eventarc Service Agent role.”,”status”:”FAILED_PRECONDITION”,”statusMessage”:”Bad Request”,”requestPath”:”https://cloudfunctions.googleapis.com/v2beta/projects/stg-slp-app/locations/asia-northeast1/functions”,”httpMethod”:”POST”}}


Firestoreにセキュリティルールを追加する(必要に応じて)

もし、クライアント側から最初に決めた「Email documents collection」(例: mail)に対して、書き込みを行う場合はセキュリティールールに許可を追記する必要があります。

クライアント側で操作しない場合は不要です。

拡張機能の「読み取り」や「送信結果の書き戻し(アップデート)」のためのルールは不要です。firestore.rules ファイルを開き、「アプリから送信依頼のドキュメントを追加(create)する許可」ように書い以下のルールを追加してデプロイします。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // mail コレクションへのルール
    match /mail/{document} {
      // ⭕️ アプリ(ユーザー)からの「追加(create)」だけを許可する
      allow create: if request.auth != null; // 例:ログイン済みのユーザーなら誰でも送信依頼を出せる
      
      // ❌ get, list, update, delete は書かない(=アプリからは一切禁止にする)
    }
    
  }
}


プログラムからテスト送信する

アプリのコード(lib/firestore/XXX.ts など)から、Firestore にデータを1件追加(Add)するシンプルな「メールアドレスを直接指定する(to)」のテストコードを書きます。

import { getFirestore, collection, addDoc } from 'firebase/firestore';

const db = getFirestore();

export async function testSendEmail() {
  try {
    // 拡張機能が見張っているコレクション(例: 'mail')にデータを追加
    await addDoc(collection(db, 'mail'), {
      to: 'your-email@example.com', // ※実際のメールアドレス(受信できるもの)に変える
      message: {
        subject: 'Firebaseからのテストメール',
        text: 'Trigger Email拡張機能から自動送信されました!成功です!',
      }
    });
    console.log('Firestoreへの書き込みに成功しました!');
  } catch (error) {
    console.error('エラーが発生しました:', error);
  }
}


プログラムからテスト送信する

正しく送信できれば、mailコレクションが生成され、その中に送信済みのデータが格納されます。

タイトルとURLをコピーしました