0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EC-CUBEのメルマガをblastengine MCPから配信する(会員CSVを一斉配信につなぐ)

0
Posted at

EC-CUBEには公式のメルマガ管理プラグインがあり、会員を条件で絞って一斉配信できます。ただし送信するのはEC-CUBEのサーバー自身です。件数が増えるとプロセスを長く占有しますし、到達率やバウンスの追跡はEC-CUBEの外側の話になります。

そこで本記事では、宛先の抽出はEC-CUBEに任せ、配信そのものはblastengineに寄せる構成を、AIエージェント(Claude Code)から扱います。使うのはblastengine MCPサーバーです。

blastengine MCPの導入手順は導入記事、ツールの一覧と入出力は全15ツールの検証記事にまとめてあります。本記事はその続きとして、実際のECサイト運用に組み込むところを扱います。手順はEC-CUBE 4.3.1とblastengine MCP v0.2.1で実際に配信するところまで確認しました。

全体構成

        ┌──────────────────────────────┐
        │        Claude Code           │
        └──────────────┬───────────────┘
                       │ stdio
        ┌──────────────▼───────────────┐
        │      blastengine MCP         │
        └──────────────┬───────────────┘
                       │ blastengine API
        ┌──────────────▼───────────────┐
        │         blastengine          │
        └──────────────────────────────┘
                       ▲
                       │ 宛先CSV(パスだけを渡す)
        ┌──────────────┴───────────────┐
        │      EC-CUBE 4(会員管理)   │
        └──────────────────────────────┘

EC-CUBEは顧客データの正、blastengineは配信基盤、AIはその間の段取りと文章づくり、という並びです。

何をAIに見せて、何を見せないか

先に設計方針を決めておきます。ここを曖昧にしたまま「AIにメルマガを送らせる」と、会員のメールアドレスがまるごとLLMのコンテキストに乗ります。

データ 置き場所 AIに渡すか
会員のメールアドレス一覧 ローカルのCSV 渡さない(ファイルパスだけ渡す)
メルマガの件名・本文 AIが作る 渡す
配信結果・エラーログ blastengine 渡す(宛先アドレスを含む点に注意)

blastengine MCPのblastengine_bulk_import_recipients_csvは、ローカルのCSVパス(csv_path)を受け取ってblastengineへアップロードするツールです。CSVの中身はMCPサーバーのプロセス内で読まれるだけで、LLMのコンテキストには入りません。宛先の実体をAIに見せずに一斉配信できるのは、この設計のおかげです。

一方、配信後に使うblastengine_mail_results_listは宛先ごとのログを返すので、こちらは結果としてメールアドレスがAIに渡ります。バウンス分析をさせるなら、そこは織り込んでおきます。

準備:blastengine MCPを一斉配信モードで登録する

一斉配信とCSVインポートを使うので、BLASTENGINE_ENABLE_BULKBLASTENGINE_ENABLE_CSV_IMPORTを有効にします。トランザクション送信は今回使わないのでfalseのままにしておきます。

claude mcp add blastengine \
  --scope local \
  --env BLASTENGINE_LOGIN_ID="$BLASTENGINE_LOGIN_ID" \
  --env BLASTENGINE_API_KEY="$BLASTENGINE_API_KEY" \
  --env BLASTENGINE_ENABLE_SEND=false \
  --env BLASTENGINE_ENABLE_BULK=true \
  --env BLASTENGINE_ENABLE_CSV_IMPORT=true \
  -- node /absolute/path/to/blastengine-mcp/dist/index.js

有効化フラグは「ツール一覧に出るかどうか」ではなく実行時のゲートとして効きます。BLASTENGINE_ENABLE_BULK=falseのままblastengine_bulk_beginを呼ぶと、下書きは作られずにこう返ります。

{
  "code": "bulk_disabled",
  "message": "BLASTENGINE_ENABLE_BULK=true is required for bulk delivery tools",
  "retryable": false
}

不要なフラグを切っておくほど事故が減るので、使う機能だけを開けます。なお、サーバーはNode.js 22.15以上が必要です(package.jsonのengines)。

手順1:会員CSVを出す

メルマガ管理プラグイン(MailMagazine42)を入れると、会員エンティティにplg_mailmagazine_flg列が追加され、管理画面の会員検索にメールマガジン受信設定の条件が増えます。フロント側では会員登録時とマイページの登録内容変更で、会員自身が受け取る/希望しないを選べます。

値は1が「受け取る」、0が「希望しない」です(プラグインのフォーム定義で確認できます)。列のデフォルトは0なので、プラグインを後から入れた場合、既存会員は全員0から始まります。

