mike-kilcoyne-G1y7tcQxG34-unsplash

Gmailのスター付きメールからTodoistのタスクを作成&Slackに通知する その1 – isStarred()メソッドを使って、未処理のスター付きメールのみを絞り込む

freeeに関係ない話題ですが、Google Apps Script(以下GAS)でできる効率化の例として番外編としてfreee API以外のGASでの活用に関しても記事にしています。

今回は、「Gmailでスターを付けたメールからTodoistのタスクを作成し、メールの受信をSlackに通知する」に挑戦したいと思います。

Gmailで条件に合致するメールに自動でスターを付ける

今回のスクリプトはスター付きメールを検索してスクリプトが実行されるようになっています。

まずスターの付け方ですが、Gmailの操作画面やアプリから手動で付けることができます。

スターを手動で付ける

また受信メールのフィルタ機能を利用して、条件設定をした上で自動でスターを付けることもできます。

ここでも活躍するのがGmailの検索演算子です。検索演算子によるメールの絞り込みは以下の記事でも紹介しています。

受信メールからスター付きメールを絞り込む

GASで処理できるように、対象となるGmailMessageオブジェクトを取得したいです。

GAS x freeeAPIライブラリのトリセツ「定期的に届くメールからfreeeの取引を作成しよう!」その1 – 対象メールの絞り込み

の記事で紹介したGmailSearchクラスを使用します。

/**
 * class GmailSearch
 * Gmailで検索条件を指定してマッチするメッセージを取得・操作するクラス
 * 
 * プロパティ
 * query - 検索条件
 * threads - 検索結果の各スレッドを格納した配列
 * threadMessages - 検索結果の各メッセージをスレッドごとに二次元配列に格納した配列
 * allMessages - 検索結果の全メールを一次元配列に格納した配列
 * lastThreadMessages - 検索結果の最新のスレッドの各メールを一次元配列に格納した配列
 * firstMessages - 検索結果の各スレッドの最初のメールを一次元配列に格納した配列
 * 
 */

/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

class GmailSearch {

  /**
   * 検索条件から条件にマッチするメッセージを取得するコンストラクタ
   * @constructor
   * @param {string}  query - 検索条件
   */

  constructor(query) {
    this.query = query;
    this.threads = GmailApp.search(this.query);
    this.threadMessages = GmailApp.getMessagesForThreads(this.threads);
    this.allMessages = this.threadMessages.flat();
    this.lastThreadMessages = this.threadMessages[0];
    this.firstMessages = this.threadMessages.map(thread => thread[0]);
  }
}

今回絞り込みたいメールの条件は…

  • スター付き(スレッド内の他のメールは不要)
  • 1日以内に受信

となります。ここで、Gmailの検索演算子のis:starredだとスター付きのメールが含まれるスレッド内のすべてのメールが取得されてしまいます。

このあたりは(少しコードが古い書き方ですが)いつも隣にITのお仕事の以下の記事が参考になります。

いつも隣にITのお仕事|【GAS】Gmailのメッセージにスターがついているか判定する方法とスターを付与する方法

本記事のアプローチも基本的には同じで、Class GmailMessageisStarred()メソッドを使って、さらに絞り込みを行っています。

以下のスクリプトではテストとしてGmailの検索演算子の受信日時を30日以内にしてスレッド内の返信メールにスターが付いているものを含めるようにしました。30日以内に該当のケースがない場合は、適宜このnewer_than:30dの部分を調整してください。

function findStarredMails() {
  const query = 'is:starred  newer_than:30d '; // TEST:30日以内に受信したスター付きのメール

  // 検索演算子の条件に該当するメールが含まれるスレッドのすべてのメールを取得
  const aryAllMessages = new GmailSearch(query).allMessages;
  aryAllMessages.forEach(message => console.log(message.getDate(), message.getSubject(), message.getFrom())); // スター付きでないものも含まれる

  // isStarred()メソッドでスター付きのメールのみに絞り込み
  const aryStarredMessages = aryAllMessages.filter(message => message.isStarred());
  aryStarredMessages.forEach(message => console.log(message.getDate(), message.getSubject(), message.getFrom()));

}

これで、スター付きのメッセージのみを抜粋できました。

前回のスクリプト実行以降に新たに受信したメールのみを処理したい

