0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

blastengine APIのCC/BCC対応トランザクション配信で業務通知メールを構築する

0
Posted at

はじめに

業務メールでは「顧客にメールを送りつつ、営業担当にもCCで共有したい」「管理者にはBCCで記録を残したい」といった要件がよくあります。

blastengine APIのトランザクション配信はCC/BCCに対応しており、このような同報配信を簡単に実装できます。本記事では、CC/BCCを活用した業務通知メールの実装パターンを解説します。

CC/BCCの仕様

blastengine APIのトランザクション配信におけるCC/BCCの仕様は以下の通りです。

パラメータ 上限 必須
to string 1件 はい
cc Array of strings 10件 いいえ
bcc Array of strings 10件 いいえ

注意点:

  • CC/BCCが使えるのはトランザクション配信のみ(一斉配信では使えません)
  • toは1件のアドレスのみ指定可能
  • CC/BCCはそれぞれ最大10件まで

環境準備

import requests
import json

API_BASE = "https://app.engn.jp/api/v1"
BEARER_TOKEN = "your_bearer_token"

HEADERS = {
    "Authorization": f"Bearer {BEARER_TOKEN}",
    "Content-Type": "application/json",
}

実装1:基本的なCC/BCC付き配信

まずはシンプルなCC/BCC付きトランザクション配信です。

curlでの実行

curl -X POST "https://app.engn.jp/api/v1/deliveries/transaction" \
  -H "Authorization: Bearer ${YOUR_BEARER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "email": "system@example.com",
      "name": "通知システム"
    },
    "to": "customer@example.jp",
    "cc": ["sales@example.com"],
    "bcc": ["admin@example.com"],
    "subject": "ご注文確認のお知らせ",
    "text_part": "ご注文ありがとうございます。ご注文内容をご確認ください。"
  }'

Pythonでの実装

def send_transaction(to, subject, text_part, cc=None, bcc=None, html_part=None):
    """CC/BCC対応トランザクション配信"""
    url = f"{API_BASE}/deliveries/transaction"

    payload = {
        "from": {
            "email": "system@example.com",
            "name": "通知システム",
        },
        "to": to,
        "subject": subject,
        "text_part": text_part,
    }

    if cc:
        payload["cc"] = cc
    if bcc:
        payload["bcc"] = bcc
    if html_part:
        payload["html_part"] = html_part

    response = requests.post(url, headers=HEADERS, data=json.dumps(payload))

    if response.status_code == 201:
        delivery_id = response.json()["delivery_id"]
        print(f"配信成功: delivery_id={delivery_id}")
        return delivery_id
    else:
        print(f"配信失敗: {response.status_code} {response.text}")
        return None


# 実行例
send_transaction(
    to="customer@example.jp",
    subject="ご注文確認のお知らせ",
    text_part="ご注文ありがとうございます。",
    cc=["sales@example.com"],
    bcc=["admin@example.com"],
)

実装2:業務シナリオ別の配信パターン

実際の業務でよく使う3つのパターンを実装します。

パターンA:顧客通知 + 営業CC

顧客にメールを送り、担当営業にCCで共有するパターンです。

def notify_order_confirmation(customer_email, sales_emails, order_info):
    """注文確認通知(顧客→TO、営業→CC)"""
    text = (
        f"{order_info['customer_name']}\n\n"
        f"ご注文ありがとうございます。\n\n"
        f"注文番号: {order_info['order_id']}\n"
        f"商品名: {order_info['product_name']}\n"
        f"金額: ¥{order_info['amount']:,}\n"
        f"お届け予定日: {order_info['delivery_date']}\n\n"
        f"ご不明な点がございましたら、お気軽にお問い合わせください。"
    )

    return send_transaction(
        to=customer_email,
        subject=f"【注文確認】注文番号 {order_info['order_id']}",
        text_part=text,
        cc=sales_emails,
    )


# 実行例
notify_order_confirmation(
    customer_email="customer@example.jp",
    sales_emails=["tanaka@example.com", "suzuki@example.com"],
    order_info={
        "customer_name": "山田太郎",
        "order_id": "ORD-2026-001",
        "product_name": "製品A",
        "amount": 150000,
        "delivery_date": "2026-04-01",
    },
)

パターンB:社内通知 + 管理者BCC

障害やアラートなどの社内通知で、担当チームにTOで送りつつ管理者にBCCで記録を残すパターンです。

def notify_system_alert(team_emails, admin_emails, alert_info):
    """システムアラート通知(チーム→TO、管理者→BCC)"""
    text = (
        f"{alert_info['severity']}】システムアラート\n\n"
        f"発生日時: {alert_info['occurred_at']}\n"
        f"対象: {alert_info['target']}\n"
        f"内容: {alert_info['message']}\n\n"
        f"対応をお願いいたします。"
    )

    # チームの先頭メンバーをTO、残りをCCに
    to = team_emails[0]
    cc = team_emails[1:] if len(team_emails) > 1 else None

    return send_transaction(
        to=to,
        subject=f"{alert_info['severity']}{alert_info['target']} アラート",
        text_part=text,
        cc=cc,
        bcc=admin_emails,
    )


