文学徒が競プロをするブログ

競技プログラミングの精進を記録していきます

GASで要対処メールを通知してくれるbotを作った

はじめに

競プロの話ではないのでこのブログの趣旨からは外れるんですが、まあ自分のブログなので(今後旅行記やポエムなんかも載せる予定)。

ところで皆様、メールって見るのしんどくないですか。
いや、確かに苦にならない方もいるのでしょうが、そんな方は就活中の大学生になった気持ちで考えてみてください。

そう、


マ○ナビやらリク○ビやらから来るメールに受信ファイルが埋め尽くされてつらい。


ということです。
正直に言って、私は就職に関してそこまでの熱意を持っていません。しかし完全に世を捨てる意思も覚悟も度胸もありません。毎日しつこく送られてくるメールにほとほと嫌気がさし、知らんふりを決め込もうとして、しかし頭の片隅に巣食う不安が、このままこれらを無視して良いのかと日々私を苛むのです。

自然ストレス源となるメーラーを開く頻度は少なくなり、重要なメールを見逃してしまう始末。気力も薄れ、要返信のものをすぐに返せなくなります。


さてここまで前置き。
まあ就活関係のことはしょうがないとして、皆様も要返信のメールが送られてきた時、すぐに対処できないことってありますよね。そんでそのまま忘れちゃったりしますよね。

そこで考えました。LINEだったら見るじゃん?と。
LINEを見ない人でも、Slackだったら見るじゃん?と。

というわけで通知してくれるブツを作りました。

成果物

f:id:sarashina-nikki65:20180904021448j:plain

f:id:sarashina-nikki65:20180904162521p:plain

いかがでしょうか。これが日に二回ほど来れば、要対処メールを忘却することはなくなるでしょう(対処する気力が芽生えるかは知らないけれど)。
※ちなみに画像からも分かる通り、私は9/10より二週間ほど欧州(旧ユーゴスラヴィア地域)へ高飛びする予定です。共産主義民族主義の残り香を嗅ぎながら旅行日記書くから読んでね。

仕組みとコード解説

このbotはGAS(Google App Script)とLINE Messaging APIを組み合わせて実装しています。
GASを採用した理由としては、私は普段Gmailを使用しており何かとやり易いためです。
GASについては何回か書いたことがあったのですがLINEについては不慣れで、相当に苦労しました。Slackの方が簡単な気がしないでもないです。そもそもAPIを使ってメッセージを送るのが初めてだったので、知らない概念がポンポン出てきて死にそうでした。

さてこのbotにやらせたいことですが、

  • 要対処メールを識別する
  • それらの総数をカウントする
  • それらの件名を取得し通知する

の3つになります。

これらを実現するために、Gmailのラベル機能を用います。
返信或いは対処を必要とするメールが届き、しかしそれをするだけの時間がない時、ありますよね? そんな時は「要対処ラベル」をポチっと付けます。

f:id:sarashina-nikki65:20180904012944j:plain

そして一定時間毎にスクリプトが受信トレイを検索し、要対処ラベルが付いたメールの数とそれぞれの件名を取得してLINEで通知する、という流れになっています。
LINEの設定法についてはGAS - LINE Messaging APIとかで検索すればわんさと出てくるので、そこまで難しくはありません。
SlackについてもGAS - slack - Incoming webhooksとかで検索かければ出てくるので気になる方は探してください。

以下、実際のコードを記載します。コメントをかなり書いているのでそこそこ分かりやすいかと.......。

コード
var URL = "https://api.line.me/v2/bot/message/push"//push通知にはここにhttpリクエストを投げます
var ACCESS_TOKEN = "<Your TOKEN!!>";//APIの管理画面から取得できるトークンを貼ります
var ID = "Your ID!!";//自分に投げたいならあなたのIDをどうぞ

function push(){
  //ラベルの名前は任意に変えられます
  const label = 'label:要対処';

  //GmailApp.search()で受信トレイ内にある全てのスレッドを任意の条件で検索できます
  const threads = GmailApp.search(label);

  //要対処ラベルがついたスレッドの数を取得します
  const count = threads.length;

  //各スレッドの最初の件名を受け取ります
  const subjects = new Array(count);
  for(i = 0; i < count; i++) {
    subjects[i] = threads[i].getFirstMessageSubject();
  }
  write(subjects, count);
}

//メッセージ通知用の関数です
function write(subjects, count){

  if(count < 5) {
    var subjects_num = count;
  } else {
    var subjects_num = 5;
  }

  //あまり大量の件名が来てもアレなので、件名通知は5件に制限します
  const message1 = "現在、要対処メールは"+count+"件あります。以下は直近"+subjects_num+"通の件名です"

  //件名を通知用に加工します
  var message2 = "";
  var message3 = "以上となります"
  for(i = 0; i < subjects_num; i++){
    message2 += "・"+subjects[i]+"\n";
  }
  
  //公式リファレンスを見れば分かりますが、以下のように設定すれば送れるようになっています
  var postdata = {
    "to" : ID,
    "messages" : [
      {
        "type" : "text",
        "text" : message1
      },
      {
        "type" : "text",
        "text" : message2
      },
      {
        "type" : "text",
        "text" : message3
      }
    ]
  }
  
  var param = {
    "method" : "post",
    "headers" : {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN//Bearerの後の半角スペース忘れずに
    },
    "payload" : JSON.stringify(postdata)
  }

  //指定のURLにオブジェクトを飛ばします
  var response = UrlFetchApp.fetch(URL, param);
}


あとはこれをタイマートリガーで発火させれば、毎日通知を送らせることができます。
Slackでもpush関数のロジックは同じで、Income Webhookを用いればSlackに通知させることが可能です。
以下Slackの通知コード(write関数のみ)

function write(subjects, count){
  if(count < 5) {
    var subjects_num = count;
  } else {
    var subjects_num = 5;
  }
  const message1 = "現在、要対処メールは"+count+"件あります。以下は直近"+subjects_num+"通の件名です"
  var message2 = "";
  var message3 = "以上となります"
  for(i = 0; i < subjects_num; i++){
    message2 += "・"+subjects[i]+"\n";
  }
  
  const username = "Gmail-Notification";
  
  var postdata = {
    "username": username,
    "attachments":[
       {
          "fallback":message1,
          "pretext":message1,
          "color":"#00FF00",
          "fields":[
             {
                "title":"件名",
                "value":message2+message3
             }
          ]
       }
    ]
  }   
  
  var param = {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : JSON.stringify(postdata)
  }

  var response = UrlFetchApp.fetch(URL, param);
}


皆はちゃんとメール見ような!!

あとがきというか展望

Gmailヘビーユーザーのラベル魔人(ラベルを設定しまくっている人)のために、直近50件にどんなラベルが幾つ貼られているかを通知してあげるスクリプトとか作りたいです。
というか八割がた完成しています。