前回の内容について、具体的に説明します。
まず、スクリプトを作成します。GSuite Developer Hubを開き、新しくプロジェクトを作成します。
https://script.google.com/home
左にある「新規スクリプト」をクリックすると空のスクリプトファイル「コード.gs」が1つある「無題のプロジェクト」が開きますので、とりあえずは下記のプログラムをコピーし、貼り付けてください。
(なお、このプログラムは、JavaScriptをまともに書いたことがない人間が作成したものですので、変なところがあるはずです。改善案や問題点があれば、ぜひコメントをお寄せください!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
// Slackで得た送信用URL var postUrl = "https://hooks.slack.com/services/XXXXXXXX/XXXXXXXX/XXXXXXXXXXXXXXXX"; // メイン処理 (トリガーで定期的に呼ばれる) function gmailToSlack() { // Gmailのメールボックスの検索条件 (未読のメール・1時間以内のメール) var threads = GmailApp.search("is:unread newer_than:1h"); // 条件を満たすスレッドの数を確認 なければ終了 var count = threads.length; if (count == 0) return; // 定義ファイルの取得 var mailDataDefinitions = getDefinitionFileFromGoogleDrive(); if (mailDataDefinitions == null) return; for (var i = 0; i < count; i++) { var thread = threads[i]; // スレッド内の最後のメールが処理対象 var numberOfMessageInThread = thread.getMessages().length; var targetMessage = thread.getMessages()[numberOfMessageInThread - 1]; var mailSubject = targetMessage.getSubject(); // メールの題名から、メール定義情報を探す var jsonMailData = findMailData(mailDataDefinitions, mailSubject); if (jsonMailData == null) continue; // Slackに送信する内容は、「メールタイトル + 条件に従って抽出した本文」 とする var mailBody = mailSubject + "\n" + extractMailBody(targetMessage.getPlainBody(), jsonMailData); postToSlack(jsonMailData, mailBody); // Slackに送信した後、既読にして捨てる thread.markRead(); thread.moveToTrash(); } } // GoogleDriveにあるメール定義のファイルを取得し、JSON形式のデータを返す function getDefinitionFileFromGoogleDrive() { // 定義ファイルがあるかどうかを確認 var files = DriveApp.getFilesByName("MailData.json"); if (files == null) return null; // 定義ファイルの内容を読み込み、JSONとして解釈して返す var file = files.next(); var data = file.getBlob().getDataAsString(); return JSON.parse(data); } // メールのタイトルから、メール定義を探す function findMailData(mailDataDefinitions, mailSubject) { var result = null; mailDataDefinitions.forEach(function (value) { if (mailSubject.indexOf(value.title) != -1) result = value; }); return result; } // 本文の指定された範囲を抽出する function extractMailBody(mailBody, jsonMailData) { var foundStartLine = false; var foundEndLine = false; var splitMailBody = mailBody.split('\n'); var exractedMailBody = ""; // 開始文字列が空文字列の場合には、先頭からすべてを対象とする if (jsonMailData.fromText == "") foundStartLine = true; splitMailBody.forEach(function (line) { // 終了文字列以降はすべて無視する if (foundEndLine) return; // 開始文字列をまだ見つけていない場合には、開始文字列かどうかの判定 if (foundStartLine == false) { if (line.indexOf(jsonMailData.fromText) != -1) { foundStartLine = true; } return; } // 終了文字列を含むかどうかの判定 if (line.indexOf(jsonMailData.toText) != -1) { foundEndLine = true; return; } // 抽出対象の本文に追加 exractedMailBody += line + "\n"; }); return exractedMailBody; } // Slackに送信する function postToSlack(jsonMailData, message) { // Slackで定義されているデータを作成 var jsonData = { "channel": jsonMailData.channel, "username": jsonMailData.username, "text": message }; var payload = JSON.stringify(jsonData); // 送信用データの作成 var options = { "method": "post", "contentType": "application/json", "payload": payload }; // Slackに送信 UrlFetchApp.fetch(postUrl, options); // 荷物お届けの場合のみ、LINEに送信 if (jsonMailData.channel == "荷物お届け") { //後日、別記事で公開するかも... } } |
なお、上記のスクリプトは、以下のページのスクリプトをベースに作成しました。この場をお借りしてお礼申し上げます。
https://github.com/comefigo/gmail-to-slack/blob/master/Main.gs
このスクリプトの先頭行の内容は、Slackのアプリの「Incoming Webhook」で取得しなければなりません。Slackの設定画面を開き、アプリの「Incoming Webhook」をインストールしてください。設定画面の「インテグレーションの設定」にある「Webhook URL」から取得できますので、そのまま貼り付けてください。
(このURLを、自分自身以外が知ることがないようにしてください。)
入力後に、保存して下さい。今回は、プロジェクト名を「GmailToSlack」としてあります。
次に、Slackに飛ばすメールの情報を定義した、JSONファイルを作成します。メモ帳などのテキストエディタを起動し、下記の内容を貼り付けてください。(中身については別途説明します。)
1 2 3 4 5 6 7 8 9 |
[ { "username" : "テスト", "channel" : "#general", "title" : "テストサンプル", "fromText" : "", "toText" : "dummy" } ] |
このファイル名を「MailData.json」として保存後、Google Driveを開き、このファイルを配置してください。配置する場所はどこでもかまいません。以下のURLからGoogle Driveに入り、Webブラウザにファイルをドラッグ&ドロップして配置できます。
https://drive.google.com/drive/my-drive
これで最低限の準備が完了しました。動作確認のためのメールが必要となるので、Gmailで自分自身宛のメールを作成し、タイトルを「テストサンプル」とし、適当に本文を記入して送信してください。すぐに自分自身が受信しますが、開封(既読)にしないでください。
再度、Google Apps Scriptに戻り、上部のメニューから「実行」→「関数を実行」→「gmailToSlack」を実行してください。スクリプトからGmailアカウントおよびGoogle Driveのファイルを参照するために、権限を付与することが必要です。「アカウントの選択」画面が表示されるので利用しているGmailのアカウント選択します。「このアプリは確認されていません」の画面が表示されるはずですが今回は自分が作ったものなので、画面下の「詳細」をクリックし、「GmailToSlack(安全ではないページ)に移動」を選択してください。
すべてがうまくいっていれば、Slackに投稿され、メール自体は既読になりゴミ箱に移動します。Slack側でログを保存する前提ですが、そうでなければメールをアーカイブしてもよいと思います。
1 2 3 |
// Slackに送信した後、既読・アーカイブを行う thread.markRead(); thread.moveToArchive(); |
なお、下記のページにあるように、メールの取得数制限(1日2万通以内)やスクリプトの動作時間制限(1日90分以内)があります。
https://developers.google.com/apps-script/guides/services/quotas
2万通というとそんなにメールは来ない、と思うかもしれませんが、これはあくまでも1日の処理数です。例えば、1分に1回スクリプトを動作するように設定し、処理対象外のメールが受信トレイに50通残っているとすると、1分ごとに50通のメールを取得して判定し、1日では50通x60分x24時間=72000通、ということで制限を超えてしまいます。
この制限に引っかからないようにすることと、処理時間を短くするために、Gmail側のフィルタで直近1時間以内のメールのみを取得するようにしました。
明日は、定義ファイルの具体的な内容と、トリガーとして定期的に実行する方法を投稿します。
2019/7/23追記
その後、運用する中でJavaScriptの内容を改善していたので、サンプルを差し替えました。
(今は、「荷物お届け」の場合のみ、妻のLINEにも通知する機能も増えています)
はじめまして。
こちらを参考に挑戦しましたが、
SyntaxError: Unexpected token: %
となり処理出来ません。調べてみたものの全く解らずです。アドバイスお願いできませんか??
コメントありがとうございました。
が、すいません、いただいたエラーの内容からは、何が原因か推測できません。
もし、JavaScriptのコード内に「%」の文字があるか、コメント化されていない日本語文字(行の先頭に//がない)があれば、それが原因と思います。
また、JSONの定義ファイル側に問題があるか、文字コードが不適切などで発生する可能性もありそうな気がするので、MailData.jsonファイルをいったん削除して実行してみると、どうでしょうか?
これでエラーが消えるようであれば、MailData.jsonファイルの中身に問題がある可能性があり、エラーが消えないならばJavaScript側に問題がありそうです。
追伸:
この記事のコードは、その後運用を経て改良しています。後ほど内容を更新します!