
大事なメールだけ、Slackに届く。Gmail Push × ルール振り分けの作り方
こんにちは!Accel-Hack (アクセルハック)開発チームです。
社内AIアシスタント「Airi」の開発プロセスをお届けする開発記ブログ。
第21回目の今回は、Google 連携の第二弾――メール連携(gmail機能)をお届けします。
前回の Vol.20 のカレンダーは、「こちらから尋ねる」機能でした。
今回はその逆、「向こうから飛んでくる」情報を扱います。
採用応募や重要な取引先からのメールを、メールボックスを常に見張ることなく、必要なものだけ Slack の担当チャンネルへ自動で届ける。
その仕組みを支えるのが、Gmail の Push 通知(Webhook) です。
1. メールは「見張る」より「届かせる」
大事なメールを見逃さない、と聞いてまず思いつくのは「定期的にメールボックスを確認する」方式でしょう。
しかしこれは、無駄な確認が多いうえ、確認の間隔だけ通知が遅れます。
そこで Airi が採ったのは、Gmail の Push 通知です。
新しいメールが届いた「その瞬間」に、Gmail のほうから「新着があったよ」と Airi に知らせてくれる。
Airi は普段じっと待っていて、通知が来たときだけ動けばいい。
ポーリング(見張り)から Push(受け身)へ。
この切り替えが、速さと効率の両方を手に入れる鍵でした。
2. Push は「新着があったよ」しか教えてくれない
ただし、この Push 通知には大きな特徴があります。
メールの本文は、一切入っていないのです。
Gmail の Push(裏側では Google Pub/Sub が使われています)で届くのは、たったこれだけ。
type GmailPushData = {
emailAddress: string; // どのアカウントに
historyId: number; // どこまで進んだか、を示す通し番号
};「誰のメールボックスに動きがあったか」と「その履歴番号」だけ。
つまり Push は「何か届いたよ」という呼び鈴にすぎません。
中身を知るには、こちらから取りに行く必要があります。
そして「前回どこまで読んだか」も、自分で覚えておかなければなりません。
3. historyId で“差分だけ”を取る
そこで活躍するのが、Vol.7 の Cloudflare KV です。
Airi は、アカウントごとに「前回どこまで処理したか」を示す historyId を KV に保存しておきます。
Push が来たら、KV の古い historyId と、今回届いた新しい historyId を比べます。
const oldHistoryId = await getGmailHistoryId(data.emailAddress);
if (!oldHistoryId) {
// 初回は「今ここから見張ります」と印をつけるだけ(過去メールは処理しない)
await setGmailHistoryId(data.emailAddress, newHistoryId);
return;
}
// 前回からの差分(新しく追加されたメール)だけを取りに行く
const history = await fetchHistory(data.emailAddress, oldHistoryId);
for (const item of history.messagesAdded) {
const message = await fetchMessage(data.emailAddress, item.message.id);
await processGmailMessage(data.emailAddress, message);
}
await setGmailHistoryId(data.emailAddress, newHistoryId); // 印を進めるポイントは2つ。
まず初回は印をつけるだけで、過去のメールを一気に処理しません(連携した瞬間に大量通知が飛ぶ事故を防ぎます)。
そして毎回、前回からの差分だけを取りに行くので、同じメールを二度処理しません。
なお、監視対象(watch リスト)に無いアドレスの通知は、そもそも無視します。
4. ルールで振り分ける
新着メールを取得できたら、最後は振り分けです。
すべてのメールを Slack に流しては、ただのノイズになってしまいます。
Airi は、メールの from(差出人)や subject(件名)を、あらかじめ決めたルールと照らし合わせます。
for (const rule of gmailConfig) {
if (matchConditions(emailAddress, from, subject, rule.conditions)) {
await logics[rule.logic](message);
return; // 最初に一致したルールだけを実行する
}
}ルールと、そのときの通知先・処理内容は、すべて設定(gmailConfig)にまとまっています。
この流れと、ルールのイメージを図にすると次のとおりです。

「最初に一致したルールだけを実行して終わり」という割り切りも効いています。
条件の順序が優先順位になるので、挙動が読みやすい。
新しい振り分けを足したくなっても、設定にルールを1つ書き加えるだけ。
コード本体に手を入れる必要はありません。
5. おわりに
今回は、Gmail 連携を題材に、「見張る」から「届かせる」への発想転換と、それを支える実装をお届けしました。
Push で呼び鈴を受け、historyId で差分だけを取り、ルールで必要なメールだけを振り分ける。
本文の来ない通知、履歴の自前管理といった Gmail ならではのクセはありますが、一つずつ丁寧に捌けば、重要な連絡を見逃さない静かな番人ができあがります。
さて、ここまで Google との連携を見てきました。
次回は開発者にとって身近なもう一つの外部サービス、GitHub です。
「Vol.22: Slackの“あなた”とGitHubの“あなた”をつなぐ。GitHub OAuth連携で作る紐付け基盤」 として、GitHub App を使った OAuth 認証と、Slack ユーザーと GitHub アカウントを紐付ける基盤づくりをお届けします。
お楽しみに!
この記事は以下の体制で作成されました。
ドラフト作成・執筆: Airi (社内AIアシスタント)
アイデア出し・レビュー: CTO
デザイン: 事務スタッフ
Accel-Hackでは、テクノロジーを駆使して世の中の課題を解決していく仲間を募集しています。
私たちの取り組みに少しでも興味を持っていただけたら、ぜひ採用ページや会社サイトも覗いてみてくださいね。