blastengine APIを利用した一斉配信を行う際、「配信登録ができなくなった」というトラブルに遭遇したことはありませんか?これは多くの場合、EDIT状態の配信が上限に達していることが原因です。本記事では、この配信登録上限の仕組みを解説し、APIを活用した具体的な対処法を紹介します。
blastengineの配信ステータス管理の概要
ステータス一覧(EDIT / RESERVE / SENT / FAILED)
blastengineでは、配信の状態を以下のステータスで管理しています。
| ステータス | 説明 |
|---|---|
| EDIT | 編集中 |
| IMPORTING | 配信アドレス一括インポート中 |
| RESERVE | 配信予約済 |
| WAIT | 配信待ち |
| SENDING | 配信中 |
| SENT | 配信成功 |
| FAILED | 配信失敗 |
これらのステータスはAPIレスポンスおよびダッシュボードで確認でき、配信一覧API(GET /deliveries)のstatusパラメータでフィルタリングすることも可能です。
EDITステータスとは?
EDITは「編集中」を表すステータスで、一斉配信(BULK)の配信登録を開始した直後の状態です。この段階では、件名・本文・送信先アドレスなどの設定途中であり、配信予約が確定していません。
一斉配信の基本的な流れは以下のようになります
-
POST /deliveries/bulk/beginで配信登録を開始 → EDIT状態 -
PUT /deliveries/bulk/update/{delivery_id}で内容を更新(オプション) -
POST /deliveries/{delivery_id}/emailsで配信先アドレスを登録 -
PATCH /deliveries/bulk/commit/{delivery_id}で配信予約を確定 → RESERVE状態
重要なポイント:EDITステータスの配信は、配信登録上限のカウント対象となります。
上限の仕様
blastengine APIでは、配信ステータスがEDITの配信が30件に達すると、それ以上配信登録ができなくなります。
この制限の意図は、未完了の配信が大量に滞留することを防ぎ、システムリソースを適切に管理することにあります。追加で配信登録を行う場合は、EDITの配信を完了(RESERVE状態へ遷移)させるか、削除する必要があります。
制限回避の実装例
1. EDIT配信の自動削除バッチ
一定期間以上経過したEDIT配信を自動削除するバッチ処理を実装することで、上限問題を予防できます。
Python実装例
import requests
from datetime import datetime, timedelta, timezone
def cleanup_old_edit_deliveries(bearer_token, days_threshold=7):
"""
指定日数以上前に作成されたEDIT配信を削除
Args:
bearer_token: API認証トークン
days_threshold: 削除対象とする経過日数(デフォルト7日)
"""
headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json"
}
# EDIT状態の配信を取得
response = requests.get(
"https://app.engn.jp/api/v1/deliveries",
headers=headers,
params={"status[]": "EDIT", "size": 100}
)
if response.status_code != 200:
print(f"配信一覧の取得に失敗: {response.status_code}")
return
deliveries = response.json().get("data", [])
threshold_date = datetime.now(timezone.utc) - timedelta(days=days_threshold)
deleted_count = 0
for delivery in deliveries:
created_time = datetime.fromisoformat(
delivery["created_time"].replace("+09:00", "+09:00")
)
# 閾値より古い配信を削除
if created_time < threshold_date:
delivery_id = delivery["delivery_id"]
delete_response = requests.delete(
f"https://app.engn.jp/api/v1/deliveries/{delivery_id}",
headers=headers
)
if delete_response.status_code == 200:
print(f"削除成功: ID={delivery_id}, 作成日={delivery['created_time']}")
deleted_count += 1
else:
print(f"削除失敗: ID={delivery_id}, エラー={delete_response.text}")
print(f"クリーンアップ完了: {deleted_count}件削除")
return deleted_count
# 実行例(7日以上前のEDIT配信を削除)
cleanup_old_edit_deliveries(bearer_token, days_threshold=7)
2. EDIT配信が既に30件近い場合の自動完了処理
上限に近づいた場合、必要な配信を自動的に完了(RESERVE状態へ遷移)させる処理も有効です。
def auto_commit_if_near_limit(bearer_token, threshold=25):
"""
EDIT配信数が閾値を超えた場合、
配信先アドレスが登録済みの配信を自動的に即時配信する
"""
headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json"
}
# EDIT状態の配信を取得
response = requests.get(
"https://app.engn.jp/api/v1/deliveries",
headers=headers,
params={"status[]": "EDIT", "size": 100}
)
deliveries = response.json().get("data", [])
if len(deliveries) < threshold:
print(f"EDIT配信数: {len(deliveries)} - 閾値未満のため処理スキップ")
return
print(f"[WARNING] EDIT配信数が閾値を超えました: {len(deliveries)}/{threshold}")
# 配信先アドレスが登録済みの配信を即時配信
for delivery in deliveries:
delivery_id = delivery["delivery_id"]
# 配信詳細を取得して配信先件数を確認
detail_response = requests.get(
f"https://app.engn.jp/api/v1/deliveries/{delivery_id}",
headers=headers
)
if detail_response.status_code == 200:
detail = detail_response.json()
total_count = detail.get("total_count", 0)
if total_count > 0:
# 即時配信を実行
commit_response = requests.patch(
f"https://app.engn.jp/api/v1/deliveries/bulk/commit/{delivery_id}/immediate",
headers=headers
)
if commit_response.status_code == 200:
print(f"即時配信開始: ID={delivery_id}, 宛先数={total_count}")
# アラート通知(Slack等への連携を想定)
send_alert(f"配信ID {delivery_id} を自動的に即時配信しました")
この処理を実行する際は、意図しない配信を防ぐため、アラート通知を組み合わせることを強く推奨します。
3. 配信テンプレート再利用によるEDIT肥大化防止策
毎回新規に配信登録するのではなく、テンプレート的なアプローチで運用することで、EDIT配信の肥大化を防げます。
運用パターン例
class DeliveryManager:
def __init__(self, bearer_token):
self.bearer_token = bearer_token
self.headers = {
"Authorization": f"Bearer {bearer_token}",
"Content-Type": "application/json"
}
def create_and_send_immediately(self, from_email, from_name, subject,
text_part, recipients):
"""
配信を作成して即座に配信開始する
(EDIT状態を最小限に抑える)
"""
# 1. 配信登録開始
begin_response = requests.post(
"https://app.engn.jp/api/v1/deliveries/bulk/begin",
headers=self.headers,
json={
"from": {"email": from_email, "name": from_name},
"subject": subject,
"text_part": text_part
}
)
if begin_response.status_code != 201:
raise Exception(f"配信登録失敗: {begin_response.text}")
delivery_id = begin_response.json()["delivery_id"]
try:
# 2. 配信先アドレスを登録
for recipient in recipients:
requests.post(
f"https://app.engn.jp/api/v1/deliveries/{delivery_id}/emails",
headers=self.headers,
json={"email": recipient["email"],
"insert_code": recipient.get("insert_code", [])}
)
# 3. 即時配信開始
commit_response = requests.patch(
f"https://app.engn.jp/api/v1/deliveries/bulk/commit/{delivery_id}/immediate",
headers=self.headers
)
if commit_response.status_code == 200:
print(f"配信開始: ID={delivery_id}")
return delivery_id
else:
raise Exception(f"配信確定失敗: {commit_response.text}")
except Exception as e:
# エラー時は配信を削除してEDIT状態を解消
requests.delete(
f"https://app.engn.jp/api/v1/deliveries/{delivery_id}",
headers=self.headers
)
raise e
このパターンでは、配信の作成から送信開始までを一連の処理として実行し、途中でエラーが発生した場合は配信を削除することで、EDIT状態の配信が残らないようにしています。
バッチ運用の注意点
自動削除バッチを運用する際の誤操作防止策を紹介します。
1. 削除対象のフィルタリング
# 削除してはいけない配信を除外するフラグ管理
PROTECTED_SUBJECTS = ["重要", "保護", "[DO NOT DELETE]"]
def should_delete(delivery):
"""削除対象かどうか判定"""
subject = delivery.get("subject", "")
# 保護対象の件名パターンにマッチする場合は削除しない
for pattern in PROTECTED_SUBJECTS:
if pattern in subject:
return False
# 作成から7日以上経過している場合のみ削除対象
created_time = datetime.fromisoformat(delivery["created_time"])
if datetime.now(timezone.utc) - created_time < timedelta(days=7):
return False
return True
2. ドライランモードの実装
def cleanup_with_dryrun(bearer_token, dry_run=True):
"""
dry_run=True: 削除対象を表示するのみ(実際には削除しない)
dry_run=False: 実際に削除を実行
"""
deliveries = get_edit_deliveries(bearer_token)
targets = [d for d in deliveries if should_delete(d)]
print(f"削除対象: {len(targets)}件")
for d in targets:
print(f" ID={d['delivery_id']}, 件名={d.get('subject', '(未設定)')}")
if dry_run:
print("[DRY RUN] 実際の削除は行いません")
return
# 確認プロンプト
confirm = input("削除を実行しますか? (yes/no): ")
if confirm.lower() != "yes":
print("キャンセルしました")
return
# 実際の削除処理
for d in targets:
delete_delivery(bearer_token, d["delivery_id"])
3. 実行ログの保存
削除したdelivery_idと削除日時をログファイルやデータベースに記録しておくことで、万が一の際にトラブルシューティングが可能になります。
まとめ
blastengineのEDIT配信30件制限について、要点を整理します。
制限の仕組み
- 配信ステータスがEDITの配信が30件に達すると新規登録不可
- 対処法は「完了(RESERVE状態へ遷移)」または「削除」
予防策
- EDIT配信数を定期監視し、閾値でアラート通知
- 配信登録から完了までを一連の処理として実装
- 古いEDIT配信を自動削除するバッチ処理の導入
適切なAPI利用と自動化により、配信登録上限の問題を未然に防ぎ、安定したメール配信運用を実現できます。