【第2回】受信メールを解析して自動応答!Cloudflare Email Routing + postal-mime で文字化けのない自動返信システムを作ろう

受信したメールを解析してresendで自動返信する流れ プログラミング

サーバーの維持費を0円(無料枠内)に抑えるモダンメールサーバー構築連載の第2回目です。

前回は、ResendとCloudflare Workersを連携させてローカル環境で「プログラムからメールを送信する」ところまでを実装しました。

今回は、独自ドメイン宛てに届いたメールをCloudflareでキャッチし、プログラム(Cloudflare Workers)で「誰から、どんな件名・本文で届いたか」を解析して、自動で返信を戻す仕組みを作っていきます。

メール受信のプログラムで最大の難所となる「文字化け対策」もクリアしていきます。

1. 今回実装する「受信・自動応答」のフロー

今回作成するプログラムの動きは以下の通りです。

cloudflareからresendAPIのメール送信の流れ
[差出人 (Gmail等)] 
       │ 1. メール送信 ([email protected])
       ▼
[Cloudflare Email Routing] 
       │ 2. イベント検知・Workerへ転送
       ▼
[Cloudflare Workers (email ハンドラ)]
       │ 3. RAWデータを postal-mime で解析 & 文字化けデコード
       ▼
[Resend API] ──► 4. 差出人へ自動応答メール送信 (引用付き)
  1. ユーザーが [email protected] 宛てにメールを送信する
  2. Cloudflare Email Routing がメールを検知し、そのまま Workers へ転送する
  3. Workers(プログラム) が起動し、届いた生(Raw)データを解析する
  4. 解析した「送信元のメールアドレス」に向けて、Resend経由で自動応答メール(本文引用付き)を送信する

2. Cloudflareのメールルーティング設定

まずは、独自ドメインに届いたメールをWorkerに流し込むための設定をCloudflareの管理画面で行います。

設定手順

  • Cloudflareのダッシュボードにログインし、対象のドメインを選択します。
  • 左メニューの 「メールサービス」>「Email Routing」 > タブを開きます。
メールルーティングを有効化するぺーじのスクリーンショット
  • 右上の「ドメインをオンボード」のボタンを押して独自ドメインを選択します。
  • 「Email Routing」で先ほど追加した独自ドメインを選択します。
  • 「ルーティングルールタブ」を選択して、「ルールを作成」 ボタンをクリックし、以下のように入力します。
メールルーティングルールを作成する画面のスクリーンショット
  • メール パターン: info (※独自ドメインの左側に info と入力)
  • アクション: Worker に送信
  • 宛先 Workers: 前回のコマンドで作成したWorkerを選択
  • 右下の「保存」をクリックします。

これで、info@独自ドメイン宛てのメールが、リアルタイムにあなたのプログラムへ転送されるようになります。

3. 必要なライブラリのインストール

メールの受信データは、裏側では MIME(Multipurpose Internet Mail Extensions) という非常に複雑なフォーマットの長文テキスト(RAWデータ)で届きます。

これを自力でパース(解析)するのは困難ですが、従来からあるNode.js向けのメール解析ライブラリ(mailparser など)はサイズが大きく、Node.js固有のモジュールに依存しているため、Cloudflare Workersのエッジ環境では動かないケースがあります。

そこで活用するのが postal-mime です。

💡 postal-mime を選ぶメリット

  • 超軽量・依存ゼロ: WorkersのV8アイソレート環境に最適化されています。
  • Web APIs準拠: Stream や Uint8Array をそのまま扱え、高速にパース処理が行えます。
MIMEによって暗号化されたメール内容を解析する流れ

ターミナルでプロジェクトのフォルダを開き、以下のコマンドで導入します。

npm install postal-mime

4. 受信・解析・自動応答プログラムの実装

それでは、src/index.ts のコードを丸ごと書き換えていきましょう。 今回は、Webからのリクエストを受ける fetch だけでなく、メール受信イベントを受け取る email というWorkers専用の機能を新しく追加します。

解説コメントを付けた完成版コードがこちらです。

