3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Ateam LifeDesignAdvent Calendar 2023

Day 7

Gmailで受信した内容をSlackに通知する

Last updated at Posted at 2023-12-23

はじめに

この記事ではGmailの内容をGASを使ってSlackに通知してみます。

作るもの

今回の想定はチームで一つのGoogleグループのメーリングリストを持っている場合に
受信したメールをSlack通知したい。
さらに、送信元ごとにSlackチャンネルを分けたい!というのをGASで実装します。

無題の図形描画 (6).png

この記事で話さないこと

  • GASのGmail操作の詳細な説明

事前準備

Slackアプリの設定&トークンの取得

以下の記事がとてもわかりやすくまとめてくださっています。

取得したトークンをスクリプトプロパティに保存

SLACK_TOKENという名前でSlackのトークンを保存します。

無題のプロジェクト-プロジェクトの設定-Apps-Script (1).png

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を実行します。

無題のプロジェクト-プロジェクト編集者-Apps-Script (1).png

Slackにメールが通知されました。

スクリーンショット 2023-12-23 21.51.45.png

スケジュール登録

トリガーを10分ごとに設定すれば
定期的にメールをチェックしてSlack通知されます。

スクリーンショット 2023-12-23 22.12.24.png

細かい実装について

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],
javascript
 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に通知してみました。
ぜひ、システム系メールをまとめて一個のアドレスで受け取っているみたいな場合にお試しください。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?