見出し画像

【組織のAI活用#229】Gmailのメール内容をGASでスプレッドシートへ自動転記することで、元データとしてAI活用しやすくなる。

こんにちは!寺田です。

現在は、デジタル関連会社のAI推進者などのAI活用者のコミュニティである「AI Digital Community (ADC)」の代表理事や、顧客事業の「×AI化」をサポートするFURIKAKE Partners(株)と組織のAI活用を支援するプロダクトを提供するAI Portalize(株)の代表取締役を務めており、様々な側面から組織のAI活用をサポートしています!

以前の記事で、スプレッドシートをデータベースにしていくといろいろなことがやりやすくなる、というお話をさせていただいたかと思います。

そのデータベース化にあたっては、各所からデータを自動で引っ張ってきて構造を作っていくと非常に便利です。今回はその中でも、メールの内容をスプシにまとめていく方法について、ソースコードもそのまま記載しながら、手順ややり方をお伝えさせていただきます。

本記事では、転記する項目の選び方、対象メールのフィルター設計、そして実装手順の3段構成で解説します。

※過去のGAS関係記事はこちら



ステップ1:どの項目を転記するかを決める

最初にやるべきはコードを書くことではなく、「シートに何の列を作るか」を決めることです。選定の考え方は「シートで何をしたいか」から逆算します。

  • 対応管理がしたい場合:受信日時・差出人・件名があれば成立します。これに手動で記入する「対応状況」「担当者」列を足すのが定番です。

  • 内容の分析・集計がしたい場合:本文の情報が必要になります。ただし本文の全文転記はおすすめしません。シートが重くなるうえ、機密情報を必要以上に複製することになるためです。「本文は先頭200文字だけ+原本メールへのリンク」という形にすると、一覧性と安全性を両立できます。

  • 添付ファイルの有無を知りたい場合:ファイルそのものではなく「添付ファイル数」を数値で記録すれば十分なことがほとんどです。

本記事のコードでは、この考え方に基づいて次の6項目を転記します:受信日時/差出人/件名/本文(先頭200文字)/添付ファイル数/メールへのリンク。

ステップ2:取得するメールにフィルターをかける

全メールを転記すると量が膨大になり、すぐ破綻します。対象を絞る方法は2つあり、併用が王道です。

1つ目は、Gmailの検索演算子です。GASのメール検索は、Gmailの検索窓とまったく同じ書き方で条件指定できます。よく使うものを挙げます。

  • from:sender@example.com (差出人で絞る)

  • to:support@example.com (宛先で絞る。問い合わせ用アドレスの抽出に)

  • subject:【問い合わせ】 (件名の キーワードで絞る)

  • label:転記対象 (特定ラベルが付いたメールだけに絞る)

  • has:attachment (添付ファイル付きのみ)

  • newer_than:2d (直近2日以内。定期実行の取得範囲を絞るのに必須)

  • -subject:広告 (先頭にマイナスを付けると除外条件)

これらは半角スペースで並べるとAND条件になります。
例:「to:support@example.com newer_than:2d -subject:自動返信」。

2つ目は、Gmail側のフィルタ機能との合わせ技です。
Gmailの設定でフィルタを作り「条件に合うメールに自動でラベルを付ける」ようにしておき、GAS側は「label:○○」で取得する方法です。条件の管理がGmailの画面上で見える形になるため、後から条件を変えたいときにコードを触らずに済みます。

【ポイント】
コードに書く前に、まずGmailの検索窓に同じクエリを打ち込んで、意図したメールだけがヒットするかを確認してください。ここで検証しておけば、実装後の「取れない・取れすぎる」トラブルの大半を防げます。

ステップ3:実装する

シートの準備

転記先のスプレッドシートを新規作成し、シート名を「メールログ」にして、1行目にヘッダーを入力します。

  • A列: 受信日時/B列: 差出人/C列: 件名/D列: 本文(先頭)/E列: 添付数/F列: メールリンク

コード全文

スプレッドシートの「拡張機能」→「Apps Script」を開き、以下を貼り付けて、冒頭の設定を書き換えてください。


// ======== 設定(自分の環境に合わせて書き換える) ========
const SEARCH_QUERY = 'to:support@example.com newer_than:2d'; // 取得条件(Gmail検索演算子)
const SHEET_NAME = 'メールログ';  // 書き込み先シート名
const BODY_LENGTH = 200;          // 本文を先頭何文字まで転記するか(0なら本文列は空にする)

