GASでGmailの長文メールを
AIで3行に自動要約する方法

毎日届く長文メールを、GmailApp(GASからGmailを操作する標準機能)とClaude API(Anthropic社の生成AI)を組み合わせ、 要点だけの3行に自動要約してスプレッドシートに記録する方法を、そのまま動くコードで解説します。

|対象: GAS / Gmail / Claude API / 業務自動化

Table of Contents

なぜメールの要約を自動化するのか

結論から言うと、長文メールの「読んで要点をつかむ」作業は、 GAS(Google Apps Script。Googleサービスを操作する無料のプログラム実行環境)とAIで自動化できます。 受信メールをAIに渡し、要点だけの3行に要約してスプレッドシートに並べておけば、 一覧をざっと見るだけで内容を把握できます。

手作業でメールを開いて読む運用と比べ、次のようなメリットがあります。

一覧で把握できる

1通ずつ開かなくても、要約が並んだシートで全体を見渡せる

見落としを減らす

長文に埋もれた重要な依頼や締め切りを要点として拾える

共有しやすい

要約シートをチームで共有すれば、対応状況を全員で追える

検索・集計できる

シート上のデータなので、あとから絞り込みや件数集計ができる

この記事では、Gmailの未読メールを取得し、Anthropic社のClaude APIで3行に要約してシートへ記録する、という一連の流れを実装します。

準備:Gmail連携とAPIキーの保管

必要なのは2つだけです。1つ目はGmailへのアクセス許可。GAS標準のGmailAppを初めて使うと承認画面が出るので、承認すれば連携できます。2つ目はClaude APIのキーです。 このキーは料金が発生する権限そのものなので、コードに直書きしてはいけません。GASの「スクリプトプロパティ」(PropertiesServiceで読み書きする、スクリプト単位の設定保存領域)に入れておき、コードからはキー名で読み出します。

// 一度だけ実行してAPIキーを安全に保存する
function saveApiKey() {
  // 実行後、この関数のキー文字列は削除しておく
  PropertiesService.getScriptProperties()
    .setProperty("ANTHROPIC_API_KEY", "sk-ant-xxxxxxxx");
}

// コードからはキー名で読み出す(直書きしない)
function getApiKey() {
  const key = PropertiesService.getScriptProperties()
    .getProperty("ANTHROPIC_API_KEY");
  if (!key) throw new Error("APIキーが未設定です。saveApiKeyを実行してください。");
  return key;
}

saveApiKeyを一度だけ実行したら、キー文字列はコードから消しておきましょう。以降はどの関数からもgetApiKey()で安全に取り出せます。あわせて、要約を書き込む「メール要約」という名前のシートを作っておきます。

Claude APIで3行要約を作る

まずはテキストを渡すと3行の箇条書きを返す関数を作ります。要約を安定させるコツは、 プロンプト(AIへの指示文)で形式を具体的に指定することです。「3つの箇条書き」「各行40文字以内」「前置きは書かない」と明示し、 さらに返ってきたテキストを改行で分割して先頭3行だけ使う後処理で、行数のぶれを抑えます。

// 渡したテキストを「3行の箇条書き」に要約して返す
function summarize3Lines(text) {
  const url = "https://api.anthropic.com/v1/messages";

  const prompt =
    "次のメール本文を、日本語で3つの箇条書きに要約してください。\n" +
    "・各行は40文字以内で、要点だけを簡潔に。\n" +
    "・記号「・」で始め、3行ちょうどにする。\n" +
    "・前置きや結びの文は書かない。\n\n" +
    "本文:\n" + text;

  const payload = {
    model: "claude-haiku-4-5",
    max_tokens: 300,
    messages: [{ role: "user", content: prompt }]
  };

  const options = {
    method: "post",
    contentType: "application/json",
    headers: {
      "x-api-key": getApiKey(),
      "anthropic-version": "2023-06-01"
    },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true // エラー時も例外にせずレスポンスを受け取る
  };

  const res = UrlFetchApp.fetch(url, options);
  const code = res.getResponseCode();
  if (code !== 200) {
    throw new Error("API エラー (" + code + "): " + res.getContentText());
  }

  const answer = JSON.parse(res.getContentText()).content[0].text.trim();

  // 改行で分割し、空行を除いて先頭3行だけ採用する(行数のぶれ対策)
  const lines = answer.split("\n").map(function (s) {
    return s.trim();
  }).filter(String);
  return lines.slice(0, 3).join("\n");
}