配信対象は、この受信設定で絞り込みます。

  1. 管理画面 → 会員管理 で、メールマガジン受信設定が「受け取る」の会員を検索します。必要なら購入回数や最終購入日でさらに絞ります。
  2. 検索結果の画面からCSVをダウンロードします。出力される項目は 設定 → 店舗設定 → CSV出力項目設定 で調整できます。メールアドレスの列名は「メールアドレス」です。

手順2:blastengine用のCSVに変換する

blastengineの一括登録用CSVは、ヘッダーの1項目めがemailである必要があります。文字コードはUTF-8、差し込みコードの上限は50件、ファイルサイズは256MBまでです。

ここで引っかかるのが文字コードです。EC-CUBEのCSV出力は既定でSJIS-win(eccube_csv_export_encoding)なので、そのまま渡すと文字化けするか、取り込みに失敗します。列の並べ替えとあわせて変換します。

import csv

src = "customer.csv"          # EC-CUBEからダウンロードしたCSV(既定は SJIS-win)
dst = "recipients.csv"        # blastengineに渡すCSV(UTF-8)
email_col = "メールアドレス"

with open(src, encoding="cp932", newline="") as f, \
     open(dst, "w", encoding="utf-8", newline="") as g:
    reader = csv.DictReader(f)
    writer = csv.writer(g)
    writer.writerow(["email"])
    seen = set()
    for row in reader:
        addr = (row.get(email_col) or "").strip()
        if addr and addr not in seen:
            seen.add(addr)
            writer.writerow([addr])

eccube_csv_export_encodingをUTF-8に変更している環境なら、読み込み側をutf-8-sigにしてください。どちらか分からないときはfileコマンドか、先頭数バイトを見て判断します。

出力は次のようになります。改行コードはCRLFのままで問題なく取り込めました。

email
member1@example.com
member2@example.com

差し込みを使う場合は、2列目以降に差し込みコードの列を足します。本文側では__prop1__のように記述した箇所が置き換わります。キーに使えるのはASCIIの英数字だけです。CSVのヘッダー名の書式は、blastengineの管理画面からダウンロードできるサンプルCSVで実際の形を確認してから決めてください。

手順3:一斉配信を組み立てる

blastengineの一斉配信は、下書きの作成 → 宛先の登録 → 内容の確認 → 確定、という多段構成です。ツールもその順に対応しています。

順序 ツール 内容
1 blastengine_bulk_begin 送信元・件名・本文を指定して下書き(EDIT状態)を作る
2 blastengine_bulk_import_recipients_csv ローカルCSVから宛先を一括登録する
3 blastengine_bulk_import_status インポートジョブの状況と件数を確認する
4 blastengine_bulk_preview 件名・送信元・宛先数・本文サマリを人が確認する
5 blastengine_bulk_commit_immediate / blastengine_bulk_commit_scheduled 即時または予約で確定する

Claude Codeへの指示はこうなります。

blastengineで一斉配信の下書きを作って。
送信元は news@example.com(表示名は「EXAMPLE STORE」)、
件名は「【EXAMPLE STORE】今週の新着商品のご案内」。
本文はこの内容で(略)。
宛先は ./recipients.csv から取り込んで。即時配信はしないで。

bulk_beginは下書きのdelivery_idを返します。続くCSVインポートはジョブとして走り、job_idが返ります。

{ "job_id": 42, "immediate": false, "warning": "CSV import will not trigger immediate delivery." }

immediateは必ずfalseのままにします。trueにするとインポート完了と同時に配信が走るため、内容を確認する前に送信が終わります。

インポートの完了はbulk_import_statusで確認します。

{ "total_count": 1, "percentage": 100, "success_count": 1, "failed_count": 0, "status": "FINISHED" }

failed_countが0でない場合は、blastengine_bulk_import_error_downloadでエラー内容のzipをローカルに保存して中身を確認します。

宛先が50件以下ならblastengine_bulk_update_recipientsでも登録できますが、既定の上限は50件(BLASTENGINE_BULK_MAX_RECIPIENTS)です。メルマガの規模ならCSVインポート一択になります。

続いてプレビューします。

{
  "delivery_id": 1258,
  "subject": "【EXAMPLE STORE】今週の新着商品のご案内",
  "from": { "email": "news@example.com", "name": "EXAMPLE STORE" },
  "recipient_count": 1,
  "body_summary": "EXAMPLE STORE をご利用いただきありがとうございます。 今週の新着商品から...",
  "note": "This preview is informational only. It does not authorize or block commit. Bulk commit tools execute directly when BLASTENGINE_ENABLE_BULK=true."
}