最終的にこのスクリプトは、通知したい間隔にあわせてトリガー実行を想定しています。この場合、newer_than:1dの1日(24時間)以内の受信メールだと15分間隔のトリガーなどでは取得されるメッセージが重複してしまいます。

そのため、前回のスクリプト実行以降に新たに受信したメールのみにフィルタリングして、タスク化などの処理を行います。

前回のスクリプト実行から今回の実行までの期間を指定する方法は、以下の記事にて紹介しています。

この記事の手法にのっとって、最後に処理したメールの受信日時をプロパティストアに格納し、そこから起算日となるDateオブジェクトを作成して、絞り込みに利用しています。

function findNewStarredMails() {

  // Gmailの検索演算子:1日以内に受信したスター付きのメール
  const query = 'is:starred  newer_than:1d ';
  
  // 検索演算子の条件に該当するメールが含まれるスレッドのすべてのメールを取得
  const aryAllMessages = new GmailSearch(query).allMessages;
  
  // 取得すべきメッセージがなければ処理を中止
  if (aryAllMessages.length === 0) { return };

  // isStarred()メソッドでスター付きのメールのみに絞り込み
  const aryStarredMessages = aryAllMessages.filter(message => message.isStarred());

  // プロパティストアからメール絞り込みの起算日時を取得
  const dateLastMail = new Date(PropertiesService.getScriptProperties().getProperty('LAST_DATE'));
  
  // 起算日時以降のメールのみに絞り込み
  const aryNewMessage = aryStarredMessages.filter(message => message.getDate() > dateLastMail);

  // 取得すべきメッセージがなければ処理を中止
  if (aryNewMessage.length === 0) { return };

  // GmailMessageクラスのメソッドを利用してメールから必要な情報を取得してTodoistとSlackに通知
  aryNewMessage.forEach(messageNew => console.log(messageNew.getFrom() + '|このログ出力部分にチャットツールに通知する処理を書く'));

  // 起算日時以降のメールを日付で降順に並び替え
  aryNewMessage.sort((a, b) => b.getDate() - a.getDate());

  // 最新のメールから受信日時を取得してプロパティストアに次回の起算日時として保存
  const messageLast = aryNewMessage[0];
  const dateLast = messageLast.getDate();
  PropertiesService.getScriptProperties().setProperty('LAST_DATE', dateLast);

}

これで、最新(スクリプト未処理)のスター付きメールのGmailMessageオブジェクトのみを絞り込めました。

おわりに

今回は、「isStarred()メソッドを使って、スクリプト未処理のスター付きメールのみを絞り込みする」までを紹介しました。

こうした配列からの要素の抜粋には、Arrayオブジェクトに対して使用できるfilter() メソッドが活躍します。ぜひこの機会にfilter() メソッドと仲良くなってみてください。

シリーズ目次

  1. Gmailのスター付きメールからTodoistのタスクを作成&Slackに通知する その1 – isStarred()メソッドを使って、未処理のスター付きメールのみを絞り込む
  2. Gmailのスター付きメールからTodoistのタスクを作成&Slackに通知する その2 – Todoist APIの認証を通す
  3. Gmailのスター付きメールからTodoistのタスクを作成&Slackに通知する その3 – Todoist APIでタスクを新たに作成する
  4. Gmailのスター付きメールからTodoistのタスクを作成&Slackに通知する その4 – Incoming Webhooksを使ってSlackに通知

Google Apps Scriptを勉強したい方へ

この記事を見て、GASを勉強したいなと思われた方はぜひノンプログラマーのためのスキルアップ研究会(通称 ノンプロ研)にご参加ください。私も未経験からこの学習コミュニティに参加し、講座を受講したことでGASが書けるようになりました。

学習コミュニティ「ノンプログラマーのためのスキルアップ研究会」

挫折しがちなプログラミングの学習も、コミュニティの力で継続できます。ノンプロ研でお待ちしております!

タグ: , , ,
Share on:
Previous Post
airfocus-v89zhr0iBFY-unsplash
GAS活用法

Gmailのスター付きメールからTodoistのタスクを作成&Slackに通知する その2 – Todoist APIの認証を通す

Next Post
カレンダー
GAS活用法

タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その4 – タイムエントリからカレンダーの予定を作成する