GmailとGeminiで受信トレイを自動整理するシステムをつくった話
- ⏱ 約8分で読めます - 👁 … views知り合いの社長さんから相談がきた。「自分が外出してる間、営業と事務のスタッフがメール対応に追われてて大変そうなんだよね。なんかできない?」
受信トレイを開く、読む、優先度を判断する、誰に回すか決める。1件1件は大した作業じゃないけど、10〜20件積み重なると午前中がつぶれる。社長がいないときに限って問い合わせが立て込んだりもする。
自分も富士通にいた頃、朝の1時間はメール処理で終わってた。まあそのうち10分くらいはWindowsが起動するのを待ってたりしてたけど。あの時間、今思うとなんだったんだろう。
それを解消するために、Gmail × Gemini API × Google Apps Script(GAS)の組み合わせでメール自動分析システムを作った。Google Workspaceを使っている会社なら、新しいインフラなしで同じ仕組みが作れる。
どんなシステムか
Gmailの未処理メールをAIが自動で読んで、スプレッドシートに記録する。記録する内容はこんな感じ:
- 3行以内の要約
- タグ分類(受注・見積もり・クレーム・請求など12カテゴリ)
- 担当部署の判定(営業部・技術部・製造部・経理部・総務部)
- 必要なアクション
- 優先度(高・中・低。当日対応が必要なものは「高」)
- 広告・一斉配信かどうかの判定(返信不要メールを自動識別)
分析結果はWebアプリのダッシュボードに表示される。カードを開くとAIが返信ドラフトを生成してくれるので、それを確認・編集してそのまま送信できる。転送用の添え書き自動生成、ステータス管理(未処理/指示済み/完了)、過去ログの検索もある。
このシステムは会社の代表メールアドレスに複数のスタッフがアクセスする構成になっている。営業・事務が同じ受信トレイを共有しながら、それぞれの担当範囲で対応する、という使い方だ。メールという業務の入口を複数人で共有するのは、運用上の効率は上がる一方、誰がいつ何をしたか追えなくなるリスクがある。そのためダッシュボードにはユーザー管理の仕組みを組み込んだ。ログイン・操作ログ・ステータス変更は担当者ごとに記録される。「あの対応、誰がやった?」が後から確認できる状態にしておくことは、チームで使うシステムの最低条件だと思っている。
技術スタックについて
GASは自分も今回が初めてだった。でも社長さんの「自分でもいじれるようになると楽しそう」という一言もあって、Googleファミリーで統一する方針に。新しいインフラは立てず、既に使っているGoogleのエコシステムだけで完結させた。
| 役割 | 採用技術 |
|---|---|
| バックエンド処理 | Google Apps Script(GAS) |
| フロントエンド | HTML/CSS/JS(GAS HtmlService) |
| AI分析 | Gemini API(gemini-3.5-flash) |
| データ保存 | Google スプレッドシート |
| メール操作 | Gmail API(GmailApp) |
| デプロイ | clasp(CLIツール) |
GASはGmail・Drive・スプレッドシートを追加認証なしで扱える。サーバー維持コストはゼロ。APIトークン代だけでシステムが動く。月に届くメール件数にもよるが、今回の規模では月数百円程度。中小企業相手の受託開発では選択肢としてかなり上位に来る。
設計でハマったところ
GASに実行時間制限があった
これは知らなかった。GASのスクリプト実行には1回あたり6分の制限がある。Webアプリのボタン操作から呼び出した処理も例外じゃない。
通常運用では問題ない。Gemini APIが1件3〜5秒として、20件処理しても2分もかからない。ただメールを何十件も溜めてから一気に分析しようとするとそこそこ食う。念のためレート制限対策の500msインターバルと3回自動リトライを入れておいた。
サーバーレスで気軽に使えるイメージだったので、こういう制約があるとは思ってなかった。GASを本格的に使うなら最初に把握しておくべき仕様だと思う。
Date型がnullになるバグ
GASのgetValues()は日時セルをDate型で返す。でもgoogle.script.runでブラウザに返す際、Date型はシリアライズに失敗してnullになる。「日付だけ消える」という症状で、原因がわかるまで少し時間がかかった。フロントエンドに返す前に文字列変換する、というルールをコードに落とし込んで解決した。
プロンプトの調整
Geminiへのプロンプトは何度も調整した。難しかったのは「広告メールの判定」と「優先度の判定基準の言語化」。最終的に判定基準を具体的な例示付きで書いて、JSONのスキーマを厳密に指定したらパースエラーの頻度がぐっと下がった。
セキュリティ
公式の受付アドレスへのフルアクセスができるシステムなので、ここは妥協しなかった。IPAの「中小企業の情報セキュリティ対策ガイドライン」を参照しつつ、Claude Codeのアセッサーエージェントでもチェックをかけた。
- SHA-256ハッシュ + スクリプトプロパティによるID/パスワード認証
- ログイン3回失敗で5分間アカウントロック
- 管理者専用操作はGASサーバー側でGoogle Sessionを使って再検証
- APIキーはすべてスクリプトプロパティに分離
作ってみてわかったこと
GASのコスパは思ってたより高かった。インフラゼロで、Google Workspaceとの連携がそのまま使えて、費用はほぼAPIトークン代のみ。ただ、テストの自動化は難しい。GASはローカル実行できないので、ユニットテストでロジックを網羅するのはコスト的に合わない。代わりに、副作用の少ないロジック(プロンプト組み立て、日付変換、JSONパースなど)を関数として独立させて、変更時の影響範囲を絞る設計にした。
プロンプトはコードと同じくバージョン管理が必要だ、というのも改めて実感した。少し変えるだけで分析結果の傾向がガラッと変わる。変更履歴とCHANGELOGを連動させるルールを最初に決めておいてよかったと思ってる。
バイブコーディングとは違う話
「AIに全部書かせました」というスタイルをバイブコーディングと呼ぶ。雰囲気でプロンプトを投げて、動いたらOK。それはそれで使い道はあるけど、受託開発でそれをやると後が怖い。
今回気をつけたのは3点。
プロンプトをコードと同じく管理する。 Geminiへの指示は何度も改版した。変更のたびにバージョン番号を振り、分析結果の傾向がどう変わったかをCHANGELOGに残す。「昨日まで動いていたのに今日は違う」を防ぐための最低限の仕組みだ。
テストしやすい設計にする。 GASはローカル実行できないのでユニットテストは難しい。だから副作用のないロジック(プロンプト組み立て・日付変換・JSONパース)を独立した関数として切り出した。変更時の影響範囲を絞る設計は、AIが書いたコードでも人間が書いたコードでも同じく必要になる。
セキュリティとエラーリカバリを手厚く定義する。 「動けばいいや」で作ると、ここが真っ先に抜ける。このシステムは会社の代表メールアドレスへのフルアクセスを持ち、複数のスタッフが使う。認証が甘ければ誰でもログインできるし、エラーで処理が止まったまま誰も気づかないという事態も起きる。そうなると「AIが整理してくれている」どころか「メール対応が止まっている」になる。
だからこそ、セキュリティとエラーリカバリは最初から設計に組み込んだ。
- SHA-256ハッシュ + スクリプトプロパティによるID/パスワード認証
- ログイン3回失敗で5分間アカウントロック
- 管理者専用操作はGASサーバー側でGoogle Sessionを使って再検証
- APIキーはすべてスクリプトプロパティに分離
- Gemini APIの失敗には500msインターバル・3回自動リトライ
- IPAの「中小企業の情報セキュリティ対策ガイドライン」を参照し、Claude Codeのアセッサーエージェントでもチェック
バイブコーダーとの違いはここだと思っている。AIを使って速く作れることは前提として、セキュリティとエラーリカバリをどれだけ手厚く定義して、システムが止まらないようにするか。「動く」ではなく「止まらない」を目標にすると、設計の優先順位が変わる。
できあがったもの
ダッシュボードは優先度ごとにカード形式で整理されていて、高優先度には赤いバッジが付く。朝イチで何から手をつけるか、開いた瞬間にわかる。カードを開くと要約・タグ・担当部署・アクション・本文が表示されて、その場でAIに返信ドラフトを生成させて送信まで完結する。
現在テスト運用中。うまく使ってもらえるといいなと思ってる。
おわりに
このシステムの開発は Claude Code を全面的に使いながら進めた。設計レビュー、コードレビュー、リファクタリング、ドキュメント整備まで、エージェントを並列で動かしながら一人で受託開発するスタイルは、正直もう手放せない。
既存のGoogleツールとAIをつなぐだけで業務が変わる、という体験は、大きな基幹システム刷新が難しい会社にとってのリアルな選択肢だと感じている。同じような悩みがあればぜひ相談してほしい。
本システムはGoogle Apps Script / Gemini API を利用しています。実行環境の仕様変更により動作が変わる場合があります。