import { Resend } from 'resend';
import PostalMime from 'postal-mime';
// 環境変数の型定義(前回のキーを引き続き使用します)
export interface Env {
  RESEND_API_KEY: string;
}
export default {
  // ■ 1. Web(API)からのリクエストを受け付ける関数(第1回で実装したもの)
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);
    if (request.method !== 'POST' || url.pathname !== '/send') {
      return new Response('Not Found', { status: 404 });
    }
    // (中略:前回の送信ロジックがそのまま動きます)
    return new Response('Fetch endpoint active', { status: 200 });
  },
  // ■ 2. 【今回新規追加】独自ドメイン宛てにメールが届いたときに自動実行される関数
  async email(message: ForwardableEmailMessage, env: Env, ctx: ExecutionContext): Promise<void> {
    try {
      // ① Cloudflareから届いたメールの「生データ(Raw Email)」をストリームとして取得
      const rawEmailStream = message.raw;
      
      // ② postal-mime を使って、生データを解析(パース)する
      const parser = new PostalMime();
      const parsedEmail = await parser.parse(rawEmailStream);
      // ③ 解析データから「送信元」「件名」「本文」を抽出
      const fromAddress = message.from; // 送信元のメールアドレス
      const subject = parsedEmail.subject || 'No Subject'; // メールの件名
      const bodyText = parsedEmail.text || '本文なし'; // メールの本文(テキスト)
      // 日本語の文字化け(MIMEエンコード)を防ぐための「デコード(復元)」処理
      // ※件名や本文が `=?UTF-8?B?...=` のような謎の文字列になっているのを日本語に戻します
      const decodedSubject = decodeMimeHeader(subject);
      // ④ 自動応答のメール本文を作成(相手の本文を引用)
      const replyText = `メールを受け付けました。
件名: ${decodedSubject}
本文:
------------------------------------------
${bodyText}
------------------------------------------
※このメールはシステムより自動送信されています。`;
      // ⑤ Resendを使って、メールを送ってきた相手に自動返信を送信!
      const resend = new Resend(env.RESEND_API_KEY);
      await resend.emails.send({
        from: '[email protected]', // あなたの独自ドメインアドレス
        to: [fromAddress],             // メールの差出人(相手のアドレス)
        subject: `【自動応答】${decodedSubject}`,
        text: replyText,
      });
    } catch (error: any) {
      console.error('メール処理中にエラーが発生しました:', error.message);
      // 注意: ここでエラーを throw するとCloudflare側でメールが「一時不達」となり再送され続けます。
      // ログを出力して処理を正常に終了させるのが安全です。
    }
  }
};
/**
 * 【文字化け対策ヘルパー関数】
 * メールヘッダー(件名など)のMIMEエンコードを検知し、正しい日本語(UTF-8)にデコードします。
 */
function decodeMimeHeader(header: string): string {
  // =?UTF-8?B?BASE64文字列?= のパターンを検出する正規表現
  const mimeRegex = /=\?UTF-8\?B\?([^\?]+)\?=/gi;
  
  return header.replace(mimeRegex, (_, base64Str) => {
    try {
      // Base64をバイナリデータに変換し、TextDecoderで日本語文字列に戻す
      const binaryString = atob(base64Str);
      const len = binaryString.length;
      const bytes = new Uint8Array(len);
      for (let i = 0; i < len; i++) {
        bytes[i] = binaryString.charCodeAt(i);
      }
      return new TextDecoder('utf-8').decode(bytes);
    } catch (e) {
      return header; // デコードに失敗した場合は元の文字列をそのまま返す
    }
  });
}

5. 本番へのデプロイと動作確認

ローカル環境ではメールの実際の「受信イベント」をテストするのが難しいため、一度Cloudflareの本番環境へデプロイ(公開)してテストします。

1. 本番用のAPIキーを登録する

今まではローカルでテストしていたため、APIキーを wrangler.jsonc 内の “vars” に書いていました。 本番のCloudflare環境にAPIキーを安全に保存するため、PowerShellで以下のコマンドを実行します。

※ Wranglerが起動したままになっている場合は、起動している方のウィンドウで Ctrl + C を押して一度終了させてから実行してください。

npx wrangler secret put RESEND_API_KEY

実行すると、ターミナルで ✔ Enter a secret value: とAPIキーの入力を求められます。 ここに ResendのAPIキー(re_xxxx…) を貼り付けて Enter を押してください。

2. クラウドにデプロイする

以下のコマンドを実行して、プログラムをCloudflareのサーバーにデプロイ(アップロード)します。
補足: npm run deploy は内部的に npx wrangler deploy を実行しています。

npm run deploy

デプロイが成功すると、画面に以下のようなURLが表示されます。

https://mail-serverless.<あなたのユーザー名>.workers.dev

これで、あなたのメールサーバープログラムが世界中からアクセスできる状態(サーバーレス)になりました。

実際にメールを送ってテストする

設定が完了したら、普段使っている個人用のGmailなどから、独自ドメインのアドレス宛てにテストメールを送信してみましょう。

送ったGmailの受信トレイに、「【自動応答】テストメール」 という件名で、自分の送った本文が綺麗に引用された返信メールが届くはずです。

まとめと次回予告

第2回では、Cloudflare Email Routing と postal-mime を組み合わせ、「受信メールの解析」 から 「文字化けのない自動返信」 までの高度な処理を完全無料で構築しました。

  • セキュアな API Key 管理(wrangler secret)
  • サーバーレスだから待機コスト0円
  • postal-mime による軽量かつ確実なパース

『プログラムからの自動返信はできたけれど、自分から普通に手動で返信したいときはどうするの?』

「自動返信ができるようになったけれど、自分から手動で返信・送信したい時はどうするの?」

第3回はいよいよ連載の最終回です!今回作った仕組みをベースに、「普段使っているWeb版Gmailの画面から、独自ドメインアドレス(info@…)差出人としてメールを送受信できるようにするGmail連携設定」 を分かりやすく解説します。

是非以下の記事をご覧ください!

コメント