// メイン関数:条件に合う新着メールをシートへ転記(1時間おきトリガーで実行)
function syncMailToSheet() {
  const props = PropertiesService.getScriptProperties();
  const processed = JSON.parse(props.getProperty('processedIds') || '{}');

  const threads = GmailApp.search(SEARCH_QUERY, 0, 100);
  const rows = [];

  threads.forEach(function(thread) {
    thread.getMessages().forEach(function(msg) {
      const id = msg.getId();
      if (processed[id]) return; // 転記済みのメールはスキップ
      rows.push(buildRow_(msg));
      processed[id] = Utilities.formatDate(msg.getDate(), 'Asia/Tokyo', 'yyyy/MM/dd');
    });
  });

  if (rows.length === 0) {
    console.log('新着メールはありません');
    return;
  }

  // 受信日時の昇順に並べ替えて追記
  rows.sort(function(a, b) { return a[0] - b[0]; });
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
  sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, rows[0].length).setValues(rows);

  // 転記済みID一覧を整理して保存
  cleanupProcessed_(processed);
  props.setProperty('processedIds', JSON.stringify(processed));
  console.log(rows.length + ' 件を転記しました');
}

// メール1件を行データに変換
function buildRow_(msg) {
  const body = BODY_LENGTH > 0
    ? msg.getPlainBody().replace(/\r?\n+/g, ' ').substring(0, BODY_LENGTH)
    : '';
  return [
    msg.getDate(),                      // A: 受信日時
    msg.getFrom(),                      // B: 差出人
    msg.getSubject() || '(件名なし)',   // C: 件名
    body,                               // D: 本文(先頭のみ)
    msg.getAttachments().length,        // E: 添付ファイル数
    'https://mail.google.com/mail/u/0/#all/' + msg.getId() // F: メールへのリンク
  ];
}

// 転記済みIDのうち7日以上前のものを削除して、記録の肥大化を防ぐ
function cleanupProcessed_(processed) {
  const limit = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
  Object.keys(processed).forEach(function(id) {
    if (new Date(processed[id]) < limit) delete processed[id];
  });
}

// 初回に一度だけ手動実行:1時間おきのトリガーを登録
function setupTrigger() {
  ScriptApp.getProjectTriggers().forEach(function(t) {
    if (t.getHandlerFunction() === 'syncMailToSheet') ScriptApp.deleteTrigger(t);
  });
  ScriptApp.newTrigger('syncMailToSheet').timeBased().everyHours(1).create();
}

コードのポイント

  • 重複防止の仕組み:転記したメールのIDを記録しておき、次回以降はスキップします。検索条件の「newer_than:2d」(直近2日)と、ID記録の保持期間(7日)を組み合わせることで、漏れも重複もない状態を軽い処理で維持します。

  • スレッドへの返信も拾える:Gmailはメールをスレッド単位で扱いますが、このコードはスレッド内の1通1通をIDで管理するため、転記後に同じスレッドへ届いた返信も次回実行時にきちんと転記されます。

  • 本文の扱い:BODY_LENGTHで転記する文字数を調整できます。本文が不要な管理用途なら0にしてください。

初回実行とトリガー設定

1. コードを保存し、関数選択で「syncMailToSheet」を選んで実行します。初回はGmailとスプレッドシートへのアクセス承認画面が出るので許可します(「確認されていません」警告は「詳細」→「移動」で進めます)。



2. シートに意図したメールが転記されていることを確認します。取れすぎ・取れなさすぎの場合は、SEARCH_QUERYをGmailの検索窓で再検証してください。

3. 問題なければ、関数選択で「setupTrigger」を実行し、1時間おきの自動実行を設定します。左メニューの時計アイコンで登録を確認できます。


動作確認チェックリスト

  • 条件に合うメールを受信→次の実行後にシートへ追記されるか

  • 同じメールが重複して転記されていないか

  • 条件に合わないメール(除外対象)が転記されていないか

  • 「実行数」画面にエラーが出ていないか

社内で導入する際のセキュリティ注意点

