Google Apps ScriptにおけるGmailの読み取り件数の制限とその対処法


limit

photo credit: Seattle Department of Transportation Speed Trailer via photopin (license)

みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。

Google Apps Scriptの用途としてGmailの特定のメールを取得するというのはけっこう多いですよね。

  • スプレッドシートに書き出したり
  • チャットに転送したり

などなど、けっこう便利ですし。

しかし、GASでメールを取得する際に気を付けなければいけない点があります。

それは、Gmailの読み取りについての1日20000件の壁です。

これをオーバーしてGmailから読み取ろうとすると、ひたすらエラーを吐き出して動作しないという切ない状況が起きてしまうんですね。

ということで、今回はこの件について注意しなきゃね、という内容です。

Google Apps ScriptにおけるGmailの読み取り件数の制限とその対処法についてお伝えします。

GASによるGmailの読み書きの制限について

まずコチラの「Google Apps Script ダッシュボード」のページをご覧ください。

Google Apps Scriptで実行する際の各種動作の制限が一覧されています。

その中で、Gmailに関しては「Gmailの読み取りと書き込み(送信以外)」という項目で

  • 一般ユーザー(gmail.com):20000 個/日
  • G Suite Basic / Business:50000 個/日

とありますね。

有料版のG Suiteと無料のGoogleアカウントでは異なりますが、いずれもGmailの読み取り件数には制限があるということをまず抑えておきましょう。

以降本記事では、無料のGoogleアカウントを前提に、20000件が許容量ということで話を進めていきます。

GASでGmailの取得件数がオーバーしてしまう例

例えば、以前書いたこちらの記事。

【GAS】Gmailに送られた過去のメールから特定条件のメールを検索して取得する
問い合わせメールのデータの蓄積と効果分析にまつわることを色々とやっていきたいということで、今回はGoogle Apps Scriptで過去の問い合わせメールを特定条件で検索して取り出す方法です。

意外に参考にして頂いているケースが多いようで大変うれしいのですが、実はちょっと問題がありました。

スクリプトはこちらです。

スクリプトを仕込んでいるGoogleアカウントのGmailから

