【GAS】Gmailから特定のメールを抽出してLINEで通知する

(最終更新月:2023年4月)

Google Apps Script(GAS)で、Gmailから特定のラベルをつけたメールを抽出し、LINE Notifyで通知するアプリを作りました。

以下のように、定期的(今回は30分おき)にGmailを巡回し、条件に当てはまるメールをLINEに飛ばします。

GASでGmailからメールをLINEへ飛ばす仕組み

以下のようなフローで、Gmailをメールへ飛ばしています。

こちらはイメージ画像です。

※「ボードを表示する(See the board)」で、フロー図を動かしたり、大きくしたりできるようになります。(編集権限はありません)

スクロールでズーム、右クリック長押しで上下左右に動かせます。

Gmailでやること

まずはGmail上で自動フィルタリングで以下のように設定します。

  • 特定のメールを抽出する条件を指定
  • 受信トレイをスキップ
  • ラベルを付ける

設定からフィルタの作成へ

フィルタリングの条件を指定

受信トレイをスキップ&ラベル付け

受信トレイのスキップは絶対条件ではありません。

ただしGASのコードが未読のみ抽出するものになっているため、受信トレイにあると意図せず既読になってしまうことも考えられたため、流れで既読にならないようにしています。

LINE Notifyでの設定

LINE Notifyは無料で使える自身のラインやグループに通知を送るためのツール。

自身のLINEアカウントでログインし、通知を送りたい先を選択し、トークンを発行する必要があります。

GAS(Google Apps Script)のコードや設定

Google Apps Scriptでは、役割ごとにファイルを分け、修正をしやすくしています。

GASでは、ファイル分割した場合でも、インポートは不要。

ひとつのファイルに記述しているように関数を呼び出せます。

コード以外にも、LINE Notifyのトークンをスクリプトプロパティに記述し、トリガーの設定が必要です。

  • gmailScraping.gs:Gmailから必要なメールを取り出す
  • LineNotify.gs:LINEへ通知したい内容を飛ばす
  • main.gs:トリガーと紐付けるメインとなるファイル

gmailScraping.gs:Gmailから必要なメールを取り出す

主にやることは以下のとおり。

  • フィルタリングで指定したラベルを指定すること
  • gmailScraperで、ラベルが一致&未読(必要な場合は文字列)であるメールを返す
  • markingReadは、最後に使用し、未読を既読にする関数
//Gメールから特定のメールを抜き出し、[{'title':タイトル, 'body':内容}]

//ラベル名
mylabel = 'ここにフィルタリングで指定したラベル名を入れる';

//取り出してMapオブジェクトの入ったArrayをリターン
function gmailScraper(conditionStr=null) { //conditionStrは、未読以外にも条件をつけたい場合に文字列を入れる。
  //特定のラベルがついたもののみ抽出
  var label = GmailApp.getUserLabelByName(mylabel);
  var labeledThreads = label.getThreads();

  //抽出したものをArrayに入れる
  var msgObjArr = [];

  for (var i = 0; i < labeledThreads.length; i++) {
    //これはメッセージのオブジェクト
    var messages = labeledThreads[i].getMessages();
  //メッセージのオブジェクトからタイトルなどを取り出すには以下が必要
    for (var j = 0; j < messages.length; j++) {
      var message = messages[j];
   //タイトルの取り出し
      var subject = message.getSubject();
   //中身の取り出し
      var body = message.getPlainBody();
   //map化の処理
      const m = new Map();
      m.set('title', subject);
      m.set('body', body);

      //未読はすべてで、抽出したい文字列はない
      if (conditionStr==null){  
        //未読はすべて
        if (message.isUnread()) {
          msgObjArr.push(m);
        }
      //抽出したい文字列がある
      } else {
        //未読&指定した文字列がタイトルに含まれているもの
        if (message.isUnread()&& message.getSubject().includes(conditionStr)) { 
          msgObjArr.push(m);
        }
      }
    }
  }

  return msgObjArr
}

