はじめに
メール配信APIを使っていると、PDFの請求書や画像ファイルを添付して送りたい場面が出てきます。blastengine APIでは、トランザクション配信で添付ファイル付きメールを送信できます。
本記事では、blastengine APIを使った添付ファイル付きメール配信の実装方法を解説します。サイズ制限や添付不可拡張子など、実装時にハマりやすいポイントも押さえていきます。
添付ファイルの制約
実装に入る前に、blastengine APIの添付ファイルに関する制約を整理しておきます。
サイズ制限
| 項目 | 制限 |
|---|---|
| 1配信あたりの合計サイズ | デフォルト1MB(契約により異なる) |
| 添付ファイル数の上限 | 100件 |
制限内であれば複数ファイルを添付可能です。
添付不可の拡張子
セキュリティ上の理由から、以下の拡張子は添付できません。
.ade, .adp, .apk, .appx, .appxbundle, .bat, .bz2, .cab, .chm, .cmd,
.com, .cpl, .dll, .dmg, .ex, .ex_, .exe, .gz, .hta, .ins, .isp, .iso,
.jar, .js, .jse, .lib, .lnk, .mde, .msc, .msi, .msix, .msixbundle,
.msp, .mst, .nsh, .pif, .ps1, .scr, .sct, .shb, .sys, .tgz, .vb,
.vbe, .vbs, .vxd, .wsc, .wsf, .wsh, .zip
実行可能ファイルや圧縮ファイルが中心です。PDF・画像・Excelなどの一般的なビジネスファイルは問題なく添付できます。
環境準備
BearerTokenの生成
blastengine APIの認証にはBearerTokenが必要です。ログインIDとAPIキーから生成します。
YOUR_LOGIN_ID="your_login_id"
YOUR_API_KEY="your_api_key"
YOUR_BEARER_TOKEN=$(echo -n "${YOUR_LOGIN_ID}${YOUR_API_KEY}" \
| shasum -a 256 | awk '{print $1}')
YOUR_BEARER_TOKEN=$(echo -n "${YOUR_BEARER_TOKEN}" | tr A-Z a-z)
YOUR_BEARER_TOKEN=$(echo -n "${YOUR_BEARER_TOKEN}" | base64 | tr -d "\n")
echo "${YOUR_BEARER_TOKEN}"
共通設定(Python)
本記事ではPythonで実装します。requestsライブラリを使用します。
pip install requests
import requests
import os
API_BASE = "https://app.engn.jp/api/v1"
BEARER_TOKEN = "your_bearer_token"
HEADERS_JSON = {
"Authorization": f"Bearer {BEARER_TOKEN}",
"Content-Type": "application/json",
}
HEADERS_MULTIPART = {
"Authorization": f"Bearer {BEARER_TOKEN}",
# Content-Typeはrequestsが自動設定するため指定しない
}
実装1:添付ファイル付きトランザクション配信(curl)
まずはcurlで基本的な動作を確認します。添付ファイル付きの場合、multipart/form-data形式でリクエストします。
curl -X POST "https://app.engn.jp/api/v1/deliveries/transaction" \
-H "Authorization: Bearer ${YOUR_BEARER_TOKEN}" \
-F 'data={"from":{"email":"sender@example.com","name":"送信者名"},"to":"recipient@example.jp","subject":"請求書送付のご案内","text_part":"請求書を添付いたします。ご確認ください。"};type=application/json' \
-F "file=@/path/to/invoice.pdf"
ポイントは、JSONパラメータをdataパートにまとめ、添付ファイルをfileパートで送ることです。通常のJSON送信とは異なり、multipart/form-dataとして送信します。
実装2:Pythonで添付ファイル付き配信
単一ファイル添付
import json
def send_with_attachment(to_email, subject, body, file_path):
"""添付ファイル付きトランザクション配信"""
url = f"{API_BASE}/deliveries/transaction"
payload = {
"from": {"email": "sender@example.com", "name": "送信者名"},
"to": to_email,
"subject": subject,
"text_part": body,
}
file_name = os.path.basename(file_path)
with open(file_path, "rb") as f:
files = {
"data": (None, json.dumps(payload), "application/json"),
"file": (file_name, f, "application/octet-stream"),
}
response = requests.post(
url, headers=HEADERS_MULTIPART, files=files
)
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_with_attachment(
to_email="recipient@example.jp",
subject="請求書送付のご案内",
body="請求書を添付いたします。ご確認ください。",
file_path="/path/to/invoice.pdf",
)
filesパラメータにdataとfileを渡すのがポイントです。dataパートにはJSONペイロードをapplication/jsonとして格納し、fileパートに添付ファイルを入れます。
複数ファイル添付
複数ファイルを添付する場合、filesパラメータにタプルのリストを渡します。
def send_with_multiple_attachments(to_email, subject, body, file_paths):
"""複数添付ファイル付きトランザクション配信"""
url = f"{API_BASE}/deliveries/transaction"
payload = {
"from": {"email": "sender@example.com", "name": "送信者名"},
"to": to_email,
"subject": subject,
"text_part": body,
}
# dataパートにJSON、fileパートに複数ファイルを送信
opened_files = []
file_tuples = [("data", (None, json.dumps(payload), "application/json"))]
try:
for file_path in file_paths:
f = open(file_path, "rb")
opened_files.append(f)
file_name = os.path.basename(file_path)
file_tuples.append(("file", (file_name, f, "application/octet-stream")))
response = requests.post(
url, headers=HEADERS_MULTIPART, files=file_tuples
)
finally:
for f in opened_files:
f.close()
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_with_multiple_attachments(
to_email="recipient@example.jp",
subject="月次レポート送付",
body="レポートと集計データを添付いたします。",
file_paths=[
"/path/to/report.pdf",
"/path/to/data.xlsx",
],
)
実装3:添付前のバリデーション
配信エラーを未然に防ぐため、送信前にバリデーションを入れておくと安心です。
BLOCKED_EXTENSIONS = {
".ade", ".adp", ".apk", ".appx", ".appxbundle", ".bat", ".bz2",
".cab", ".chm", ".cmd", ".com", ".cpl", ".dll", ".dmg", ".ex",
".ex_", ".exe", ".gz", ".hta", ".ins", ".isp", ".iso", ".jar",
".js", ".jse", ".lib", ".lnk", ".mde", ".msc", ".msi", ".msix",
".msixbundle", ".msp", ".mst", ".nsh", ".pif", ".ps1", ".scr",
".sct", ".shb", ".sys", ".tgz", ".vb", ".vbe", ".vbs", ".vxd",
".wsc", ".wsf", ".wsh", ".zip",
}
MAX_TOTAL_SIZE = 1 * 1024 * 1024 # 1MB(デフォルト)
MAX_FILE_COUNT = 100
def validate_attachments(file_paths, max_size=MAX_TOTAL_SIZE):
"""添付ファイルのバリデーション"""
errors = []
if len(file_paths) > MAX_FILE_COUNT:
errors.append(f"添付ファイル数が上限({MAX_FILE_COUNT}件)を超えています")
total_size = 0
for file_path in file_paths:
# 拡張子チェック
_, ext = os.path.splitext(file_path)
if ext.lower() in BLOCKED_EXTENSIONS:
errors.append(f"添付不可の拡張子です: {file_path}")
# ファイル存在チェック
if not os.path.exists(file_path):
errors.append(f"ファイルが存在しません: {file_path}")
continue
total_size += os.path.getsize(file_path)
# 合計サイズチェック
if total_size > max_size:
size_mb = total_size / (1024 * 1024)
limit_mb = max_size / (1024 * 1024)
errors.append(
f"合計サイズ({size_mb:.2f}MB)が上限({limit_mb:.2f}MB)を超えています"
)
return errors
# バリデーション付き送信
def send_with_validation(to_email, subject, body, file_paths):
"""バリデーション付き添付ファイル配信"""
errors = validate_attachments(file_paths)
if errors:
for e in errors:
print(f"エラー: {e}")
return None
return send_with_multiple_attachments(to_email, subject, body, file_paths)
実装4:配信結果の確認
送信後、配信が正常に完了したかを配信詳細APIで確認します。
def get_delivery_detail(delivery_id):
"""配信詳細を取得"""
url = f"{API_BASE}/deliveries/{delivery_id}"
response = requests.get(url, headers=HEADERS_JSON)
if response.status_code == 200:
data = response.json()
print(f"配信ID: {data['delivery_id']}")
print(f"ステータス: {data['status']}")
print(f"配信種別: {data['delivery_type']}")
print(f"件名: {data['subject']}")
if "attaches" in data:
print(f"添付ファイル数: {len(data['attaches'])}")
for attach in data["attaches"]:
print(f" - {attach}")
return data
else:
print(f"取得失敗: {response.status_code}")
return None
実装時の注意点まとめ
| ポイント | 詳細 |
|---|---|
| Content-Type | 添付ありはmultipart/form-data、なしはapplication/json
|
| サイズ上限 | デフォルト1MB(契約で変更可能) |
| ファイル数上限 | 100件/配信 |
| 拡張子制限 | 実行可能ファイル・圧縮ファイルは不可 |
| 送信前バリデーション | API呼び出し前にローカルでチェックするとエラーを減らせる |
おわりに
blastengine APIの添付ファイル付き配信は、multipart/form-data形式でリクエストする点がJSON送信との違いです。サイズ制限と拡張子制限を事前にバリデーションしておけば、実運用でもスムーズに使えます。
請求書や帳票の自動送信など、業務自動化の一部としてぜひ活用してみてください。