Hexabaseとblastengineでメールマガジンを送信する（メールログを反映する）

Hexabaseはエンタープライズ企業向けのBaaS（Backend as a Service）を提供しています。認証やデータストア（データベース）、ファイルストレージ、FaaS（Function as a Service）といった機能があります。

前回はそんなHexabaseとblastengineを使って、メールマガジンを作成しました。今回は送信ログを使って、配信エラー情報を更新する処理を実装します。

## コード

コードは [blastengineMania/hexabase-mailmagazine](https://github.com/blastengineMania/hexabase-mailmagazine) にアップしてあります。実装時の参考にしてください。

## アーキテクチャ

今回のアーキテクチャは以下のようになります。Hexabaseのデータストアに送信するメールのテンプレート（件名や本文など）、メールアドレスの2つのテーブルを用意します。

メールアドレスのテーブルにあるデータを使って、メールマガジンを送信します。

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/46730b99-7202-a1fa-9108-05f2dd69f947.png)


今回はこの配信結果をblastengineから取得し、その結果をHexabaseのメールアドレステーブルに反映します。

## 実装について

### プロジェクトのフォルダ作成とNode.jsプロジェクトの初期化

今回は `hexabase-mail` とします。以下はこのフォルダの中で処理します。

```
mkdir hexabase-mail
cd hexabase-mail
npm init -y
```

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

必要なライブラリをインストールします。

- @hexabase/hexabase-js
- blastengine
- dotenv
- ts-node
- typescript

```
npm i @hexabase/hexabase-js
npm i blastengine
npm i dotenv
npm i ts-node
npm i typescript
```

TypeScriptプロジェクトとして初期化します。

```
npx tsc --init
```

以下は log.ts での実装内容です。

### 環境変数の用意

`.env` を作成して、環境変数を用意します。

```bash
BLASTENGINE_USER_ID=blastengineのユーザーID
BLASTENGINE_API_KEY=blastengineのAPIキー
HEXABASE_PUBLIC_TOKEN=Hexabaseのパブリックトークン
HEXABASE_WORKSPACE_ID=Hexabaseの対象ワークスペースID
HEXABASE_PROJECT_ID=Hexabaseの対象プロジェクトID
HEXABASE_DATASTORE_MAIL_ID=Hexabaseのデータストア（メールテンプレート）のID（Mailなど）
HEXABASE_DATASTORE_EMAIL_ID=Hexabaseのデータストア（メールアドレス）のID（Emailなど）
```

### ライブラリのインポート

必要なライブラリ（blastengine、HexabaseのSDK）、dotenvを読み込みます。

```tsx
import { BlastEngine, Log } from 'blastengine';
import { HexabaseClient } from '@hexabase/hexabase-js';
import 'dotenv/config';
```

### blastengine、Hexabase SDKの初期化

blastengine、Hexabase SDKを初期化します。

```tsx
new BlastEngine(process.env.BLASTENGINE_USER_ID!, process.env.BLASTENGINE_API_KEY!);
const client = new HexabaseClient();
```

### メインコード

非同期処理が多いので、処理全体をasync/awaitで処理します。

```tsx
(async () => {
	// 以下はこの中に書きます
})();
```

### Hexabaseの準備

Hexabase SDKの準備をします。

```ts
await client.setToken(process.env.HEXABASE_PUBLIC_TOKEN!);
const mailId = process.argv[2];
if (!mailId) throw new Error('メールIDが指定されていません');
await client.setWorkspace(process.env.HEXABASE_WORKSPACE_ID!);
const query = client.query(process.env.HEXABASE_PROJECT_ID!);
```

### blastengineから送信ログを取得

blastengineのLogクラスを使って、送信エラー（ハードエラー）を取得します。

```ts
const logs = await Log.find({
	status: ['HARDERROR']
});
```

### ログデータからHexabaseのデータベースに反映する

取得したログデータに基づいて、Hexabaseのデータベースを更新します。

```ts
for (const log of logs) {
	const { email } = log;
	// メールアドレスを検索
	const emails = await query
		.from(process.env.HEXABASE_DATASTORE_EMAIL_ID!)
		.where([
			query.condition.equalTo('mailaddress', email), // メールアドレス
			query.condition.equalTo('Status', 'enable'),   // 状態が送信可なもの
		])
		.limit(1)
		.select('mailaddress, sendError');
	// データがなければ（すでに更新済みの場合など）スキップ
	if (emails.length === 0) continue;
	// メールアドレスのデータを更新
	const mail = emails[0];
	await mail
		.set('sendError', log.lastResponseMessage) // エラーメッセージ
		.save();
	// ステータスも更新
	await mail.execute('Error');
}
```

## まとめ

今回はHexabaseと組み合わせて、エラーメールを次回から送信しないようにするコードを紹介しました。Hexabaseのデータストアにメールアドレスを保存しておくことで、メールマガジンの送信が簡単になります。

blastengineはメールマガジンのような一括配信だけでなく、即時配信のような個別配信にも対応しています。ぜひメール配信で役立ててください。

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