メールは機密情報の塊です。今回の仕組みは特に慎重に扱ってください。

  • 導入前に社内の承認を得る:メールの内容を別の場所(スプレッドシート)へ複製する行為は、情報管理規程の対象になり得ます。特に顧客とのやり取りを含むメールボックスを対象にする場合は、情報システム部門や上長へ確認してから進めましょう。

  • 転記先の共有範囲は最小限に:メールボックスは本人しか見られませんが、スプレッドシートは共有設定次第で誰でも見られます。「そのメールを読む権限がある人」だけに共有を絞るのが原則です。

  • 転記する情報も最小限に:本文の全文転記や添付ファイルの複製は避け、目的に必要な項目だけを転記してください。本記事のコードが「本文は先頭のみ+リンク」なのはこのためです。

危険な設定例も挙げておきます。

  • 個人の受信トレイ全体を条件なしで転記対象にする

  • 顧客の個人情報を含むメールログを「リンクを知っている全員」共有のシートに蓄積する

  • 退職・異動後もスクリプトが動き続け、誰も管理していない転記シートが残る(作成者と管理者を明記しておく)

応用

  • 対応管理への発展:シートに「対応状況」列を足し、前回紹介した「スプレッドシート→Slack通知」のGASと組み合わせれば、「メール受信→シート転記→Slackに新着通知→対応状況を記入」という一連の仕組みが完成します。

  • AIとの連携:蓄積した問い合わせログは、FAQの元データやNotebookLMのソースとして活用できます。

  • 定型メールの項目抽出:申請メールなど形式が決まったメールなら、本文から正規表現で「申請者」「金額」などを取り出して列に分ける発展も可能です。

メールの情報を、スプレッドシートで活かす

メール転記のGASは、「①項目を目的から逆算して選ぶ → ②Gmail検索演算子で対象を絞る(まず検索窓で検証)→ ③コードを貼って重複防止付きで自動化」の3ステップです。

スプシに情報をまとめておくことで、それをソースとしてボットを作成したり、ドキュメントを作成したり、何かのトリガーにしてアクションをしたりなど、いろんなことをしやすくなります。

ぜひ、まずは手動での1回実行から、試してみていただければなと思います!

ちなみに、以前お伝えしたGoogle Workspace Studioでもこれは実現できますので、やりやすい方から試してみてください。



読んでいただきありがとうございました!
過去のAI関連記事はこちらです!

ちなみに、組織におけるAIの推進についてまとめた本も出版させていただいております。もしよければご覧ください。


<自己紹介>
直近までは、電通グループに属する約1400人・20社以上の事業会社群で構成されるCARTA HOLDINGSにて、全社横断のAI推進室で組織全体のAI活用推進を担いつつ、法人向けの「生成AI&デジマ人材」研修サービスであるD-Marketing Academyの代表取締役も兼務し、大手企業からスタートアップまで、数百社にわたるAI人材育成を支援してきました。

現在は、デジタル関連会社のAI推進や担当コミュニティである「AI Digital Community (ADC)」の代表理事や、顧客事業の「×AI化」をサポートするFURIKAKE Partners(株)と組織のAI活用を支援するプロダクトを提供するAI Portalize(株)の代表取締役を務めており、様々な側面から組織のAI活用をサポートしています!

<略歴>
2005年 5月 大学在学時にEC事業を開始
2007年 5月 (株)サイバーエージェントに入社し新規事業の立ち上げに携わる
2011年 10月 (株)VOYAGE GROUPにてKDDIとの協業事業を行う(株)Flesselを設立し代表取締役に就任
2015年 11月 ECコンサルティング事業を行う(株)JSコンサルティングの代表取締役へ就任
2018年 4月 東証一部プライム企業Hamee(株)にJSコンサルティングをM&Aし、代表取締役を継続
2019年 5月 Hamee(株)の執行役員に就任し、Hameeグループの新規事業領域を管轄
2021年 2月 D2C支援を行うTHE CHOSEN ONE(株)の顧問に就任
2021年 3月 アパレルD2C事業を行う(株)NAAFYの取締役に就任
2021年 4月 D-Marketing Academy(株)を設立し代表取締役に就任
2023年 1月 (株)CARTA HOLDINGSにD-Marketing AcademyをM&Aし、代表取締役を継続
2025年 3月 CARTA HOLDINGSグループ全体のAI活用促進を行うAI推進室を兼務開始
2026年 1月 生成AIに関しての顧問を行うFURIKAKE Partners(株)を設立し、代表取締役に就任
2026年 1月 組織の生成AIプラットフォームサービスAI Portalize(株)を設立し、代表取締役に就任
2026年 1月 デジタル関連のAI活用企業コミュニティ「AI Digital Community(ADC)」を設立し代表理事に就任

いいなと思ったら応援しよう!