0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GAS】Gmail自動取得で「特定のメールが拾えない」原因はスレッド機能【備忘録】

Posted at

ChatGPT Image 2025年11月28日 20_49_01.png

はじめに

Google Apps Script (GAS) を使って、特定の件名のメールをスプレッドシートに自動転記するスクリプトを作成していた際のこと。「返信 (Re:)」や「転送 (Fwd:)」は除外したいけれど、肝心の 「元の依頼メール」まで拾えていないという現象に遭遇しました。

原因はGmail特有の 「スレッド機能」 と、GASでの取得ロジックの組み合わせにありました。同じミスを防ぐために、事象と解決策をまとめておきます。


1. 起きていた問題

「見積もり依頼」というキーワードを含むメールを抽出したい。ただし、「Re:」や「Fwd:」がついている返信・転送メールはノイズになるので除外したい。

期待する動作

  • 【対象】【社内】見積もり依頼(A社) → 取得したい
  • 【除外】Re: 【社内】見積もり依頼(A社) → 除外したい

実際の動作

  • 【除外】Re: 【社内】見積もり依頼(A社) → OK(除外された)
  • 【不明】【社内】見積もり依頼(A社)なぜか一緒に除外されてしまう!

2. 原因:スレッドの「最新の1通」しか見ていなかった

Gmailの仕様として、件名が同じやり取りは1つの「スレッド」にまとめられます。

当初のコードでは、以下のように記述していました。

// 【NGコード】スレッドごとのループ
for (const thread of threads) {
  // スレッド内の「最新の1通」だけを取得
  const message = thread.getMessages().pop();
  
  // そのメッセージが「Re:」ならスキップ
  if (message.getSubject().match(/^Re:/)) {
    continue; // ← ここでスレッドごと処理終了してしまう!
  }
  
  // 書き込み処理...
}

何が起きていたか?

  1. あるスレッドに「元の依頼メール」と、それに対する「返信メール (Re:)」が含まれている。
  2. GASの検索(GmailApp.search)はスレッド単位でヒットする。
  3. コードは thread.getMessages().pop() で、一番最後のメール(つまりRe:がついたメール)だけを取り出す。
  4. 「あ、これはRe:がついているから除外対象だ」と判断し、continue する。
  5. 結果、そのスレッドに含まれていた「Re:がついていない元のメール」を見る前に、次のスレッドへ行ってしまう!

3. 解決策:スレッド内の全メッセージをループする

スレッドを取得した後、その中のメッセージを1つずつ回して判定する必要がありました。

// 【OKコード】スレッド → メッセージ の2重ループ
for (const thread of threads) {
  const messages = thread.getMessages(); // スレッド内の全メールを取得
  
  // メッセージを1つずつチェック
  for (const message of messages) {
    const subject = message.getSubject();
    
    // 「このメッセージ」がRe:ならスキップ(スレッド全体はスキップしない)
    if (REPLY_FORWARD_REGEX.test(subject)) {
      continue;
    }
    
    // 書き込み処理...
  }
}

これで、「Re:メール」は除外しつつ、同じスレッド内にある「元メール」は正しく拾えるようになりました。


4. 今後のためのチェックリスト(教訓)

Gmail関連のGASを書く際は、以下の点に注意が必要です。

✅ GmailApp.search は「スレッド」を返す

  • 検索条件にヒットしたメールが1通でもあれば、スレッドごと取得されます。

✅ 除外判定は「メッセージ単位」で行う

  • スレッド単位で continue すると、巻き添えで必要なメールも捨ててしまうリスクがあります。

✅ getMessages() は配列を返す

  • pop()(最新) や [0](最古) だけで処理を済ませようとせず、必要に応じて for ループで全件チェックしましょう。

まとめ

「最新の状態だけ知りたい」なら pop() で良いですが、「ログとして過去のやり取りも抽出したい」 場合は、必ずメッセージ単位でのループ処理が必要です。

Gmailのスレッド機能は便利ですが、GASで扱う際には「スレッド ≠ メール」という点を意識しないと、思わぬ落とし穴にはまります。

同じような問題で悩んでいる方の参考になれば幸いです!


タグ: #GAS #GoogleAppsScript #Gmail #スプレッドシート #自動化 #備忘録

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?