SMTP・API連携で高速メール配信するならブラストエンジン

Notionからblastengine経由で送信したメールのエラーステータスを更新する

更新日: Notion

Notionは最近注目度の高い情報共有サービスです。Wikiのように自由テキストを保存したり、データベースのように構造化されたデータを保存もできます。

今回はそんなNotion内にあるメールアドレスを使って、blastengineと組み合わせてみました。前回はNotionデータベース上のメールアドレスを使ってメール送信を行いましたので、今回はエラーステータスをデータベースに反映します。

機能について

  • データベースにある顧客リストのメールアドレス宛にメールを一括送信
  • エラーリストを使って次回以降送信しないようにNotionのデータを更新

後半となるこの記事ではblastengineから取得できるエラーリストを使って、データベースにある顧客リストのメールアドレスのステータスを更新します。

ベースとなるアプリやライブラリは前回のものを使います。

ファイルの作成

今回は update.ts というファイルを作成します。

ライブラリ読み込み

update.ts への記述です。まず最初に必要なライブラリを読み込みます。

// dotenvを読み込み、環境変数を設定する
require('dotenv').config();

// Notionのクライアントを読み込む
import { Client } from '@notionhq/client';

// Notionから返されるページオブジェクトの型を読み込む
import { PageObjectResponse } from '@notionhq/client/build/src/api-endpoints';

// blastEngineとErrorReportを読み込む
import { BlastEngine, ErrorReport } from 'blastengine'

Notionクライアントの初期化への接続情報を作成する

.env ファイルに定義したシークレットを使って、Notionクライアントを作成します。

// Notion APIの認証を設定
const notion = new Client({ auth: process.env.NOTION_SECRET });

blastengineの初期化

blastengine SDKを初期化します。こちらも .env ファイルの内容を使います。

// blastEngineを初期化する
new BlastEngine(process.env.BLASTENGINE_USERID, process.env.BLASTENGINE_APIKEY);

無名関数の定義

ここからはネットワーク処理があるので、非同期処理用にasync/awaitを定義します。

// メイン処理をasync関数で囲む
(async () => {
  // ここからはこの中に書いていきます
})();

blastengineのエラーレポートをダウンロード

blastengineのエラーレポートをダウンロードします。これは、2回以上配信エラーがあったメールアドレスが記録されています。

// blastEngineのエラーレポートを管理するオブジェクトを作成する
const report = new ErrorReport;
// ダウンロードができるようになるまで待つ
while (await report.finished() === false) {
	// 1秒待つ
	await new Promise(res => setTimeout(res, 1000));
}
// エラーレポートをダウンロードする
const results = await report.download();

エラーレポートは管理画面でも確認できます。

Untitled.png

Notionからレコードを取得

エラーレポートに含まれているメールアドレスを使って、Notionのデータベースを検索します。

// ダウンロードしたエラーレポートからメールアドレスを取り出し、
// それらのメールが含まれるページのIDを取得する
const ary = await fetchAll(
	process.env.DB_ID!,
	results.map((r: any) => r.email)
);