//最後に既読をつけるための記述
function markingRead(){
  var label = GmailApp.getUserLabelByName(mylabel);
  var labeledThreads = label.getThreads();

  for (var i = 0; i < labeledThreads.length; i++) {
    var messages = labeledThreads[i].getMessages();
    for (var j = 0; j < messages.length; j++) {
      var message = messages[j];
      message.markRead()
    }
  }
}

LineNotify.gs:LINEへ通知したい内容を飛ばす

こちらでは、LINE Notifyへ通知したい内容を飛ばします。

必要なことは以下のとおり。

  • スクリプトプロパティからキーを取り出す
  • 飛ばしたいメッセージを正しい形式のペイロードに変える
  • リクエストを飛ばす
const apiKey = ScriptProperties.getProperty('API_KEY'); //スクリプトプロパティのキー
const ep = "https://notify-api.line.me/api/notify";

//メッセージの送信
function lineTo(msg) {
  const payload = {"message": msg}
  const options = {
          "method": "post",
          "headers": {
            'Authorization': 'Bearer ' + apiKey,
          },
          "payload": payload
  }
  var response = UrlFetchApp.fetch(ep, options);
  var json = response.getContentText();
  var data = JSON.parse(json);
}

main.gs:トリガーと紐付けるメインとなるファイル

メインの関数で、LINEで通知するメッセージは以下の2種類。

  1. 最初に合計で何個のメールが見つかったかとその時刻
  2. 実際に見つかったメール
function main() {
  //未読すべて抽出する場合は、引数は不要。
  const unreadObj = gmailScraper();

  if (mapObj.length > 0) {
  //時刻を文字列に変換する
    const timeStr =getDateTimeString();
  //メッセージが何件あるかの文章を作る
    const feedbackComment = `${timeStr}XXからのメールが${mapObj.length}件見つかりました。`

  //メッセージが何件あるかの宣言を、最初にLINEで飛ばす
    lineTo(feedbackComment);

    for (var i=0; i<mapObj.length;i++){
      const msgObj = mapObj[i];
      const sentence = `タイトル:${msgObj.get('title')}、内容:${msgObj.get('body')}`;
      //抽出したメールをひとつずつ送る
      lineTo(sentence);
    }

  //すべての処理がおわったらmarkRead()
  markingRead()

}

//今の時刻を文字列に変える
function getDateTimeString() {
  var now = new Date();
  var month = now.getMonth() + 1; // getMonth()は0から始まるため+1する
  var day = now.getDate();
  var hour = now.getHours();
  var minute = now.getMinutes();
  var dateTimeString = `【${month}月${day}日${hour}時${minute}分取得情報】`;
  return dateTimeString;
}

スクリプトプロパティの設定方法

スクリプトプロパティの設定方法がわからない方は、以下の画像で場所を確認してください。

※キーは任意のものでOKです。

トリガーの設定

トリガーで以下のように時間設定にしましょう。

実行の権限を付与

一度実行をして権限を付与しておきましょう。

※今回のコードではスプレッドシートの権限ではなく、外部へのアクセス権限を許可することになります。

当システムの弱点

当システムにも弱点はあります。

なぜなら私自身の用途に合わせて作っているからです。

こちらを参考に仕組みを作るなら以下の点を考慮して、必要に応じて改善案を盛り込まなければなりません。

  • リアルタイムで通知されない(こちらでは30分ごと)
  • 誰かが読んで既読が付くと、LINEに飛ばない
  • たくさんメールがあると、メール本体がどこにあるのかが見つけにくい

お使いの用途に合わせて、コードは工夫しましょう。

私が別で使用している例として、毎朝前日のメールを一覧でリマインドするようにしているものもあります。

リマインドだけなら、内容まで通知せずとも、タイトルだけで良い可能性もありますね!

まとめ:GASで特定のGmailをLINEへ通知する方法

Gmailも数が増えてくると管理が大変です。

ラベリングなどで少しでも見やすくするものの、それでも見落としてしまうことがあります。

とくに大事なものだけでも、LINEなど身近なアプリに飛ばせるようにすると見落としが減らせるでしょう。

一日に一回、当日に来たメールの振り返りなどでも良いと思います。

上手く活用してください。