返答はcontent配列の先頭textに入ります。muteHttpExceptions: trueを付けると、エラー時も例外で止まらず自分でステータスコードを確認できます。モデルは軽量なclaude-haiku-4-5から始め、要約品質を上げたいときに高性能なclaude-opus-4-8へ差し替えるだけで切り替えられます。

長文をトークン上限に収める切り詰め

AIには一度に扱える文字数(トークン。AIが文章を区切って数える単位)に上限があります。 長いメールをそのまま送ると上限を超えてエラーになったり、料金が無駄にかさんだりします。 そこで、本文を送る前に先頭で切り詰めておきます。あわせて、返信メールにありがちな 「行頭が>の引用部分」を落とすと、要約の精度も上がります。

// 長文はトークン上限に収まるよう先頭で切り詰める
function trimForApi(text, maxChars) {
  maxChars = maxChars || 4000;
  if (!text) return "";

  // 引用部分(行頭が「>」の返信引用)を除いてノイズを減らす
  const withoutQuote = text.split("\n").filter(function (line) {
    return line.indexOf(">") !== 0;
  }).join("\n");

  if (withoutQuote.length <= maxChars) return withoutQuote;
  return withoutQuote.slice(0, maxChars) + "\n(以下省略)";
}

ここでは先頭4000文字を目安にしています。要約は本文全体の細部までは必要としないため、 先頭の主要部分だけでも要点は十分に拾えます。メールの傾向に合わせてmaxCharsを調整してください。

Gmailから取得して要約・記録する

いよいよ本体です。GmailApp.search()で未読メール(is:unread)を取得し、本文を切り詰めてから要約し、シートに1行ずつ追記します。1回の実行では最大10件に絞り、 実行時間制限に配慮します。

// 未読メールを取得し、要約してシートに記録する
// シート構成: A=処理日時, B=送信者, C=件名, D=3行要約, E=メールID
function summarizeUnreadMails() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("メール要約");

  // すでに処理済みのメールIDを集合として読み込む(二重記録防止)
  const doneIds = readDoneIds(sheet);

  // 未読メールを最大10件だけ取得(実行時間制限への配慮)
  const threads = GmailApp.search("is:unread", 0, 10);

  threads.forEach(function (thread) {
    thread.getMessages().forEach(function (msg) {
      const id = msg.getId();
      if (doneIds[id]) return; // 記録済みはスキップ

      const body = trimForApi(msg.getPlainBody(), 4000);
      if (!body) return;

      const summary = summarize3Lines(body);

      sheet.appendRow([
        new Date(),          // A: 処理日時
        msg.getFrom(),       // B: 送信者
        msg.getSubject(),    // C: 件名
        summary,             // D: 3行要約
        id                   // E: メールID(次回の重複判定に使う)
      ]);

      doneIds[id] = true;
      Utilities.sleep(300); // 連続呼び出しの間隔をあける
    });
  });
}

// E列に記録済みのメールIDを { id: true } の形で返す
function readDoneIds(sheet) {
  const lastRow = sheet.getLastRow();
  const map = {};
  if (lastRow < 2) return map; // ヘッダーのみ

  const ids = sheet.getRange(2, 5, lastRow - 1, 1).getValues(); // E列
  ids.forEach(function (row) {
    if (row[0]) map[row[0]] = true;
  });
  return map;
}

