blastengine APIを使ってPythonで添付ファイル付きメールを送信する

[blastengine](https://blastengine.jp/)はシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先に届くようになります。

今回はblastengineのAPIを使ってPythonで添付ファイル付きのメール送信を行うまでの流れを解説します。

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。

![getting-started-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/515541ad-b74e-e1e2-ac34-46d181ee2924.jpeg)


## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## APIキーを取得する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/47b2b2ac-2e41-77fe-d84f-0ae0b7541f36.jpeg)


そして設定の中で、APIキーを取得します。

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2b5ca124-3020-1d39-84e4-911cd4db27e2.png)

## ライブラリのインストール

今回利用するライブラリは下記のrequestsです。

[requests · PyPI](https://pypi.org/project/requests/)

HTTPアクセスできるライブラリがあれば良いので、好きなものを利用してください。Pythonプロジェクトの作成と、ライブラリのインストール用コマンドを実行します。

```
$ mkdir blastengine-test
$ cd blastengine-test
$ echo "requests" >> requirements.txt
$ pip install -r requirements.txt
```

### ライブラリを読み込む

まず必要なライブラリを読み込みます。上記の `requests` に加えて、JSONを扱う `json` 、ハッシュを作成する `hashlib` なども読み込みます。

```py
import os
import sys
import requests
import json
import hashlib
import base64
```

### 必要な変数を取得

今回はターミナル（コマンドプロンプト）から実行します。その際にユーザIDとAPIキーを渡す仕組みにしますので、スクリプト側で入力値を受け取ります。また、両方とも必須なので、入力がなかったらエラーとします。

```py
user_id = os.environ['BE_USERID']
api_key = os.environ['BE_APIKEY']
```

### トークンを生成する

APIリクエストするためのトークンを生成します。手順としては次のとおりです。

1. ユーザIDとAPIキーを連結する
2. SHA256のハッシュを生成する
3. ハッシュを全て小文字にする
4. 3の文字列をBASE64エンコードする

実際のコードで言うと、次のようになります。 `token` がトークンです。

```py
digest = hashlib.sha256(f'{user_id}{api_key}'.encode()).hexdigest()
token = base64.b64encode(digest.encode()).decode('utf-8')
```

### メール内容を準備する

メールの内容はdictで作成します。

```py
entity = {
	'from': {
		'email': 'no-reply@example.jp',
		'name': '送信者サンプル'
	},
	'to': 'test@example.com',
	'subject': 'テスト件名',
	'encode': 'ISO-2022-JP',
	'text_part': 'テスト配信',
	'html_part': '<!DOCTYPE html><html><header></header><body>sample html</body></html>'
}
```

### 添付ファイルを準備する

先ほど用意したentityはdataという名前で利用し、他に添付ファイルをfileパラメータに適用します。

```py
# 添付ファイルの設定
files = [
	# fileは添付ファイル
	('file', ('README.md', open('./README.md', 'rb'), 'text/markdown')),
	('file', ('requirements.txt', open('./requirements.txt', 'rb'), 'text/plain')),
	# dataはメール内容（data.jsonはダミーのファイル名です）
	('data', ('data.json', json.dumps(entity), 'application/json'))
]
```

### メールを送信する

では実際にメールを送信します。APIのエンドポイントは `https://app.engn.jp/api/v1/deliveries/transaction` になります。生成したトークンは `Authorization` ヘッダーに適用します。

```py
url = 'https://app.engn.jp/api/v1/deliveries/transaction'
headers = {
	'Authorization': f'Bearer {token}'
}
# 送信時にはfilesパラメータに適用してください
response = requests.post(url, files=files, headers=headers)
```

### 結果

レスポンスを出力します。配信ID（delivery_id）は照会、変更および削除操作に必要です。

```py
if response.status_code > 300:
	print('Error')
res = json.loads(response.content)
print(res['delivery_id'])
# 9
```

### 全体のコード

今回のサンプルコードは次のようになります。実装時の参考にしてください。

```py
import os
import sys
import requests
import json
import hashlib
import base64

user_id = os.environ['BE_USERID']
api_key = os.environ['BE_APIKEY']

digest = hashlib.sha256(f'{user_id}{api_key}'.encode()).hexdigest()
token = base64.b64encode(digest.encode()).decode('utf-8')

url = 'https://app.engn.jp/api/v1/deliveries/transaction'
entity = {
	'from': {
		'email': 'no-reply@example.jp',
		'name': '送信者サンプル'
	},
	'to': 'test@example.com',
	'subject': 'テスト件名',
	'encode': 'ISO-2022-JP',
	'text_part': 'テスト配信',
	'html_part': '<!DOCTYPE html><html><header></header><body>sample html</body></html>'
}
headers = {
	'Authorization': f'Bearer {token}'
}
# 添付ファイルの設定
files = [
	# fileは添付ファイル
	('file', ('README.md', open('./README.md', 'rb'), 'text/markdown')),
	('file', ('requirements.txt', open('./requirements.txt', 'rb'), 'text/plain')),
	# dataはメール内容（data.jsonはダミーのファイル名です）
	('data', ('data.json', json.dumps(entity), 'application/json'))
]
# 送信時にはfilesパラメータに適用してください
response = requests.post(url, files=files, headers=headers)
if response.status_code > 300:
	print('Error')
res = json.loads(response.content)
print(res['delivery_id'])
```

## まとめ

クラウドサービスではSMTPポートが塞がれている場合があるので、そうした時にはAPI経由を利用してください。SMTPリレーを使えば、より信頼性高く、安定した配信が実現できるでしょう。

APIとSMTPリレー、それぞれの要件に合わせて最適な方を選択してください。

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)