Google Apps ScriptでSlackにbotを作る(1)

Google Apps ScriptでSlackにbotを作る(1)

概要

GASが一定間隔でGmailからメールデータを取得し、新たに受信したメールがあれば内容をSlackに投稿するbot。

  1. 設定したトリガーが実行される。
  2. GASがgmailからメールデータを取得する
  3. スプレッドシートにある前回実行したときのメールデータと比較し、新たに受信したメールがあるかを確認する。
  4. 新たに受信したメールの内容をSlackにPOSTする。
  5. Slackのチャンネルに投稿される。

今回は例として、自分のメールボックスにconnpassから配信される勉強会の情報をまとめているラベルがあるので、そこから新着情報を抽出してSlackに流すようにしたいと思います。

作成

gmailまわり

gmailから「勉強会」というラベルに該当するメール情報を取得する。

getMail.gs

function getMail() {
  
  var condition = 'label:勉強会';
  var myThreads = GmailApp.search(condition,0,30);
  var myMsgs = GmailApp.getMessagesForThreads(myThreads);
  
  var valMsgs = [];
  
  //各メールから日時、送信元、件名、内容を取り出す
  for(var i=0; i<myMsgs.length; i++) {
    valMsgs[i] = [];
    valMsgs[i][0] = myMsgs[i][0].getDate();
    valMsgs[i][1] = myMsgs[i][0].getFrom();
    valMsgs[i][2] = myMsgs[i][0].getSubject();
    valMsgs[i][3] = myMsgs[i][0].getPlainBody();
  }
  return valMsgs;
}

conditionにメールの抽出条件を入れています。

スプレッドシートまわり

スプレッドシートの用意

二つの列のデータを比較して、差分が表示されるようなスプレッドシートを作成します。

スプレッドシート名は「botSpreadSheet」
シート名は「mailList」
C列の一番下まで以下の関数を入れています。

=IF(COUNTIF($B$1:$B$1000,A1)=0,A1,)

スプレッドシートを操作する

以下の動作を実装しています。

  • A列にデータを書き込む
  • A列のデータをB列へ移動する
  • C列のデータを取得する

spreadControl.gs

//A列にデータを配列で書き込む(1次元配列が引数)
function setSheetColumnValues(values) {
  
  //1次元配列を2次元配列に変換する(setValuesは2次元配列が引数)
  var doubleArray = [];
  for each(var value in values) {
    doubleArray.push([value])
  }
  
  var spreadSheet = SpreadsheetApp.openByUrl("[スプレッドシートの共有パス]");
  var sheet = spreadSheet.getSheetByName("mailList");
  var cols = values.length;
  
  sheet.getRange(1, 1, cols).setValues(doubleArray);
}

//A列のデータをB列へ移動する
function moveSheetColumnValues() {
  var spreadSheet = SpreadsheetApp.openByUrl("[スプレッドシートの共有パス]");
  var sheet = spreadSheet.getSheetByName("mailList");
  
  //A列のデータをB列へコピー
  sheet.getRange("A:A").copyTo(sheet.getRange("B:B"),{contentsOnly:true});
  //A列のデータを削除
  sheet.getRange("A:A").clear();
}

//C列のデータを配列で取得する
function getSheetColumnValues() {
  var spreadSheet = SpreadsheetApp.openByUrl("[スプレッドシートの共有パス]");
  var sheet = spreadSheet.getSheetByName("mailList");
  var data = sheet.getRange("C:C").getValues();
  
  var result = new Array();
  
  for each(var value in data) {
    if(value != null && value != "") {
      result.push(value);
    }
  }
  
  return result;
}

Slackまわり

Slackに通知されるように設定します。

Incoming Webhookの作成

SlackのAppからIncoming Webhookを追加します。

Slackに投稿する

postSlack.gs

function testPost() {
  var text = "text";
  postSlack(text);
}

function postSlack(text,url) {
  
  var url="[Incoming Webhookで設定したURL]";
  var jsonData={
    "channel":"botテスト",
    "username":"J.A.R.V.I.S",
    "text":text
  }
  
  var options={
    "method":"POST",
    "headers":{"Content-type":"application/json"},
    "payload":JSON.stringify(jsonData)
  };
  UrlFetchApp.fetch(url,options);
}

この例だと、「#botテスト」というチャンネルがあり、そこに「J.A.R.V.I.S」という名前で投稿するように設定しています。
※J.A.R.V.I.Sはアイアンマンの映画に出てくるトニーをサポートするAIの名前です。
testPost()を実行させると上の投稿がされます。

一つのAppとしてまとめる

main.gs

function main() {
  var mailDataList = getMail();
  
  var titleList = [];
  for each(var mailData in mailDataList) {
    titleList.push(mailData[2]);
  }
  
  setSheetColumnValues(titleList);
  
  var targetList = getSheetColumnValues();
  
  moveSheetColumnValues();
  
  if(targetList.length === 0) {
    Logger.log("through");
  } else {
    Logger.log("push slack");
    
    for each(var postText in targetList) {
      postSlack(postText.toString());
    }
  }
  Logger.log(targetList);
}

トリガーを設定する

gasエディター画面上で「現在のプロジェクトのトリガー」タブを選択するとトリガー画面に遷移します。
「トリガーを追加」から以下のように設定してください。

  • 実行する関数は「main」
  • イベントのソースは時間主導型に
  • トリガータイプは分ベース
  • 15分おき

GASからメールの取得は1日100回までしかできない

GASからメールを取得する関数を叩いたときに、受信は無料アカウントの場合だと1日100件しか行うことが出来ません。
https://developers.google.com/apps-script/guides/services/quotas

なので、1日24時間で100回叩くことを逆算して、15分置きであれば1日94回の実行で済む計算になります。

実行

Slack上に投稿されました。

今回はメールを取得しタイトルのみを投稿させるようにしていましたが、
取得したメールの本文を整形して投稿出来たりもします。

メールのリストの本文に対して欲しい文字列だけを抽出して返す関数も作成したので一応載せておきます。

function mailDataList() {
  
  var list = getMail();
  

  var regex = new RegExp("【増席】.*|URL.*","g");
  var resultList = [];
  
  for(var i=0; i<list.length; i++) {
    resultList[i] = list[i][3].match(regex);
  }
  
  Logger.log(resultList);
  
  return resultList;
}

上の例では、
「【増席】」、「URL」という文字がついている文章を抽出するような正規表現で、すべてのメールに対して適用しています。

プログラミングカテゴリの最新記事