blastengine Google Apps Script SDKを使って購読停止（List-Unsubscribe）ヘッダを付けたメールを送信する

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

今回は今開発中のGoogle Apps Script用SDK（以下GAS SDK）を使って、List-Unsubscribeヘッダーを付けたメールを送信する方法を解説します。

## コードについて

GAS SDKはMIT Licenseのオープンソース・ソフトウェアです。リポジトリは以下にあります。

[blastengineMania/blastengine-gas: Google Apps Script向けのblastengine SDKです](https://github.com/blastengineMania/blastengine-gas)

## ユーザ登録する

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

![getting-started-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/5c6c8cb0-9ad1-0a6d-88fe-e24bc3ee7b17.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/78a4eeb3-4649-149f-8246-44f83d03a0cf.jpeg)

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

![getting-started-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/d21fc4e3-36f0-6f5c-23e3-8c675e16f538.png)

## ライブラリIDについて

GASのライブラリIDは `1GvJKygDvrhoq9w1FIRepBo1kAB3yo1LucHtL6CIM-KqmaFaxLUbyBdim` になります。こちらをGoogle Apps Scriptのエディタにて、ライブラリとして登録してください。

```
1GvJKygDvrhoq9w1FIRepBo1kAB3yo1LucHtL6CIM-KqmaFaxLUbyBdim
```

![blastengine-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/e7bd1386-9893-0d80-226c-d130eb912a1b.jpeg)

今回はIDを `Blastengine` として解説します。変更している場合はそれぞれ読み替えてください。

## 初回実行時の注意

初回実行時には外部URL（blastengineのAPI）にアクセスを許可するダイアログが出ます。なお、この時に以下のような怖いダイアログが出ます。

![blastengine-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/a57beb3b-5ab8-1ca1-a612-97124ce248fb.jpeg)

ｚこれはインストール数が増えると消えるらしいのですが、まだ作成したばかりのため表示されてしまうようです。左下にある詳細というリンクから許諾を続行できます。

## 初期化

先ほど取得したユーザー名とAPIキーを使って初期化します。

```js
Blastengine.init('YOUR_USER_NAME', 'YOUR_API_KEY');
```

## メールの送信

### メール送信時のクラス

blastengine GAS SDKでメール送信を行う際には、3つのクラスが利用できます。

- **Transaction:**  
都度配信用クラス
- **Bulk:**  
一括配信用クラス
- **Mail:**  
Transaction/Bulk双方を必要に応じて使い分けるクラス

基本的にはMailクラスを利用していれば問題ありません。以下のメソッド名は共通です。

## List-Unsubscribe用の情報設定

List-Unsubscribeヘッダーを使う際には、 `setUnsubscribe` メソッドを使います。

```jsx
const mail = new Mail;
mail
	.setFrom(config.from.email, config.from.name)
	.setText('本文 __name1__')
	.setFrom('info@blastengine.jp')
	.addAttachment(Utilities.newBlob('Hire me!', 'text/plain', 'resume.txt'))
	.setUnsubscribe({
		url: 'https://example.com/unsubscribe/__code__',
		email: 'unsubscribed+__code__@example.com?subject=unsubscribe'
	})
	.addTo('atsushi@example.com', {name1: 'Atsushi', code: '123456'});
```

`setUnsubscribe` は `url` と `email` をオプションに取ります。どちらもオプションです。`__code__` は置換文字列になります。 `addTo` の第2引数に指定したキーで置換されます（実際には `__キー__` と置換されます）。今回の例であれば、URLは `https://example.com/unsubscribe/123456` 、メールアドレスは `unsubscribed+123456@example.com?subject=unsubscribe` になります。

## メールの送信

メールの送信は `send` メソッドを使います。

```jsx
mail.send();
```

## ログの取得

メールの送信ログを取得するには、 `Mail` クラスを使います。 `list_unsubscribe_mailto` や `list_unsubscribe_url` を検索条件に指定する場合は、  `Mail.find` メソッドを使います。 `list_unsubscribe_mailto` と `list_unsubscribe_url` はそれぞれ `setUnsubscribe` メソッドで指定した値になります。また、部分一致で検索できます。

```jsx
const mails = await Mail.fnd({
	size: 100,
	delivery_type: ['BULK'],
	list_unsubscribe_mailto: 'example'
}) as Bulk[];
```

なお、 `Mail.find` はAPIで送信されたメールのみを対象とします。SMTPで送信されたメールを含める際には、 `Mail.all` メソッドを使います。

```jsx
const mails = await Mail.all({
	size: 100,
	delivery_type: ['BULK'],
	status: ['EDIT']
}) as Bulk[];
```

## まとめ

List-Unsubscribeヘッダーは、Gmailのガイドライン変更に伴って、対応が必須になっている機能になります。blastengineの場合は、APIとSMTP両方でList-Unsubscribeヘッダーに対応しています。

現在はGmailのみですが、他のメールプロバイダーについても対応が進んでいくことでしょう。blastengineを使って、配信したメールを確実に受信者に届けるためにも、List-Unsubscribeヘッダーの対応を行ってください。

[blastengine API](https://blastengine.jp/documents/)




## メールオブジェクトの用意

blastengineでは即時配信されるトランザクションメールと、一括配信のバルクメールがあります。執筆時点（2022年4月現在）では、SDKはトランザクションメールのみ対応してます。

```js
const transaction = Blastengine.transaction();
```

## 配信元、配信先を設定

件名や宛先などをセットします。

```js
transaction.fromEmail = 'info@example.com';
transaction.setTo('user@example.jp');
transaction.subject = 'Test subject';
transaction.setText('Test body');
```

## 添付ファイルを追加する

添付ファイルは `addAttachment` メソッドを使います。Blobをセットすれば良いので、リソースはリモートやGoogle Driveどちらでも使えます。

```js
// Google Drive
const file = DriveApp.getFileById('DRIVE_FILE_ID');
transaction.addAttachment(file.getBlob());
// リモート
const response = UrlFetchApp.fetch('https://example.com/logo.jpg');
transaction.addAttachment(response.getBlob());
```

## 送信する

送信を実行します。GASなのでネットワーク処理は同期になります。

```js
const res = transaction.send();
```

結果の `res` には、デリバリーIDが入ってきます。このIDを使って配信状況を確認できます。

```js
console.log(res);
// { delivery_id: 188 }
```

## Tips

blastengineのAPIでは、fileパラメータに複数ファイルを添付してAPI呼び出しを行います。GASのUrlFetchAppはパラメータをJSONオブジェクトで渡すので、1つのキーに対して複数パラメータを設定できません。配列は使えませんでした。

そこで[Google Apps Scriptを使ってmultipart/form-dataタイプでHTTPリクエストする - Qiita](https://qiita.com/tanaike/items/02feac3ab75e9c79594d)で作成されているFetchAppを試したのですが、こちらも複数指定はできませんでした。そのためFetchAppを参考にして、独自でboundaryを生成しています。

[この辺りのコード](https://github.com/blastengineMania/blastengine-gas/blob/main/src/libs/delivery/transaction/base.ts#L75)なのですが、コツはpayloadに適用するバイト文字列は1次元の配列になっている必要があります。バイト文字列の生成は `Utilities.newBlob` で任意の文字列からBlobを生成して、 getBytes メソッドで取得するのが一番手軽です。

テキストファイルであればバイト文字列化は不要ですが、画像などのバイナリファイルを multipart/form-data で送信する際には必須になります。あまりないとは思いますが、GASでmultipart/form-data送信を自作する場合には参考にしてください。

## まとめ

GAS SDKを使えばスプレッドシートからメールを一括配信したり、Googleフォームから個人ではないFromを使って返信できます。Gmailでは1日の配信件数に限界がありますが、blastengineを使えばそういった心配は無用です。

ぜひblastengineをお試しください！

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