1通送れた。配信ログもSENT。それなのに、MCPで取得した利用通数は0でした。
blastengineの公式MCPサーバーから自分宛てに1通送り、配信ログとGmailまで照合しました。利用状況のupdated_timeを読むと、23:52の送信より古い23:47:30の値だったと分かりました。「利用0だから未送信」とAIが判断したら、余計な再送をしかねません。
この記事では、送信ツールの返り値から配信IDを追い、送信の結果と利用量の集計を分けて確認する手順を残します。記録は2026年11月4日の1通分です。Gmailでは届いた本文を迷惑メール内に確認しました。
配信ID・配信ログ・受信結果を対応させる
| 確認先 | 今回確認した結果 | そこから言えること |
|---|---|---|
| MCPの送信ツール | delivery_id: 1 |
追跡する配信IDを取得した |
| blastengineの配信ログ | 配信成功、応答コード250 | 配信ログ上で成功と記録された |
| Gmail | 迷惑メール内に本文を確認 | 今回の1通は届いたが、受信トレイには入らなかった |
2026年11月4日23:52 JSTの検証。件名・ステータス・応答コードの部分を切り出しています。
同じ件名のメールをGmailで開いた結果。「以前迷惑メールと判断されたメールに類似」と表示され、指定した本文を確認できました。個人アドレスの部分は撮影範囲から外しています。
これは1通の動作確認です。到達率の比較や、迷惑メール判定の原因特定をした実験ではありません。今回は自分のGmailアドレスを送信元にも使っており、独自ドメインの認証を整えた運用環境とは条件が違います。
まず「送らずに読む」接続を作った
公式マニュアルで紹介されている公開リポジトリを使いました。検証したのはblastengine-mcp-server 0.2.2、コミットは46961dc304824b60311484c6b84bde9f5967796dです。公式リポジトリ
今回はClaude Desktopへ常設する代わりに、小さなNode.jsのMCPクライアントからローカルのstdioサーバーへ接続しました。AIエージェントによる検証作業ですが、Claude Desktopのチャット画面で試した例ではありません。
最初は次の設定で起動しています。
{
"BLASTENGINE_ENABLE_SEND": "false",
"BLASTENGINE_ENABLE_BULK": "false",
"BLASTENGINE_ENABLE_CSV_IMPORT": "false"
}
ログインIDとAPIキーは別途環境変数で渡します。キーを記事、ソースコード、スクリーンショットへ入れないようにします。
この状態でtools/listから15個のツールを取得し、次の二つを呼びました。
| ツール | 確認する内容 | 送信前の結果 |
|---|---|---|
blastengine_usage_latest_get |
利用通数・残量・更新時刻 | 利用0、残り10,000 |
blastengine_mail_results_list |
対象期間の配信ログ | data: [] |
「無効」と「ツール一覧に出ない」は同じではなかった
送信を無効にした起動でも、tools/listにはblastengine_send_transactionが載っていました。ツールが見えるだけで、送信可能と判断してはいけません。
この版のソースでは、送信操作時にBLASTENGINE_ENABLE_SENDを確認する実装になっています。11月4日の実送信検証では、送信無効時の送信ツール自体は呼び出していません。そこで11月7日、次の隔離試験を追加しました。
追試:一覧に載る送信ツールを呼ぶと、上流へ届く前に拒否された
公式MCPサーバー0.2.2をstdioで起動し、送信・一斉配信・CSV取込をすべてfalseにしました。接続先のBLASTENGINE_BASE_URLは自分のPCのHTTPサーバー、認証情報はダミーです。blastengineの実APIへ送信要求を出した試験ではありません。
| 操作 | 実際の結果 | ローカルHTTPサーバーが受けた要求 |
|---|---|---|
tools/list |
送信ツールが一覧に含まれる | 0 |
blastengine_send_transaction |
isError: true、code: send_disabled
|
0 |
blastengine_usage_latest_get |
モックの利用状況を取得 | GET /usages/latest が1件 |
送信ツールには構文上正しい例示用アドレス・件名・本文を渡しました。返答は次のとおりです。
{"code":"send_disabled","message":"BLASTENGINE_ENABLE_SEND=true is required to send transaction mail","retryable":false}
SDKクライアント側でisErrorとコードを検査し、送信呼び出し直後のHTTP要求数が0であることもassertしました。その後に参照系のGETが1件届いたため、単に接続不能だったという結果とも区別できます。参照系の返答値は自作モックの固定値なので、実アカウントの利用状況としては扱いません。
この試験で分かったのは、当該版の送信無効設定が、ツールを隠す方式ではなく実行時に拒否することです。人間の承認済みかをMCPサーバーが自動判断したわけではありません。送信を有効にしたプロセスでは、宛先や本文の承認は別途必要です。
AIと人間がそれぞれ決めたこと
実送信では、人間が宛先・件名・本文・1通という上限を承認しました。AIエージェントは接続設定の準備、ローカルMCPクライアントの実行、配信IDを使ったログの照合を担当しました。迷惑メール内の受信結果と利用状況の基準時刻も確認しています。今回の追試では、AIがダミーの上流を用意し、拒否の返答と要求数を照合しました。
実送信をもう一度行わずに、未確認だった拒否動作を補えました。実サービスへの配送確認と、ローカルでの安全策の検査は、異なる証拠として残しています。
トライアルでは、先に送信先を登録する
管理画面のスタートアップガイドには、トライアルの配信可能アドレスを登録する案内がありました。今回の画面では5件までの登録と説明されていました。
そこで自分が管理する宛先だけを登録し、今回の送信条件を固定しました。
宛先:自分が管理する検証用メールアドレス1件
件名:【アドカレ検証】blastengine受信確認
本文:Qiita記事の動作確認用メールです。返信は不要です。
件数:1通
一斉配信・CSV取込:使わない
宛先が許可リストに入っていることと、今回の本文を送ってよいことも別の確認です。今回は宛先・件名・本文・件数について、人間の承認を得てから実行しています。
MCPを通して送信し、配信IDを受け取る
1通の送信時だけ、別のローカルプロセスでBLASTENGINE_ENABLE_SEND=trueにしました。一斉配信・CSV取込はfalseのままです。実行したツールと引数の形は次です。アドレスは例示に置き換えています。
{
"name": "blastengine_send_transaction",
"arguments": {
"from_email": "sender@example.com",
"to": "recipient@example.com",
"subject": "【アドカレ検証】blastengine受信確認",
"text_part": "Qiita記事の動作確認用メールです。返信は不要です。"
}
}
返った値は次でした。
{
"delivery_id": 1
}
ここで「受信者が読める」とまでは言いません。次はこのIDの結果を調べます。送信用プロセスは終了し、確認は再び送信無効のプロセスで行いました。
管理画面とMCPのログを照合する
blastengine_mail_results_listには、相対的な「今日」ではなく、時差を含む開始・終了時刻を渡しました。
{
"name": "blastengine_mail_results_list",
"arguments": {
"count": 100,
"delivery_start": "2026-11-04T00:00:00+09:00",
"delivery_end": "2026-11-05T00:00:00+09:00"
}
}
結果のうち、今回照合した項目は以下です。宛先等を省いた抜粋です。
{
"delivery_id": 1,
"maillog_id": 1,
"delivery_type": "TRANSACTION",
"status": "SENT",
"last_response_code": "250",
"last_response_message": "配信に成功しました"
}
管理画面の「配信成功」「250」と対応しました。一方、Gmailでは同じ件名と本文を迷惑メール内に確認しています。配信ログの成功を、受信トレイへの配置保証へ読み替えないことが、画面を並べるとよく分かります。
なお、Gmailの表示だけからSPF、DKIM、DMARCのどれが判定原因だったかは特定していません。認証結果のヘッダ照合や、認証済み独自ドメインでの比較は次の検証です。
利用状況には、値と一緒に更新時刻が必要だった
もう一つ気になった点があります。送信後に取得した利用状況には、まだ次の値が返りました。
{
"month": 202611,
"current": 0,
"remaining": 10000,
"updated_time": "2026-11-04T23:47:30+09:00"
}
今回の送信は23:52です。利用状況の更新時刻はそれより前でした。配信ログに1件あるのに利用状況が0だからといって、「送れていないので再送」と判断すると危険です。
この観測から更新間隔の仕様までは断定できません。ただ、AIに残量を要約させるなら「残り10,000通」だけでなく、何時時点の情報かも返してほしいと思いました。
AIの完了報告を「送れました」で終わらせない
| 残すもの | 必要な理由 |
|---|---|
| 承認した宛先・件名・本文・件数 | 送信した内容が依頼と一致するか確かめる |
| delivery_idとmaillog_id | ツールの返り値と配信結果を対応させる |
| 確認した期間・時差 | 別の日や別の配信を調べない |
| 状態・SMTP応答・観測時刻 | API受理、配信結果、古い利用状況を混ぜない |
| 受信側で確認した場所 | 配信ログだけでは分からない配置を記録する |
今回の結果を人が判断できる報告にするなら、次のように書けます。これはMCPの生レスポンスではなく、上記の観測をまとめ直した例です。
対象:今回承認した1通、delivery_id=1
配信ログ:SENT / SMTP応答250、maillog_id=1
受信確認:Gmailの迷惑メール内で同じ件名・本文を確認
利用状況:current=0、remaining=10000
利用状況の基準時刻:2026-11-04 23:47:30 +09:00(23:52の送信より前)
判断:利用0を根拠に再送しない。既存の配信IDを追跡する
未確認:迷惑メール判定の原因、利用状況が反映されるまでの時間
実装するなら、「送信要求」「配信ログの取得」「人による受信確認」を別の状態として保持します。利用量の値だけを見て送信処理へ戻す分岐は作りません。タイムアウトなどで送信結果が不明になった場合も、今回の記録だけでは再送の安全性を保証できないため、結果不明として確認へ回します。
今回の収穫は、MCPでメールを送れたことに加え、配信結果と利用状況の鮮度が別だったことです。AIに運用を手伝わせるときは、値と一緒に「何を、いつ確認したか」を返す必要がありました。
blastengine MCP設定マニュアル/検証した公式リポジトリ
執筆・検証補助にAIを使用しています。実行経路はローカルのMCPクライアントで、Claude Desktopの操作記録ではありません。