‘(“このメールは 株式会社プランノーツ http://plannauts.co.jp のお問い合わせフォームから送信されました” OR “このメールは いつも隣にITのお仕事 http://tonari-it.com のお問い合わせフォームから送信されました”)’

という条件で検索するという内容です。

GmailApp.searchメソッドの最大取得数に注意

「1日20000件なんて、そんないかないだろ~」って思いますでしょ?

実はそうじゃないんです。

まず、例えば15分に一回のトリガーを仕込んだとすると、このスクリプトは1日で96回呼び出されることになりますよね。

そして、ポイントはこの7行目の一文。

Gmailから指定の条件でスレッドを検索するsearchメソッドですが、書き方はこうです。

GmailApp.search(検索条件, 開始スレッドのインデックス, 最大取得数)

そして、3つめの引数である最大取得数ですが、上記スクリプトの例では500件です。

条件にマッチするスレッドがMAXの500件あったとすると、1日で96回呼び出されるわけですから

500件×96回/日=48000件/日

となり、余裕でオーバーとなります。これはいかんですね。設計ミスです。

GmailApp.searchメソッドを使う場合は、その最大取得数に気をつけなければいけないのです。

Gmailの制限はすぐにオーバーする

実際はどうでしょうか。

試しに、現時点でGmailを同条件で検索してみたら

Gmail検索の結果件数

このように、146件でした。

15分に1回の場合、1回あたりの受信件数の許容量は

146件/回×96回/日≒14016件/日

ですから、今のところ20000件/日の許容範囲内ですが、検索条件にマッチする問い合わせメールが208件ほどたまった段階で、オーバーするようになっていってしまうということです。

以下、分タイマーでトリガーを仕込んでいる場合の最大取得数の参考値です。

トリガーの間隔 最大取得数の許容数
1分 13件
5分 69件
10分 138件
15分 208件
30分 416件

さらに、同一アカウントで複数のスクリプトを仕込んでいる場合は、全ての合算値になりますから

  • 個々の最大取得数はできる限り小さい
  • イベントトリガーの間隔はできる限り長い

に越したことはありません。

最大取得数と検索条件をfunctionから外出しする

このように、GmailApp.searchメソッドの最大取得数はちょいちょいチューニングをするような数値になりますので、以下スクリプトのようにfunction外で指定するようにするほうが、わかりやすいかも知れませんね。

ついでに、検索条件も外出ししてみました。

まとめ

以上、Google Apps ScriptにおけるGmailの読み取り件数の制限とその対処法についてお伝えしました。

Gmailの読み取り件数に関しては、GmailApp.searchメソッドの最大取得数とイベントトリガーの発火間隔についてはよく注意して設計をして下さいね。

GASはクラウド環境でたいへん便利な一方で、様々な制限が課せられていますね。

ただ、制限内で開発するというのは、けっこうスキル的には向上の機会だったりもするので、ポジティブに捉えています。

また、気を付けて欲しい点があれば、記事にしますね。

どうぞお楽しみに!

連載目次:GASでGmailに届いた問い合わせメールを分析する

お仕事の現場では日々様々なメールが届きます。その中で重要なのが「問い合わせメール」ですね。このシリーズでは、Webサイトからの問い合わせメールを自動でスプレッドシートに取り込んだり、チャットワークに送る方法についてお伝えしていきます。

  1. 【GAS】Gmailに送られた過去のメールから特定条件のメールを検索して取得する
  2. 【GAS】Gmailからメールを検索してスプレッドシートに書き出す
  3. フリーランスの仕事はどこから来たか、独立して1年間の受注件数を全て晒す
  4. 【GAS】新たな問い合わせメールをGmailで取得しスプレッドシートに随時追加する
  5. 【GAS】Gmailに来た問い合わせをチャットワークに通知してかつタスク追加する
  6. Google Apps ScriptにおけるGmailの読み取り件数の制限とその対処法
  7. 【GAS】Gmailの特定条件で検索したスレッドの全メールを取得してスプレッドシートに書き出す
  8. 【GAS】GmailのメッセージIDを利用して新規メールのみをスプレッドシートに追加する

  投稿者プロフィール

タカハシノリアキ株式会社プランノーツ 代表取締役
株式会社プランノーツ代表、コミュニティ「ノンプロ研」主宰。1976年こどもの日生まれ。東京板橋区在住。「ITで日本の『働く』の価値を上げる!」をテーマに、VBA&GASの開発、講師、執筆などをしております。→詳しいプロフィールはコチラ
★ご依頼・ご相談はお気軽にどうぞ!→お問い合わせはコチラ
★フォロー頂ければ嬉しいです。

コメント

  1. Fujii より:

    はじめまして。貴重な情報をシェアしていただいていつも有難うございます。初めて組んでみたGoogleスプレッドシートのスクリプトでGmailApp.searchの上限に達してしまった様で悩んでいます。Gmailの特定ラベル内のメールをスプレッドシートへインポートするものです。
    ============================
    function mailToSheet () {

    // —– ここから書き換え —–
    // 書き込むシートURL
    var sheet_url = ‘https://docs.google.com/spreadsheets/d/xxxxxxxxxxxxx/edit’;
    // 書き込むシート名
    var sheet_name = ‘シート1’;
    // Gmailの抽出条件
    var mail_query = ‘Label:BTA’;
    // 存在チェック(既にシートに書き込み済のメールは処理しない(日付、from、to、件名の一致で判定))
    var existence_check = true;
    // —– ここまで書き換え —–

    var ss = SpreadsheetApp.openByUrl(sheet_url);
    var sheet = ss.getSheetByName(sheet_name);
    var existence_keys = fetchExistenceKeys();
    var mail_data = fetchMailData();
    for (var i = 0; item = mail_data[i]; i++) {
    if (existence_check && existsData(item)) {
    continue;
    }
    sheet.appendRow(itemToRow(item));
    }

    function fetchExistenceKeys () {
    var existence_keys = {};
    var sheet_data = sheet.getDataRange().getValues();
    for (var i = 0; row = sheet_data[i]; i++) {
    existence_keys[generateKey(rowToItem(row))] = true;
    }
    return existence_keys;
    }

    function existsData (item) {
    if (existence_keys[generateKey(item)]) {
    return true;
    }
    return false;
    }

    function generateKey (item) {
    var key = item[‘date’] + ‘_’ + item[‘subject’] + ‘_’ + item[‘from’] + ‘_’ + item[‘to’];
    // Logger.log(key);
    return key;
    }

    function rowToItem (row) {
    var item = {};
    item[‘date’] = row[0];
    item[‘subject’] = row[1];
    item[‘from’] = row[2];
    item[‘to’] = row[3];
    return item;
    }

    function itemToRow (item) {
    var row = [];
    row[0] = item[‘date’];
    row[1] = item[‘subject’];
    row[2] = item[‘from’];
    row[3] = item[‘to’];
    row[4] = item[‘body’];
    return row;
    }

    function fetchMailData () {
    var result = [];
    var threads = GmailApp.search(mail_query);
    for (var i = 0; it = threads[i]; i++) {
    var messages = it.getMessages();
    for (var j = 0; message = messages[j]; j++) {
    var item = {};
    item[‘date’] = message.getDate();
    item[‘subject’] = message.getSubject();
    item[‘from’] = message.getFrom();
    item[‘to’] = message.getTo();
    item[‘body’] = message.getBody();
    result.push(item);
    }
    }
    return result;
    }
    }
    =======================
    このようなスクリプトです。
    当初、何もわからずトリガーを5分間隔で設定していましたら、3日目にLimitに達したというエラーが出るようになってしまいました。今は一日一度のトリガーに変更しましたが、それで回避策になるでしょうか?一日に新しい該当メールは1000通ほど届きます。
    もし教えていただけるようであれば救われます・・どうぞよろしくお願いいたします。

    • Fujiiさん

      コメントありがとうございます。
      GmailApp.searchメソッドで指定している検索条件のクエリがラベルだけで、かつ最大取得数を指定していないので、毎回500スレッドを取得する形になっているものと思います。
      対策としては、未読のスレッドだけを拾って処理済みのスレッドは既読にする、処理済みのスレッドには別のラベルをつけてそのラベルは検索条件の対象外にするなどが対策としてはあるかと思います。

      今は一日一度のトリガーに変更しましたが、それで回避策になるでしょうか?一日に新しい該当メールは1000通ほど届きます。

      記事にもある通り、Gmailの読み取りは一日20000件ですので、1日1回のトリガーなら制限にはかかりません。ただ、1回あたり500件までしか取得しないので、1000通届くなら取得漏れする可能性があるかと思います。

  2. 人造人間クリリン40号 より:

    こんにちは、タカハシさん

    いつも大変助かっております。
    1点質問です。

    Gmail内でスレッド化したものは、その最初のメールの内容しか届かないようなのですが、
    どうにか切り分ける方法は無いでしょうか?

    どうぞよろしくお願いいたします。

    • 人造人間クリリン40号さん

      お返事遅くなりましてごめんなさい。
      実際におっしゃる通りの仕様になっています。

      解決する方法はありますので、別途記事にて紹介したいと思います。

      お待ちいただければありがたく思います。
      よろしくお願いいたします。