概要
既存の「メールアドレス宛にスケジュール配信するメールマガジン機能」に加え、Lineにも同様のスケジュール配信を行う仕組みを実装したいという要望は多いです。
この記事では、以下の要件を満たす手順を紹介します。
- メールマガジン用に保存しているテーブル(例:
MailMagazine
)を使い、Line用の送信スケジュールテーブルを新設する - スケジュールされた時間 (
scheduledAt
) にLineメッセージを送信 - 送信ステータス管理(例:
SCHEDULED
→SENT
など)
前提
- メールアドレス宛にスケジュール配信する機能 がすでに存在する
-
メールマガジンの内容を保存するテーブル (例:
MailMagazine
) がすでに存在する
ここからは、Line向けのスケジュール配信を追加するための流れを説明していきます。
テーブル構成
1. LineMessageSchedule
テーブルの作成
新たに以下のようなテーブルを作成します。
※ 実際のORMやマイグレーションツールなどの記述に合わせて修正してください。
CREATE TABLE LineMessageSchedule (
id INT AUTO_INCREMENT PRIMARY KEY,
mailMagazineId INT NOT NULL, -- メールマガジンテーブルとのリレーション
lineUserId VARCHAR(255) NOT NULL,
message TEXT NOT NULL, -- 送信するメッセージ本文
scheduledAt DATETIME NOT NULL, -- スケジュール時刻
status VARCHAR(50) NOT NULL -- SCHEDULED / SENT など
);
主な項目
- mailMagazineId : どのメールマガジンに紐づいているかを示すID
- lineUserId : 送信先のLineユーザーID
- message : 実際に送信する内容(FlexMessageなど)
- scheduledAt : 送信予定日時
-
status : ステータス (例:
SCHEDULED
= 送信待ち、SENT
= 送信済み など)
実装フロー
1. 配信先ユーザーの取得と振り分け
メールマガジン送信先として登録されているグループ情報(deliveryGroup
)から、Lineユーザーとメールユーザーを振り分けます。
// 配信先グループを取得
const deliveryGroupsWithUser =
await this.deliveryGroupService.findAllForMailMagazine({
deliveryGroupIds:
deliveryGroupIds ||
mailMagazine.deliveryGroups.map(
({ deliveryGroupId }) => deliveryGroupId,
),
});
// 配信先グループ内で LineUser とメール User に分割
const lineUsers = deliveryGroupsWithUser.filter((user) => user.lineUserId);
const emailUsers = deliveryGroupsWithUser.filter((user) => !user.lineUserId);
ここで lineUserId
を持っているかどうかで Lineかメールかを区別しています。
2. Line用メッセージスケジュールの登録
Line向けのスケジュール情報を、先ほど作成した LineMessageSchedule
テーブルに作成します。
(ここでは Prisma の createMany
を利用しています。)
await this.prisma.lineMessageSchedule.createMany({
data: await Promise.all(
lineUsers.map(async (user) => {
return {
mailMagazineId: createdMailMagazine.mailMagazineId,
lineUserId: user.lineUserId,
// 送信内容を作成 (FlexMessageなど)
message: this.lineService.createFlexMessage(
subject,
body,
),
scheduledAt: deliveryAt,
status: 'SCHEDULED',
};
}),
),
});
-
lineUserId
: 配信対象ユーザー(Lineユーザー) -
message
: 送信するLineメッセージ(FlexMessageなどを生成) -
scheduledAt
: ユーザーが指定した配信日時
3. 定期実行 (Cron) での送信処理
スケジュールが登録されたLineメッセージを定期的にチェックし、送信予定時刻になったら実際にLineへpushメッセージを送ります。
以下の例では、Node.js の cron
あるいは NestJS の @Cron
を使用し、毎分実行として設定しています。
@Cron('* * * * *') // 毎分実行
async sendScheduledLineMessages() {
const now = new Date();
// ステータスが SCHEDULED で、scheduledAt <= 現在時刻 のメッセージを取得
const schedules = await this.prisma.lineMessageSchedule.findMany({
where: {
scheduledAt: {
lte: now,
},
status: 'SCHEDULED',
},
include: {
mailMagazine: true, // 必要に応じてメールマガジンの情報も取得
},
});
// 取得したスケジュールを順次送信
for (const schedule of schedules) {
try {
// 送信処理 (Push Message)
await this.lineClient.pushMessage({
to: schedule.lineUserId,
messages: [schedule.message],
});
// ステータスを SENT に更新 (例)
await this.prisma.lineMessageSchedule.update({
where: { id: schedule.id },
data: { status: 'SENT' },
});
} catch (error) {
console.error('Line message send error:', error);
// エラー時のリトライやステータス管理は適宜実装
}
}
}
-
スケジュール一覧取得 :
scheduledAt
が現在時刻以前、かつステータスがSCHEDULED
のレコードを取得 -
実際の送信処理 :
lineClient.pushMessage
などでLineに送信 -
ステータス更新 : 送信成功後
SENT
などに更新し、再度送信されないようにする
まとめ
以上のように、既存のメールマガジンのスケジュール配信機能に加えて、Lineにも同様の仕組みを組み込むことができます。基本的な流れは以下です。
-
Line用のスケジュールテーブル (
LineMessageSchedule
) を新設 - 配信先ユーザー をメール・Lineで振り分ける
- スケジュール情報 を登録し、cronなどで定期的に送信を実行
参考になれば幸いです!質問等あればコメントでお待ちしています。