ふくらみ

膨張し続けている

Google Apps ScriptでGmailの大量の未読を一掃する

最近忙しかったのでGmailを放置していたら酷いことになった。

f:id:tfukumachi:20171001020344p:plain
画像は再現

こういう大量の未読メールを手作業で処理するのはこのクソ忙しい中では不可能である。
そういうわけで、自らの手を汚さず機械の手で虫けらのような未読を一掃することにした。

一掃しよう

使うのはGoogle Apps Script(GAS)。Google神がこの世に遣わした文明の利器である。
詳しくは公式のドキュメントか、丁寧に解説してくれるアフィサイトがググればたんまり出てくるのでそちらを見てほしい。

余談だが個人的にGASは愛用しており、メールを処理してSlackに投げたり、OPACを叩いて図書館で借りた本の期限管理をしたり、Twitterbotを作ったりしている。Javascriptなので型なんかもなく無思考で書けるのが最高なのだ。

さて、端的に誰でもわかるやり方だけ書く。
とりあえずscript.google.comにアクセスするか、Google Drive新規>その他>アプリを追加からGoogle Apps Scriptを探そう。

何か画面が出てきたら、下記をコピペ。

function unreadKiller(){
  //メインの処理
  var inbox = GmailApp.search("in:inbox is:unread"); // max 500 threads
  var unreadCount = GmailApp.getInboxUnreadCount();
  for (var i=0; inbox[i] && unreadCount>0; i++){
    if(inbox[i].isUnread()){
      inbox[i].markRead();
      unreadCount--;
    }
  }

  //500件を超える場合の処理
  //使用済みトリガー削除
  var userProp = PropertiesService.getUserProperties();
  var userPropKey = "unreadKillerLastTriggerId";
  var triggerId = userProp.getProperty(userPropKey);
  if(triggerId){
    var triggers = ScriptApp.getProjectTriggers();
    for(var i=0; i<triggers.length; i++){
      if(triggers[i].getUniqueId() == triggerId){
        ScriptApp.deleteTrigger(triggers[i]);
        break;
      }
    }
    userProp.deleteProperty(userPropKey);
  }

  //継続用トリガーの追加
  if(unreadCount>0){
    var trigger = ScriptApp.newTrigger("unreadKiller").timeBased().after(10*1000).create(); //wait 10 sec.
    userProp.setProperty(userPropKey, trigger.getUniqueId());
  }
  //ここまで
}

コピペしたら上の「関数を選択」からunreadKillerを選び、隣の三角形を押す。
すると恐らく「許可が必要です」というダイアログが出るので、許可を確認
もしかすると次のような警告が出るかもしれない。
f:id:tfukumachi:20171001022145p:plain:w300
出た場合は、「unreadKiller(安全ではないページ)に移動」を構わず押す。
f:id:tfukumachi:20171001022343p:plain:w300
こんなものが出るので、差支えなければ許可してやってほしい。

あとはGmailの画面で少しずつ経る未読数を眺めるなり、面白いアニメを見る(※10/10まで)なりしよう。




f:id:tfukumachi:20160923224800p:plain



で、何をやっているの?

メインの処理は以下のとおり。

  • Gmailの未読メールを列挙する
  • ループさせて全部既読にする

慣れた人ならお怒りだろう。こんな単純な処理のためにブログ記事なんか書いて帯域を無駄遣いするんじゃない。大体なんだ。こんなコードに何十行もかけやがって。無能め。
申し訳ないのだが、正直5行くらいで済むはずだった。そう思っていたのだ。

実は、GASのGmailAppでスレッドを一回に取得できる数には限りがある。公式リファレンスには記載がないようだが、inboxやラベル等あらゆるスレッド取得処理において、最大取得数は500に制限されている。つまり、未読が500件を超える場合は先の処理を複数回実行する必要がある。

さらに面倒なのが、実行5分制限だ。GASでは1回のスクリプトの処理が5分以内に終了していなければならない。500件の未読メールを既読にする処理は、筆者の手計測でおよそ2~3分程度の時間がかかる。つまり、1000件を超えるような場合は手動でもう一度スクリプトを実行する必要が出てくる。ファッキンシット*1

というわけで、以下の処理を付け加える羽目になったというわけだ。

  • ScriptAppのトリガー作成機能で時間主導型トリガーを10秒後にセット
    →トリガーをかませば5分制限に引っかからない
  • 使用済みトリガーは勝手に消えてくれないのでこれを削除する
    ScriptAppが妙に痒いところに手が届かないせいで、削除にはトリガーのUniqueIdが要る
  • 削除のためのUniqueIdPropertiesServiceを使って保持する

未読の数が500件を超えない人で、余計な権限を与えたくない人は//500件を超える場合の処理以下を削除すると良いだろう。

f:id:tfukumachi:20171001030615j:plain
お わ り

*1:余談だが、無料のGoogle Apps Scriptでは一日あたりのGmail処理件数が20000までという制限もあるのでこちらにも注意する必要がある