fetchAll関数は以下のようになります。関数は (async () => { 外で問題ありません。

// Notionデータベースから未送信の情報を取得する関数
const fetchAll = async (databaseId: string, emails: string[]): Promise<string[]> => {
	// データベースをクエリして、結果を取得する
	const res = await notion.databases.query({
    database_id: databaseId,
		filter: {
			// フィルタ条件は指定されたメールアドレスが含まれているエントリ
			or: emails.map(email => ({
				property: process.env.EMAIL_PROPERTY!,
				rich_text: {
					contains: email,
				}
			}))
		}
	});
	// 返された結果からIDのみを取り出す
	return (res.results as PageObjectResponse[]).map(row => row.id);
};

Notionデータベースのプロパティを更新する

取得できたページIDを使って、Notionデータベースを更新します。

// 取得したページのIDに対してプロパティを更新する
await updateAll(ary);

updateAll 関数は以下のようになります。これも (async () => { 外で問題ありません。

// 全ての指定されたページのプロパティを更新する関数
const updateAll = async (ary: string[]): Promise<boolean> => {
	// 指定されたページIDすべてを非同期で更新する
	const res = await Promise.all(ary.map(id => {
		return notion.pages.update({
			page_id: id,
			properties: {
				// 更新するプロパティはCHECKBOX_IDの値
				[process.env.CHECKBOX_ID!]: {
					checkbox: true,
				}
			}
		});
	}));
	return true;
};

スクリプトの全体像

update.ts の内容は以下の通りです。

// dotenvを読み込み、環境変数を設定する
require('dotenv').config();

// Notionのクライアントを読み込む
import { Client } from '@notionhq/client';

// Notionから返されるページオブジェクトの型を読み込む
import { PageObjectResponse } from '@notionhq/client/build/src/api-endpoints';

// Notion APIの認証を設定する
const notion = new Client({ auth: process.env.NOTION_SECRET });

// blastEngineとErrorReportを読み込む
import { BlastEngine, ErrorReport } from 'blastengine';

// BlastEngineのユーザIDとAPIキーを使ってblastEngineを初期化する
new BlastEngine(process.env.BLASTENGINE_USERID, process.env.BLASTENGINE_APIKEY);

// Notionデータベースから未送信の情報を取得する関数
const fetchAll = async (databaseId: string, emails: string[]): Promise<string[]> => {
	// データベースをクエリして、結果を取得する
	const res = await notion.databases.query({
    database_id: databaseId,
		filter: {
			// フィルタ条件は指定されたメールアドレスが含まれているエントリ
			or: emails.map(email => ({
				property: process.env.EMAIL_PROPERTY!,
				rich_text: {
					contains: email,
				}
			}))
		}
	});
	// 返された結果からIDのみを取り出す
	return (res.results as PageObjectResponse[]).map(row => row.id);
};

// 全ての指定されたページのプロパティを更新する関数
const updateAll = async (ary: string[]): Promise<boolean> => {
	// 指定されたページIDすべてを非同期で更新する
	const res = await Promise.all(ary.map(id => {
		return notion.pages.update({
			page_id: id,
			properties: {
				// 更新するプロパティはCHECKBOX_IDの値
				[process.env.CHECKBOX_ID!]: {
					checkbox: true,
				}
			}
		});
	}));
	return true;
};

// メイン処理をasync関数で囲む
(async () => {
	// blastEngineのエラーレポートを管理するオブジェクトを作成する
	const report = new ErrorReport;
	// ダウンロードができるようになるまで待つ
	while (await report.finished() === false) {
		// 1秒待つ
		await new Promise(res => setTimeout(res, 1000));
	}
	// エラーレポートをダウンロードする
	const results = await report.download();
  // ダウンロードしたエラーレポートからメールアドレスを取り出し、
  // それらのメールが含まれるページのIDを取得する
  const ary = await fetchAll(
  	process.env.DB_ID!,
  	results.map((r: any) => r.email)
  );
	// 取得したページのIDに対してプロパティを更新する
	await updateAll(ary);
	// 完了メッセージをログに表示する
	console.log('更新完了しました');
})();

実行する

以下のようにしてコマンドプロンプトやターミナルで実行します。

npx ts-node update.ts

以下のようなメッセージが出れば更新されているはずです。

更新完了しました

Notionデータベースも更新されているはずです。

Untitled 1.png

まとめ

今回はblastengineの配信エラーレポートをダウンロードして、Notionのデータベースへ反映するまでの流れを紹介しました。

Notionデータベースはメールの配信ログやメールアドレスを蓄積しておくのにぴったりです。ぜひblastengineと組み合わせてください。

エンジニア向けメール配信システム「ブラストエンジン(blastengine)」

blastengine(プラストエンジン)ロゴ

エンジニアを面倒なメールに関するトラブルから解放するために作られたブラストエンジン
まずは無料トライアルで、その使いやすさを実感してみませんか?

\メールアドレス入力のみ/

無料トライアル