はじめに
この記事ではGmailの内容をGASを使ってSlackに通知してみます。
作るもの
今回の想定はチームで一つのGoogleグループのメーリングリストを持っている場合に
受信したメールをSlack通知したい。
さらに、送信元ごとにSlackチャンネルを分けたい!というのをGASで実装します。
この記事で話さないこと
- GASのGmail操作の詳細な説明
事前準備
Slackアプリの設定&トークンの取得
以下の記事がとてもわかりやすくまとめてくださっています。
取得したトークンをスクリプトプロパティに保存
SLACK_TOKEN
という名前でSlackのトークンを保存します。
GAS作成
参考にさせていただいた記事
完成したコード
// 送信元アドレスと、受信したら通知したいSlackのチャンネルIDを書く
const CHANNEL_LIST = {
'送信元メールアドレス': {
'channel': '通知先SlackチャンネルID',
'icon_emoji': ':email:'
},
}
function main(){
const results = search();
if(results){
for(const result of results){
const channelInfo = CHANNEL_LIST[result.from];
console.log(channelInfo)
sendToSlack(result.body, channelInfo.channel, channelInfo.icon_emoji || ':email:' );
}
}else{
// 該当のメールが存在しない場合はコンソールログを出力
console.log('There are not messages.');
}
}
function sendToSlack(text, channel, icon_emoji) {
const SLACK_TOKEN = PropertiesService.getScriptProperties().getProperty('SLACK_TOKEN');
console.log(SLACK_TOKEN)
const url = "https://slack.com/api/chat.postMessage";
const payload = {
"token" : SLACK_TOKEN,
"channel" : channel,
"username": "メール通知",
"icon_emoji": icon_emoji,
"text" : text,
};
const params = {
"method" : "post",
"payload" : payload
};
const result = UrlFetchApp.fetch(url, params);
console.log(result)
}
function search() {
const now = new Date();
// 10分前(Unixタイム): Gmailでの時分秒単位での検索はUnixタイムにする必要あり
const tenMinBeforeUnix = parseInt((now.getTime() - 10 * 60 * 1000)/1000);
const senders = Object.keys(CHANNEL_LIST).map(sender => `from:${sender}`).join(' OR ')
const query = `after:${tenMinBeforeUnix} AND (${senders})`;
console.log(query)
const threads = GmailApp.search(query);
let results = [];
for(const thread of threads){
const threadId = thread.getId();
const subject = thread.getFirstMessageSubject();
const messages = thread.getMessages();
for(const message of messages) {
const sender = message.getFrom();
const receivedDate = Utilities.formatDate(message.getDate(), "JST", "yyyy/MM/dd HH:mm:ss");
const baseUrl = 'https://mail.google.com/mail/u/0/#inbox';
const mailUrl = `${baseUrl}/${threadId}`;
results.push(
{
from: sender.match(/([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*)/)[0],
body: `受信日時:${receivedDate}\n送信者:${sender}\n件名:${subject}\nメールURL:${mailUrl}\n本文:\`\`\`${message.getPlainBody()}\`\`\``
}
)
}
}
return results;
}
通知対象を設定
channel
に送信元メールアドレス。icon_emoji
にSlack通知時のbotのアイコンを設定してください。
// 送信元アドレスと、受信したら通知したいSlackのチャンネルIDを書く
const CHANNEL_LIST = {
'送信元メールアドレス': {
'channel': '通知先SlackチャンネルID',
'icon_emoji': ':email:'
},
}
実行する
手動でmainを実行します。
Slackにメールが通知されました。
スケジュール登録
トリガーを10分ごとに設定すれば
定期的にメールをチェックしてSlack通知されます。
細かい実装について
Gmailのフィルター
CHANNEL_LIST
のKEYを送信元アドレスにしており、senders
で送信元アドレスをフィルタリングするための文字列を作成しています。
以下が作成される文字列です。
CHANNEL_LIST
のメールアドレスが増えるとfrom: 送信元メールアドレス OR from: 送信元メールアドレス
と増えてきいきます。
after:1703335800 AND (from: 送信元メールアドレス)
const CHANNEL_LIST = {
'送信元メールアドレス': {
'channel': '通知先SlackチャンネルID',
'icon_emoji': ':email:'
},
}
const tenMinBeforeUnix = parseInt((now.getTime() - 10 * 60 * 1000)/1000);
const senders = Object.keys(CHANNEL_LIST).map(sender => `from:${sender}`).join(' OR ')
const query = `after:${tenMinBeforeUnix} AND (${senders})`;
Slack通知先仕分け
取得したメールを送信元と本文ごとに配列挿入。
getFrom()
はメールアドレスが取得されるわけではなく 名前(メールアドレス)
のようにメールのFromに入ってくるテキストが返ってきます。
後で、CHANNEL_LIST
との照合に使いたいのでメールアドレス部分だけ抽出するようにします。
from: sender.match(/([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*)/)[0],
let results = [];
for(const thread of threads){
const threadId = thread.getId();
const subject = thread.getFirstMessageSubject();
const messages = thread.getMessages();
for(const message of messages) {
const sender = message.getFrom();
const receivedDate = Utilities.formatDate(message.getDate(), "JST", "yyyy/MM/dd HH:mm:ss");
const baseUrl = 'https://mail.google.com/mail/u/0/#inbox';
const mailUrl = `${baseUrl}/${threadId}`;
+ results.push(
+ {
+ from: sender.match(/([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*)/)[0],
+ body: `受信日時:${receivedDate}\n送信者:${sender}\n件名:${subject}\nメールURL:${mailUrl}\n本文:\`\`\`${message.getPlainBody()}\`\`\``
+ }
)
}
result.from
には正規表現で抽出した送信元が入っているので、送信元メールアドレスの
通知先SlackチャンネルIDを取得し、Slackのchat.postMessage
のchannelをチャンネルIDをメールごとに切り替えることで通知先を仕分けてます。
const CHANNEL_LIST = {
'送信元メールアドレス': {
'channel': '通知先SlackチャンネルID',
'icon_emoji': ':email:'
},
}
function main(){
const results = search();
if(results){
for(const result of results){
const channelInfo = CHANNEL_LIST[result.from];
console.log(channelInfo)
sendToSlack(result.body, channelInfo.channel, channelInfo.icon_emoji || ':email:' );
}
}else{
// 該当のメールが存在しない場合はコンソールログを出力
console.log('There are not messages.');
}
}
最後に
GASはGgoole Workspace周りのことは基本なんでもできるので楽しいですよね。
今回は受信したメールの送信元ごとにチャンネルを分けてSlackに通知してみました。
ぜひ、システム系メールをまとめて一個のアドレスで受け取っているみたいな場合にお試しください。