【GAS】Gmailのメール受信をChatworkに通知
Posted on 2017/07/16 in tech
zapier が Chatwork と連携していて便利。Gmailの特定メール受信時に、Chatworkへ通知させてみたら喜ばれた。
けれども無料プランだと
- 月に100のタスクまでしか処理できない
- 5つまでしか設定を保存できない
という制限がある。
人は無料だと喜ぶけど、有料になったとたんに「はん。まぁ、金払えば便利にはなるわな」となる。切ない。
とりあえず前者だけ解決したくて、今回GASで書いたときのメモ
理想的な流れ
Gmail 受信 → Chatwork API たたく→ Chatwork に通知くる
現実
GAS定期実行で新規メール確認→新規メール発見したらChatwork API たたく→Chatworkに通知くる
要するにバッチ処理で新規メールを確認して判定する。ただ、おもむろに1分間隔でバッチ走らせてたら夜にメールがきた。
泣いた。
ここ↓をよく読んでおきましょう
https://developers.google.com/apps-script/guides/services/quotas?hl=en
最終的に15分間隔くらいでバッチを回しました。
用意するもの
-
Chatwork API 認証トークン
- ビジネスアカウント契約しないと取得できない
- 参考: [http://developer.chatwork.com/ja/authenticate.html]
-
Gmail
- 僕はInbox派
-
Google Apps Script
当然だけど、自分のGoogleアカウントで受信できるメールを通知します。
スクリプトはよ
とりあえずGAS(Google Apps Script)のコードのサンプル。
function run() {
var title = "メール通知";
var searchQuery = "from:delivery@mail.com to:me@gmail.com";
var checkSpanMinute= 15; // 起動時間間隔(15分)
/* debug
var roomId = "1010101"; // テスト用のマイチャットルーム ID
/*/
var roomId = "21212121"; // 通知したいチャットのルーム ID
//*/
var dt = new Date();
dt.setMinutes(dt.getMinutes() - checkSpanMinute);
var threads = GmailApp.search(searchQuery);
var msgs = GmailApp.getMessagesForThreads(threads);
for(var i = 0; i < msgs.length; i++) {
var lastMsgDt = threads[i].getLastMessageDate();
if(lastMsgDt.getTime() < dt.getTime()) {
break;
}
for(var j = 0; j < msgs[i].length; j++) {
var msgDate = msgs[i][j].getDate();
var msgBody = msgs[i][j].getPlainBody();
var msgFrom = msgs[i][j].getFrom();
var matches = msgFrom.match(/"(.+)".*<(.+)>/)
{
var subject = msgs[i][j].getSubject();
var postMsg = "[info]" +
title + "\n" +
Utilities.formatDate(msgDate, 'Asia/Tokyo', 'yyyy/MM/dd hh:mm:ss') + "\n" +
"件名:" + subject + "\n" +
"[hr]" +
msgBody +
"[/info]";
// リクエストトークン
var token = {
"method" : "post",
"headers" : {
"X-ChatWorkToken" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // Chatworkの認証トークン
},
"payload" : {
"body" : postMsg,
}
};
var apiUrl = "https://api.chatwork.com/v2/rooms/" + roomId + "/messages"
var response = UrlFetchApp.fetch(apiUrl, token);
}
}
}
}
動作結果 in Chatwork
真っ黒じゃねぇか
解説
var searchQuery = "from:delivery@mail.com to:me@gmail.com";
Gmail検索クエリ。Gmailの検索バー?で入力してみて、通知させたいメールだけヒットするか試してみるといい。
参考: Gmail で使用できる検索演算子 - Gmail ヘルプ
複数条件をスペースで入力するとAND検索になる。リンク先には紹介されていないが、NOTも使えた。
/* debug
var roomId = "1010101"; // テスト用のマイチャットルーム ID
/*/
var roomId = "21212121"; // 通知したいチャットのルーム ID
//*/
あんまりGAS関係ないけど このコメントの書き方は
新卒エンジニアでもできる!コメントアウトで同期に差をつける裏技 - Qiita で知った。
debug
と書かれた先頭の行に/
をつけると、デバッグモードのチャットルームIDが有効になる。
//* debug
var roomId = "1010101"; // テスト用のマイチャットルーム ID
/*/
var roomId = "21212121"; // 通知したいチャットのルーム ID
//*/
ほらね。すごい。
ちなみにルームIDは、通知させたいチャットを開いた際のURL末尾のridに続く数字のこと。
例えば https://www.chatwork.com/#!rid102030
なら 102030
がルームID。
var dt = new Date();
dt.setMinutes(dt.getMinutes() - checkSpanMinute);
分単位の計算。現在時刻から checkSpanMinute
分だけ遡って検索してる
var threads = GmailApp.search(searchQuery);
var msgs = GmailApp.getMessagesForThreads(threads);
検索クエリ searchQuery
でGmailを検索してる。
GmailThread
クラスと GmailMessage
クラスの概念をここで把握しておくべきなのだけれど、ざっくり言うと GmailThread
はスレッド(まんまや)。同じ件名でお互いが返信し続けると、Gmailって1つのスレッドで表示されますよね。あのひとまとまりが、GmailThread
クラスのインスタンスとして扱える。
GmailThread
インスタンスには、そのスレッドを構成する GmailMessage
クラスのインスタンスを持つ。
Gmail Service | Apps Script | Google Developers
ここで注意が必要だったのが、それぞれのインデックスの扱い方。
var msgs = GmailApp.getMessagesForThreads(threads);
for(var i = 0; i < msgs.length; i++) {
var lastMsgDt = threads[i].getLastMessageDate();
if(lastMsgDt.getTime() < dt.getTime()) {
break;
}
for(var j = 0; j < msgs[i].length; j++) {
var msgDate = msgs[i][j].getDate();
...
}
上記では msgs
が2次元のインデックスを持っているが、msgs[i]
は i
が小さいとスレッド中の__最終受信メールの時刻__がより新しいものとなる。
msgs[i][j]
の j
では、スレッド i
中のメッセージ j
の時刻がより古いものになる。
から、一定時間前のメッセージで走査を打ち切る場合は、i
は 0
から、j
はスレッド i
の メッセージ数 -1
からインデックスを走査する必要がある。
// リクエストトークン
var token = {
"method" : "post",
"headers" : {
"X-ChatWorkToken" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // Chatworkの認証トークン
},
"payload" : {
"body" : postMsg,
}
};
var apiUrl = "https://api.chatwork.com/v2/rooms/" + roomId + "/messages"
var response = UrlFetchApp.fetch(apiUrl, token);
参考: Class UrlFetchApp | Apps Script | Google Developers
Chatwork API はヘッダに X-ChatWorkToken
が必要で、個々の認証トークンを記述する必要がある。
こういった独自のヘッダはコードに示したように headers
内に Key Value 形式で書いたらいい。
ここまでできたら、定期実行のトリガーを仕掛ける。
GAS の編集画面のメニューから編集→現在のプロジェクトのトリガー
実行したい関数を設定(この例では run
)、「時間主導型」のトリガーにする。当然だが、スクリプトで設定した起動時間間隔に合わせること。
課題・未確認事項
エラー処理は特にしてない。スクリプトの実行時間と起動間隔のå ¼ね合いで、スクリプト実行中に受信したメールは通知されないかも知れない。
ほか
もっとトリガーの種類ほしい。GASつよい。