noteにあるとおり、プレビューは情報を見せるだけで、確定を承認したり止めたりする効果はありません。ENABLE_BULKが有効なら、確定ツールはプレビューを経由しなくても実行できます。送信の可否を判断するのは人間側だと理解しておいてください。

内容に問題がなければ確定します。予約配信にする場合、時刻はタイムゾーンオフセット付きのISO 8601で指定します。「明日の10時」のような相対表現は受け付けないので、具体的な時刻に解決してから渡します。

配信ID 1258 を 2026-09-01T10:00:00+09:00 に予約配信で確定して。

手順4:配信結果をEC-CUBE側に戻す

配信後は、宛先ごとのログを確認します。

{
  "delivery_id": 1258,
  "maillog_id": 1275,
  "delivery_type": "BULK",
  "email": "member1@example.com",
  "status": "SENT",
  "last_response_code": "250",
  "last_response_message": "配信に成功しました",
  "open_time": null
}

ハードバウンス(HARDERROR)したアドレスは、EC-CUBE側でメールマガジン受信設定を「希望しない」(0)に変更します。会員データの更新なので、管理画面から直すか、bin/consoleで自作コマンドを書くことになります。件数が多いなら後者です。

配信情報と配信ログは、配信開始から62日で削除されます。長期の到達率推移を残したいなら、この期間内に自分側へ吸い出しておく必要があります。

エージェントに任せたときに起きること

ここまでの手順をClaude Codeに指示して実際に回すと、ツールを直接叩くのとは違う挙動がいくつか出ます。実際に確認できたものを挙げておきます。

まず、送信のような取り消せない操作の手前で、エージェントは自分から止まって確認を求めてきます。対話で使っている限りはこれが承認ゲートとして働くので都合がいいのですが、非対話(claude -p)で回すときは、止まったまま何も起きずに終わります。バッチに載せるなら、プロンプトの中で「確認は取れている、追加の確認は不要」と明示的に承認を与える必要があります。

次に、許可していないツールを呼ぼうとすることがあります。今回は件名の丸括弧を半角から全角に直そうとして、許可リストに入れていないblastengine_bulk_update_recipientsを呼び、拒否されて止まりました。許可リストを絞るのは正しいのですが、絞った結果どこで詰まるかは事前に読み切れません。実行結果のpermission_denialsを必ず見てください。

そして、指示していない細部をエージェントが整えようとすることがあります。上の件名の例がまさにそれです。件名や本文の表記をこちらで確定させたい場合は、「表記はこのままで、修正しないでください」と明示するほうが確実です。

宛先を登録していない下書きに対してblastengine_bulk_previewを呼ぶと、件名も宛先件数もnullで返ります。プレビューが空に見えたら、CSVインポートがまだ終わっていないと考えてください。

そして最も注意したいのが、送信ツールが成功を返しても、それは「blastengineが受け付けた」という意味でしかない点です。配信可能アドレスに登録していない宛先の場合、ツールはdelivery_idを返して成功したように見えますが、実際には配信ログ側でDROP、レスポンスコード554(rejection)になります。エージェントは戻り値だけを見て「送信しました」と報告するので、到達の確認まで指示に含めておいてください。

送信したら、配信ログでstatusとレスポンスコードまで確認して報告して。

つまずきやすいポイント

症状 原因と対処
CSVを取り込むと文字化けする EC-CUBEのCSV出力は既定でSJIS-win。UTF-8に変換してから渡す
CSVインポートが弾かれる ヘッダー1項目めがemailか、拡張子が.csvかを確認する。URL指定や空ファイルは不可
宛先が50件で頭打ちになる blastengine_bulk_update_recipientsの既定上限。CSVインポートを使う
予約時刻が受け付けられない オフセット付きのISO 8601が必須。2026-09-01のような日付のみは不可
送信は成功したのにメールが届かない 配信可能アドレスに未登録の宛先は、送信ツール側ではエラーにならず配信ログでDROP / 554(rejection)になる。成否は必ず配信ログで確認する(トライアルの登録上限は5件)
送信済みの配信をもう一度確定してしまった timeoutが返ることがある。実体は404だが、APIの応答が既定のタイムアウト(30秒)より遅い。BLASTENGINE_TIMEOUT_MSを伸ばすと本来のエラーを確認できる
送信直後に使用量が増えていない usage_latest_getの集計には反映のラグがある。送信の成否は配信ログで確認する
62日より前の配信が検索できない 保管期限による削除。期限内にエクスポートしておく
MCPサーバーが起動しない Node.js 22.15以上が必要。バージョンを確認する
非対話実行でAIが確認を求めて止まる 送信前にエージェントが承認を求める。プロンプトで明示的に承認を与える
プレビューがnullばかり返る 宛先が未登録の下書き。CSVインポートの完了を先に確認する

