Gmailを検索するGASで結果を一度に取得して止まる場合は、検索件数を小さく区切ります。GmailApp.search(query, start, max)を使うと、取得を始める位置と、1回に返してほしい件数を指定できます。
ただし、返されるのはメール1通ずつではなくスレッドです。返信を含む1つのまとまりが1件なので、スレッド数をそのままメールの通数にしないようにします。検索中に結果が増減する場合もあるため、小分け取得だけで漏れのない一覧が保証されるわけではありません。
startは開始するスレッドの位置
公式のGmailAppでは、startは開始スレッドの位置、maxは返すスレッドの最大数です。最初は0から始めます。次の位置は取得した件数を足して進めます。
練習では少数のメールへ「練習対象」というラベルを付けた状態を使います。サンプルの検索語はlabel:練習対象です。件名や本文をログへ出さず、スレッドIDの一覧と重複数だけを返します。IDも共有が必要な人だけが見られるログで扱ってください。
ラベルを付け替えながら同じ検索結果を取得すると、位置がずれやすくなります。この例は読み取りだけにし、検索結果を見ながら既読化・移動・ラベル変更を行う処理は加えません。
最大回数を決めた読み取りコード
次の関数は同じIDが再び現れたら重複として数え、結果へ二重に入れません。最大回数へ達した場合は、続きがあるか不明だという印も返します。
function readThreadPages(search, query, pageSize, pageLimit) {
if (!Number.isSafeInteger(pageSize) || pageSize < 1 || pageSize > 100 ||
!Number.isSafeInteger(pageLimit) || pageLimit < 1 || pageLimit > 10) {
throw new Error('1回の件数と回数を確認してください');
}
const seen = new Set();
const threadIds = [];
let start = 0;
let duplicates = 0;
for (let page = 0; page < pageLimit; page++) {
const threads = search(query, start, pageSize);
threads.forEach(function (thread) {
const id = thread.getId();
if (seen.has(id)) duplicates++;
else { seen.add(id); threadIds.push(id); }
});
start += threads.length;
if (threads.length < pageSize) {
return {threadIds: threadIds, duplicates: duplicates, nextStart: start, moreUnknown: false};
}
}
return {threadIds: threadIds, duplicates: duplicates, nextStart: start, moreUnknown: true};
}
function previewGmailPages() {
const result = readThreadPages(
(query, start, max) => GmailApp.search(query, start, max),
'label:練習対象', 2, 3
);
console.log(JSON.stringify(result));
}
1ページ目がT1・T2、2ページ目がT2・T3、3ページ目が空なら、架空の結果はT1・T2・T3の3件、重複数1です。nextStartは取得件数の合計4になります。これは実際のGmailのIDではなく、分岐を確かめる入力例です。
重複がなくても漏れは残り得る
同じ検索語でも、新着メールや削除などで結果の並びや件数が変わると、位置での取得は安定した一覧の写しにはなりません。重複IDを除けたからと、すべての対象を取得できたとは判断しないでください。
対象期間やラベルを事前に決め、検索中の状態変更を減らすと、確認しやすくなります。網羅性が必要なら、対象IDの記録と再照合を別に用意します。moreUnknown:falseも、その時点の取得が指定件数より少なかったという意味で、以後の新着を含めないことを保証する値ではありません。
スレッド内の各メールを使う場合は、GmailThreadのgetMessagesで取り出す段階を分けます。返信まで対象なのか、条件に合うメールだけなのかを改めて決める必要があります。
小分けでも読み過ぎない
ページ数を増やすだけでは、GASの実行時間やGmailの利用制限は解決しません。1回の対象を絞り、次にどこから確認するかを残します。保存した位置は検索結果の変化で意味が変わるため、それだけを再開の根拠にしないようにします。
ローカルでは代用検索で、開始位置、重複、空結果、上限停止、引数不備を確認しました。Gmailへの検索・状態変更・送信は実行していません。Gmail通知の基本と読み取りの機能を分け、失敗は実行履歴とログで確認できる形にします。