getPlainBody()は、HTMLメールから装飾を除いた本文テキストだけを取り出します。要約にはこの方が向いています。appendRow()でシートの末尾に追記していくので、実行のたびに要約が下へ積み上がっていきます。

同じメールを二重に処理しない仕組み

定期実行するなら、二重記録の防止が欠かせません。上のコードでは、各メールが持つ一意のID(getId()で取得できる文字列)をE列に記録し、次回実行時にreadDoneIds()で読み込んで照合しています。すでに記録済みのIDはスキップするので、同じメールを何度も要約しません。

「未読」を条件にしているため、要約したメールをmarkRead()で既読にしたり、addLabel()で「要約済み」ラベルを付けたりして、検索条件からも外す方法も有効です。IDによる照合とラベル運用を 組み合わせると、より確実に重複を防げます。

トリガーで定期実行を自動化する

最後に、時間主導トリガー(決まった間隔で関数を自動実行するGASの仕組み)を設定すれば、 人が手を動かさなくても要約が回り続けます。15分おきに新着メールをチェックする例です。

// 15分おきに自動要約を回す時間主導トリガーを設定する
function createSummaryTrigger() {
  ScriptApp.newTrigger("summarizeUnreadMails")
    .timeBased()
    .everyMinutes(15)
    .create();
}

なお、1回の実行で扱う件数が多いと、GASの実行時間制限(無料枠で6分)に達することがあります。 上のコードではsearch("is:unread", 0, 10)で1回10件に区切っています。件数が多い場合は、続きを次のトリガーで再開する分割実行にすると安定します。 実装の詳細は関連記事で解説しています。

まとめ

GmailとClaude APIをGASでつなぐと、長文メールの要点把握を自動化できます。ポイントは4つです。 APIキーはスクリプトプロパティで安全に保管し、要約は形式指定+後処理で行数のぶれを抑え、 長文は切り詰めてトークン上限を回避し、メールIDの照合で二重処理を防ぐ——この型を押さえれば、 要約に限らず、優先度の判定・返信の下書き生成といったAI活用にも同じ流れで応用できます。

よくある質問

特別な外部ライブラリは不要です。GAS標準のGmailApp.search()で条件に合うスレッドを取り出し、getMessages()・getPlainBody()で本文を取得できます。初回実行時にGmailへのアクセス許可を求められるので、承認すれば動きます。

AIの出力は自然文なので、指示だけでは行数がぶれることがあります。プロンプトで「必ず3つの箇条書きで、各行は40文字以内」と明示し、返ってきたテキストを改行で分割して先頭3行だけ使う後処理を入れると安定します。本文でこの実装を紹介しています。

多くはトークン上限の超過が原因です。AIは一度に扱える文字数(トークン)に上限があります。本文を先頭数千文字で切り詰めてから送る、または署名や引用部分を削ってから送ると回避できます。本文で切り詰めのコードを紹介しています。

処理済みのメールID(getId()で取得できる一意の文字列)をスプレッドシートに記録し、次回以降はそのIDが記録済みかを照合してスキップします。Gmail側で処理済みラベルを付ける方法も有効です。両方を本文で解説しています。

要約は比較的軽い処理なので、まずはコストを抑えられる軽量モデル claude-haiku-4-5 で品質を確認し、要約の精度をさらに上げたい場合に高性能な claude-opus-4-8 へ切り替えるのがおすすめです。モデルはリクエストのmodelフィールドの文字列を差し替えるだけで変更できます。

引っかかる可能性があります。GASには1回の実行あたり6分(Workspaceは30分)の制限があります。1回で処理する件数を区切り、続きは時間主導トリガーで再開する分割実行にすると安定します。関連記事で分割実行の実装を解説しています。

AI×GASの業務自動化を
相談する。

メール要約のほかにも、問い合わせ分類・優先度判定・返信下書きの自動生成など、 AI APIとGASを組み合わせた自動化をご相談いただけます。既存のGmail・スプレッドシート運用にも組み込めます。

AI×GAS自動化の対応範囲を見る