# 実行例
notify_system_alert(
    team_emails=["dev-lead@example.com", "dev1@example.com", "dev2@example.com"],
    admin_emails=["cto@example.com"],
    alert_info={
        "severity": "WARNING",
        "occurred_at": "2026-03-21 14:30:00",
        "target": "APIサーバー",
        "message": "レスポンスタイム閾値超過(p99 > 3s)",
    },
)

パターンC:取引先通知 + 社内関係者CC + 監査BCC

取引先への通知に社内関係者をCC、監査部門をBCCに入れるパターンです。

def notify_invoice(partner_email, internal_cc, audit_bcc, invoice_info):
    """請求書送付通知(取引先→TO、社内→CC、監査→BCC)"""
    text = (
        f"{invoice_info['company_name']} 御中\n\n"
        f"請求書を送付いたします。\n\n"
        f"請求書番号: {invoice_info['invoice_id']}\n"
        f"請求金額: ¥{invoice_info['amount']:,}\n"
        f"お支払期限: {invoice_info['due_date']}\n\n"
        f"ご確認のほど、よろしくお願いいたします。"
    )

    return send_transaction(
        to=partner_email,
        subject=f"【請求書】{invoice_info['invoice_id']}",
        text_part=text,
        cc=internal_cc,
        bcc=audit_bcc,
    )


# 実行例
notify_invoice(
    partner_email="accounts@partner.co.jp",
    internal_cc=["sales@example.com", "accounting@example.com"],
    audit_bcc=["audit@example.com"],
    invoice_info={
        "company_name": "株式会社パートナー",
        "invoice_id": "INV-2026-0321",
        "amount": 500000,
        "due_date": "2026-04-30",
    },
)

実装3:差し込みコードとの組み合わせ

トランザクション配信では差し込みコード(insert_code)も併用できます。CC/BCCと組み合わせて、宛先ごとにパーソナライズしたメールを同報配信できます。

def send_with_insert_code(to, cc, subject, text_part, insert_codes):
    """差し込みコード + CC付きトランザクション配信"""
    url = f"{API_BASE}/deliveries/transaction"

    payload = {
        "from": {
            "email": "system@example.com",
            "name": "通知システム",
        },
        "to": to,
        "cc": cc,
        "subject": subject,
        "text_part": text_part,
        "insert_code": [
            {"key": f"__{k}__", "value": v} for k, v in insert_codes.items()
        ],
    }

    response = requests.post(url, headers=HEADERS, data=json.dumps(payload))

    if response.status_code == 201:
        return response.json()["delivery_id"]
    else:
        print(f"配信失敗: {response.status_code} {response.text}")
        return None


# 実行例:差し込みコードで宛名をパーソナライズ
send_with_insert_code(
    to="customer@example.jp",
    cc=["sales@example.com"],
    subject="__prop1__様 サービス更新のお知らせ",
    text_part=(
        "__prop1__ 様\n\n"
        "ご利用中の __prop2__ プランの更新日が近づいております。\n"
        "更新日: __prop3__\n"
    ),
    insert_codes={
        "prop1": "山田太郎",
        "prop2": "スタンダード",
        "prop3": "2026-04-01",
    },
)

実装4:配信結果の確認

CC/BCC付きで送信した場合、配信ログではTO/CC/BCCそれぞれに対して配信ログIDが発行されます。配信ログAPIで各宛先の到達状況を確認できます。

def check_delivery_logs(delivery_id):
    """配信IDに紐づく配信ログを確認"""
    url = f"{API_BASE}/logs/mails/results"
    params = {
        "delivery_id": delivery_id,
        "count": 100,
    }
    response = requests.get(url, headers=HEADERS, params=params)

    if response.status_code != 200:
        print(f"取得失敗: {response.status_code}")
        return None

    logs = response.json()["data"]
    print(f"配信ID {delivery_id} の配信ログ({len(logs)}件):")
    print(f"{'メールアドレス':<30} | {'ステータス':<12} | {'コード'}")
    print("-" * 65)
    for log in logs:
        print(
            f"{log['email']:<30} | {log['status']:<12} | "
            f"{log.get('last_response_code', '-')}"
        )

    return logs


# 配信IDを指定してログを確認
check_delivery_logs(delivery_id=12345)

出力例:

配信ID 12345 の配信ログ(3件):
メールアドレス                   | ステータス       | コード
-----------------------------------------------------------------
customer@example.jp            | SENT         | 250
sales@example.com              | SENT         | 250
admin@example.com              | SENT         | 250

CC/BCC活用時の設計ポイント

観点 推奨
TO/CC/BCCの使い分け TO=主たる宛先、CC=情報共有、BCC=記録・監査
CCの上限 10件まで。超える場合はメーリングリスト等を検討
BCCの活用 監査証跡や管理者通知に。受信者からは見えない
エラーハンドリング TO/CC/BCCの一部が失敗しても他は配信される。ログで個別に確認
差し込みコード TO宛のメール本文に適用される。CC/BCC受信者も同じ本文を受け取る

おわりに

blastengine APIのCC/BCC対応を活用すれば、「顧客通知 + 社内共有」を1回のAPI呼び出しで実現できます。TOとCCを別々に送る必要がないため、実装もシンプルになり、送信タイミングのズレも起きません。

注文確認、請求書送付、アラート通知など、業務メールの多くはCC/BCCが絡むケースです。ぜひ活用してみてください。

0
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?