GASで重要なメールをSlackに転送しよう

Google Developer Student Club Tokyo City UniversityのYukiです。
# はじめに
gmailをよく使っているのですが、色んなところでメールアドレスを登録しているおかげで、メールの整理ができなくなってきています。
段々とメールが溜まっていき、大抵のメールは読まなくても良いものの、読まなければいけない重要なメールを見逃してしまう可能性が高くなってきます。
そこで、Gmailの検索機能とGAS(Google Apps Script)を使ってWebhook経由でSlackに重要なメールの通知を行いたいと思います。

# Webhookの設定
参考：https://api.slack.com/messaging/webhooks
## Slack appの作成
https://api.slack.com/apps?new_app=1 にアクセスして、Slack appを作成します。
「From scratch」を選択し、「App name」には好きな名前を付け、追加するワークスペースを選択します。作成ができたら、「Incoming webhook」を選択して、「Add New Wobhook to Workspace」をクリックします。
投稿先のチャンネルを選択し、「許可する」をクリックします。
これでWebhookのURLが作成できました。
下の方にスクロールすると、WebhookのURLがコピーできる状態になっています。
WebhookのURLにはチャンネルへの投稿権限などが付いていますので、扱いには注意しましょう。

# GASからSlack WebhookにPOSTする
SlackのWebhook URLに対しては、Content-typeにapplication/jsonを指定し、POSTを行います。
キー「text」に送りたい内容を値としてセットしてPOSTすることで、Slackのチャンネルに投稿できます。
それを実現した関数がこんな感じです。
```javascript
function postToSlack(message) {

  let jsonData = {
    "text" : message
  }
  
  let payload = JSON.stringify(jsonData);

  let options = {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload
  };

  let response = UrlFetchApp.fetch(PropertiesService.getScriptProperties().getProperty("slack_webhook_url"), options);
  Logger.log(response.getContentText());
}
```
PropertiesServiceで、ScriptPropertiesの`slack_webhook_url`の値をURLとして使用するようにしています。Google Apps Scriptのプロジェクトの設定から、Script PropertiesにPropertyをslack_webhook_urlを入れ、Valueに先ほど作成したWebhookのURLを入れて保存します。
ここまでできているか確認するために、テストメッセージを送信する関数を作りました
```javascript
function sendTestMessage() {
    postToSlack("Hello, World!");
}
```
こんな感じでSlackにメッセージが送られてきたら、ここまでは大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568101/0443a708-a336-a854-8963-59534b4c671a.png)

# Slackにメールを通知する
ここからは通知するメールを取得する処理を記述していきます。
今回は次のような設計で組んでいきたいと思います
- Slackに通知するメールは予めGmail側でラベル付けを行う
- ラベル付けされたメールのみをSlackに通知する
- Slackに通知したメールからはラベルを剥がす

## Gmailでラベル付けを自動化する
これは、特にプログラムを組みません。
よほど複雑な条件でない限り、Gmailのフィルタ機能で実現できます。
https://mail.google.com/ にアクセスして、画面上部の検索ボックスの右端にある「検索オプションを表示」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568101/1e6acdfa-4f07-57cf-7755-242591b6f927.png)
通知したいメールの条件を入力し、「フィルタを作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568101/416c7772-5160-bd37-d7d0-8bf6a05ba4d1.png)
条件に引っかかるメッセージが来たときにどのような処理を行うかを聞かれるので、「ラベルの適用」を設定します。設定したラベルはSlackへの通知と同時に剥がされるようにするので、私は「SendToSlack」というラベルを付けるようにしました。既読にすることもできるので、この辺のオプションはお好みで設定すると良いでしょう。

## ラベル付けされたメールのみをSlackに通知する
今回はスレッドの一番最初のメッセージを取得してその内容から概要を通知するようにします。具体的な内容が知りたくなったときのためにメールへのリンクも貼るようにします。
```javascript
function getMail() {
  const gmail_base_url = "https://mail.google.com/mail/u/0/#inbox/";
  let threads = GmailApp.search('label:SendToSlack');

  for(let thread of threads) {
    let msgs = thread.getMessages();

    // 該当メッセージについて送信
    if(msgs[0]) {
      let msg = msgs[0];
      let from = msg.getFrom(); // 送信元
      let to = msg.getTo(); // 送信先
      let date = msg.getDate(); // 日付
      let subject = msg.getSubject(); // 件名
      let id = msg.getId(); // メッセージID(URL用)
      // ここからメッセージ生成(\nはSlackでの改行)
      let notify_message = "From : " + from;
      notify_message += "\nTo : " + to;
      notify_message += "\nDate : " + date;
      notify_message += "\nSubject : " + subject;
      notify_message += "\nURL : " + gmail_base_url + id; // Gmailの受信トレイの後ろにメッセージIDを付けることで、URLとして利用可能
      postToSlack(notify_message); // Slackに送信
    }
  }
}
```
これでSlackに、送信元、送信先、日付、件名、メールへのURLが送信できるようになりました。
ただし、このままだと永遠と同じメッセージがSlackに送信され続けるのでラベルをはがす処理を追加します。
## メールからラベルを剥がす
メールからラベルを剥がすためには、GmailAppから`GmailLabel`を取得しておく必要があります。
取得したGmailLabelを既にSlackに送信したメッセージから剥がすようにします。
```javascript
function getMail() {
  const gmail_base_url = "https://mail.google.com/mail/u/2/#inbox/";
  const trigger_label = GmailApp.getUserLabelByName('SendToSlack'); // New GmailAppからGmailLabelを取得する
  let threads = GmailApp.search('label:SendToSlack');

  for(let thread of threads) {
    // ...
    thread.removeLabel(trigger_label); // New 取得したGmailLabelをスレッドから剥がす
  }
}
```

# 作ったスクリプトを自動実行する
これで特定のラベルが付けられたメールをSlackに通知して、再通知もされないようにすることができました。後はこのスクリプトを自動実行するように設定するだけです。
Google Apps Scriptの編集画面の左側から「トリガー」を選択し、「トリガーを作成」をクリックします。
作ったメール取得関数を指定し、時間基準型で、毎分単位で実行されるように設定します。設定ができたら保存でOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568101/59424313-158e-e08b-ab7f-dc4afe918f4c.png)

# 終わりに
これで、GmailからSlackにWebhookで通知することができるようになりました。
GmailからSlackに通知する記事は需要があるからか結構ありますが、Gmail側でラベル付けするやり方はあまり出てこなかったので記事にしてみました。
最後まで読んでいただきありがとうございます。