Customers Mail CloudのWebhookは2種類あります。
- メール受信時
- メール送信時
メール受信時のWebhookはその名の通り、メールを受け取った際に任意のURLをコールするものです。この記事では添付ファイル付きメールを受け取った際のWebhook処理について解説します。
フォーマットはマルチパートフォームデータ
Webhookの形式として、JSONとマルチパートフォームデータ(multipart/form-data)が選択できます。この二つの違いは、添付ファイルがあるかどうかです。JSONの場合、添付ファイルは送られてきません。今回のようにメールに添付ファイルがついてくる場合は、後者を選択してください。

送信されてくるデータについて
メールを受信すると、以下のようなWebhookが送られてきます(データは一部マスキングしています)。JSONにしていますが、実際にはmultipart/form-dataです。
{ "filter": "info@smtps.jp", "headers": [ {name: 'Return-Path', value: '<user@example.com>'}, : {name: 'Date', value: 'Thu, 27 Apr 2023 15:56:26 +0900'} ], "subject": "Webhookのテスト", "envelope-to": "user@smtps.jp", "server_composition": "sandbox", "html": "<div dir=\\\\\\\\\\\\\\\\"ltr\\\\\\\\\\\\\\\\">Webhookのテスト用メールです。<div>...</div></div>", "text": "Webhookのテスト用メールです。\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\n\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\n--\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\n...", "envelope-from": "info@smtps.jp", "attachments": 1, "attachment1": "...." }
AWS Lambdaの準備
AWS Lambdaで新しい関数を作成します。その際、条件として以下を指定します。
- ランタイム
Node.js 22.x - 関数 URL を有効化
チェックを入れる - 認証タイプ
NONE
関数の作成が完了したら、関数コードを編集します。ベースになるコードは以下の通りです。
export const handler = async (event) => { // TODO implement const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
JavaScriptのコード
処理は index.mjs に記述します。
export const handler = async (event) => { // TODO implement const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
マルチパートフォームデータを取得する
添付ファイルを処理する際には busboy というライブラリを利用します。
import Busboy from 'busboy';
そして、全体を Promise でラップします。
export const handler = async (event) => { const { body } = await new Promise((resolve, reject) => { const busboy = Busboy({ headers: { 'content-type': event.headers['Content-Type'] || event.headers['content-type'], }, }); const result = { files: [], fields: {}, }; busboy.on('file', (fieldname, file, filename, encoding, mimetype) => { const fileData = []; file.on('data', (data) => { fileData.push(data); }).on('end', () => { result.files.push({ fieldname, filename: typeof filename === 'string' ? filename : decodeFilename(filename.filename), encoding, mimetype, content: Buffer.concat(fileData), }); }); }); busboy.on('field', (fieldname, val) => { result.fields[fieldname] = val; }); busboy.on('finish', () => { resolve({ statusCode: 200, body: result, }); }); busboy.on('error', (error) => { reject({ statusCode: 500, body: JSON.stringify({ error: error.message }), }); }); busboy.write(event.body, event.isBase64Encoded ? 'base64' : 'binary'); busboy.end(); });
decodeFilename は、ファイル名のデコードを行う関数です。日本語ファイル名の場合に利用できます。
const decodeFilename = (encodedFilename) => { // エンコード形式の解析 const matches = encodedFilename.match(/=\?([^?]+)\?([BQ])\?([^?]+)\?=/i); if (!matches || matches.length !== 4) { throw new Error("無効なエンコード形式です"); } const charset = matches[1]; // 文字セット(例: UTF-8) const encodedText = matches[3]; // エンコードされたテキスト const buffer = Buffer.from(encodedText, 'base64'); // バッファを指定された文字セットでデコード return buffer.toString(charset); }
そして、処理した結果は body に入ります。
console.log(body.files.length); // 添付ファイルの数 console.log(body.files[0].filename); // 1つ目の添付ファイルのファイル名 console.log(body.fields.server_composition); // pro
ファイルを保存する場合には、 content にデータが入っています。
console.log(body.files[0].content); // ファイルの内容(Buffer.concat(fileData)した内容)
Webhookの結果は管理画面で確認
Webhookでデータが送信されたログは管理画面で確認できます。送信時のAPIキー設定など、HTTPヘッダーを編集するといった機能も用意されていますので、運用に応じて細かなカスタマイズが可能です。

まとめ
メールと連携したシステムはよくあります。通常、メールサーバを立てて、その中で処理することが多いのですが、メールサーバが落ちてしまうとシステムが稼働しなくなったり、メール文面の解析が煩雑でした。Customers Mail Cloudを使えばそうした手間なくJSONで処理できて便利です。
添付ファイルまで処理対象にしたい時には、この方法を利用してください。