発展:EC-CUBE側もMCPでつなぐには

宛先の抽出まで会話で完結させたいなら、EC-CUBE側にもMCPを用意する手があります。EC-CUBEには公式のWeb APIプラグインApi42)があり、GraphQLで商品・受注・顧客を取得できます。エンドポイントはhttps://<ホスト名>/api、認可はAuthorization Code Flowのみ、スコープはreadwriteの2つです。

GraphQLをそのままMCPとして喋らせるなら、汎用のmcp-graphqlが使えます。Mutationは既定で無効なので、参照だけならこの設定で足ります。

claude mcp add eccube \
  --env ENDPOINT=https://<ホスト名>/api \
  --env 'HEADERS={"Authorization":"Bearer <アクセストークン>"}' \
  --env ALLOW_MUTATIONS=false \
  -- npx -y mcp-graphql

ただし、この構成には先に知っておいたほうがいい制約が2つあります。

1つめは権限の粒度です。EC-CUBEのスコープはリソース単位に分かれていないため、readを渡した時点でAIはcustomersクエリを投げて会員のメールアドレスを取得できます。mcp-graphqlのREADME自身も、絞り込みたいなら自前のMCPを書いてロックダウンするよう勧めています。本番サイトに常時つなぐなら、クエリを固定した自作MCP(独自ツールを追加する記事と同じ要領で書けます)に置き換えるのが安全です。

2つめはアクセストークンの寿命です。Authorization Code Flowで発行されるトークンの有効期限は3600秒なので、HEADERSに静的に書くとすぐ切れます。リフレッシュトークンで更新する仕組みが別に要ります。

なお、筆者の検証環境(Docker上のEC-CUBE 4.3.1にtarballからプラグインを導入)では、このGraphQLエンドポイントを動かすところまで到達できませんでした。プラグインのcomposer依存が自動では入らない、webonyx/graphql-phpの要求バージョンがセキュリティアドバイザリでブロックされる、composerのレシピがOAuthバンドルを二重登録する、といった手当てが続き、最後はOAuthの鍵設定で止まっています。オーナーズストア経由の正規導入なら結果は変わる可能性がありますが、少なくとも「軽く試す」構成ではありません。

宛先の抽出は管理画面のCSVで足りるので、まずは本記事の主線で運用を回し、必要になった段階でEC-CUBE側のMCP化を検討するのが現実的だと思います。

EC-CUBE標準のメルマガ機能との使い分け

すべてをblastengineに寄せる必要はありません。判断の目安を挙げておきます。

  • 会員数が少なく、テンプレート管理と配信履歴がEC-CUBE内で完結していれば十分な場合は、メルマガ管理プラグインのままで問題ありません。
  • 配信件数が増えてEC-CUBEのプロセスを長く占有するようになった、あるいはバウンスの内訳やレスポンスコードまで追いたくなったら、配信基盤を外に出す判断になります。
  • 注文確認メールなどのシステムメールは今回の構成とは別の話で、そちらはEC-CUBEのMAILER_DSNをblastengineのSMTPに向けるほうが素直です。blastengine側の配信一覧にはSMTP種別として結果が入るので、ログの確認方法は共通化できます。

まとめ

EC-CUBEのメルマガをblastengine MCPに寄せる構成のポイントは3つです。

  • 宛先の実体はCSVのままにして、blastengine MCPにはパスだけを渡す。会員のメールアドレスをLLMのコンテキストに載せずに一斉配信できる
  • EC-CUBEのCSV出力は既定でSJIS-win、blastengineの一括登録CSVはUTF-8で1列目がemail。ここの変換が実務上の最初の関門になる
  • 一斉配信は下書き → 宛先登録 → プレビュー → 確定の多段。immediatefalseを厳守し、プレビューは判断材料であって承認ではないと理解しておく

EC-CUBE側もMCPでつなぐ発展形はありますが、Web APIプラグインの導入コストは小さくありません。まずはCSVで橋渡しする構成から始めるのがおすすめです。


blastengine MCPサーバーへの要望や感想は、以下のアンケートフォームから送ると開発チームに届くみたいです。

https://docs.google.com/forms/d/e/1FAIpQLSdNZ9TswUT3JEv3pMHkJGqOvgmsXuKP1smkJiNEsqbTVDwRyg/viewform

※本記事の手順はEC-CUBE 4.3.1-p1、メルマガ管理プラグイン4.3.0、blastengine MCPサーバー v0.2.1で確認しました。仕様はバージョンにより変わり得ます。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?