Webサービスなどで利用料のお知らせがメールで来るものがあります。支払いをクレジットカードで登録していれば、カードの明細を同期させて、取引を自動登録することができます。
ただ、同じカードで複数の部門の支払いを登録していて後から部門を付与したり、同期で明細が登録されるのが遅く早く月次を締めたい!みたいな場合には、事前に未決済取引を登録しておく必要があります。
利用料お知らせメールが定期・定型であることが前提になりますが、このお知らせメールを起点にfreeeに取引を自動登録できないかに挑戦します。
GmailAppクラスで対象メールを絞り込もう
GASでのGmailの操作は、GmailAppクラスを使用します。まずはリファレンスを確認しましょう。
https://developers.google.com/apps-script/reference/gmail/gmail-app
今回は、まずGmailApp.search(query)
メソッドを使って検索条件に合致するスレッドを取得して、対象のメールを絞り込み、その本文や受信日時などを取得していきます。
GASを使ってGmailを操作する場合は、Gmail特有のスレッドの概念の理解が重要になります。詳細は詳解! Google Apps Script完全入門 [第3版](以降GAS本)で丁寧に解説されているので、ぜひこちらでご確認ください。
Gmailの検索演算子
もう一つ、Gmail操作に欠かせない知識が、検索演算子です。
GmailApp.search(query)
メソッドでターゲットとなるスレッドを絞り込む際に活躍します。
検索演算子については以下の記事も参考になります。
いつも隣にITのお仕事|GASでGmailの受信トレイに溜まった今日から指定の日数以前のスレッドをアーカイブする方法
いつも隣にITのお仕事|GASでGmailの受信トレイに溜まった指定の日付以前のスレッドを自動でアーカイブする方法
検索対象のメールの条件を整理する
今回の検索対象のメールは
- 月に1度だけ15日前後に来る
- 件名は固定
- 複数部門で個別に申し込みをして利用
- 部門ごとに宛先のメールアドレスが異なり、それぞれにメールが来る
という条件で進めます。
この部分の設計ゴールとしては、「毎月20日ごろに過去1ヶ月以内のメールから対象の件名のメールを全て配列で取得」となります。
検索演算子 subject:とnewer_than:
まず検索演算子を使って件名で絞り込みます。
今回は件名が【XXサービス】決済完了メール(自動配信)なので
subject:(【XXサービス】決済完了メール(自動配信))
としました。
続いて1ヶ月以内のメールのみを検索対象にしたいので
newer_than:1m
を追加します。
newer_thanは、日(d)、月(m)、年(y)を指定し、その時期より新しいメールを検索するもので、時期より古いメールを検索するolder_thanもあります。
例えば、
1週間に1回のトリガーで、1週間分の該当するスレッド群を取得する場合
newer_than:7d(7日前から現在まで)
1日1回のトリガーで24時間以内の該当するスレッド群を取得する場合
newer_than:1d(24時間前から現在まで)
となります。
実際に意図したメールを検索で絞り込めているか、確認のためにGmailの検索ボックスに入力して確かめてみます。
GmailApp.search(query)メソッドで検索条件にマッチするスレッドを取得
GmailApp.search(query)
メソッドは引数にqueryつまり検索条件を指定します。戻り値は検索条件にマッチしたいくつかのスレッド(一連のメールのあつまり)が、配列で取得できます。
[スレッド1, スレッド2, スレッド3 … ]
のようなイメージですね。
今回の前提(月に1度だけ15日前後に来る・部門ごとに宛先のメールアドレスが異なり、それぞれにメールが来る)ですと、同日に複数の部門宛の決済完了メールが受信され、それらは同一の件名のため1つのスレッドにまとまっています。検索期間の設定に誤りがなければスレッドとしては1つだけ取得できているのが正解となります。
GmailApp.getMessagesForThreads(threads) メソッドでスレッド内のメールを取得
GmailApp.search(query)
メソッドは、GmailThreadオブジェクトを一次元配列で取得します。このままだとスレッド内にある個別のメール(GmailAppクラスではMessageオブジェクト)を確認できませんので、GmailApp.getMessagesForThreads(threads)
メソッドで、各スレッドのメッセージを格納した二次元配列を取得します。
[
[スレッド1のメール1, スレッド1のメール2],
[スレッド2のメール1],
[スレッド3のメール1, スレッド3のメール2, スレッド3のメール3],
…]
このようなイメージですね。
今回はスレッド1 = 最新のスレッドのみが存在するはずですから、その最新スレッド内の各メールの件名を確認のためにログ出力してみます。
function searchLastThreadMessages() {
const query = 'subject:(【XXサービス】決済完了メール(自動配信)) newer_than:1m';
const threads = GmailApp.search(query);
const threadMessages = GmailApp.getMessagesForThreads(threads);
const lastThreadMessages = threadMessages[0]; // 最新のスレッド内のメッセージを格納した配列
for (const message of lastThreadMessages) {
console.log(message.getSubject());
}
}
Gmailの検索クエリでの絞り込みをクラス化する
上記のように検索条件でスレッドやメッセージを絞り込む作業は、よく使いそう…ということで、よく使う機能はクラス化しています。
/**
* 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]);
}
}
こうしてクラスを準備しておくと
function demoSearchLastThreadMessages() {
const query = 'subject:(【XXサービス】決済完了メール(自動配信)) newer_than:1m';
const lastThreadMessages = new GmailSearch(query).lastThreadMessages;
for (const message of lastThreadMessages) {
console.log(message.getSubject());
}
}
同じように最新スレッド内の各メールの件名をログ出力するスクリプトもスッキリ書けます。
続く…
シリーズ目次
- GAS x freeeAPIライブラリのトリセツ「定期的に届くメールからfreeeの取引を作成しよう!」その1 – 対象メールの絞り込み
- GAS x freeeAPIライブラリのトリセツ「定期的に届くメールからfreeeの取引を作成しよう!」その2 – POST用の情報を抜粋する
- GAS x freeeAPIライブラリのトリセツ「定期的に届くメールからfreeeの取引を作成しよう!」その3 – 雛形オブジェクトをGETしよう
- GAS x freeeAPIライブラリのトリセツ「定期的に届くメールからfreeeの取引を作成しよう!」その4 – 雛形上書きしてPOSTしよう
Amazon欲しい物リスト公開しています。
開発者のモチベーションアップのためにAmazon欲しい物リストを公開しております。役に立ったよ!という方の感謝の気持ちで何かいただけるのであれば嬉しいです笑