dカードプリペイドの残高が指定額以下で通知する

GASを使ってdカードプリペイドの残高が一定額を下回ったらメールで通知するようにしてみた。最新の残高もスプレッドシートに表示される。
やりたい人がいるかもしれないので簡単にやり方とスクリプトを書いておく。

Gmailの準備

まずは"【dカードプリペイド】ご利用のお知らせ"をGmailで受け取り、メールに特定のラベルが付くようにフィルタを作成する。ここでは"dカード"という名前のラベルにしている
メール通知がうっとうしい場合、ラベル通知でこのラベルの場合のみ通知しないように設定しておくのが良い。

スプレッドシートの準備

スプレッドシートシートを作成する。
スプレッドシートスクリーンショットを貼っておくが、必要なのは"残高""更新日時""通知"の3つの値。
重要なのは3つの値が入るところに"名前付き範囲"を指定しておくこと。
ここでは"残高"の入るところに"balance"、更新日時に"update_time"、これ以下だと通知する残高の基準に"notify_limit"を設定している。
名前付き範囲さえ正しく設定されていれば、文字の大きさや場所は適当でよい。
f:id:yamak:20200320164037p:plain

スクリプトの準備

スプレッドシートから"スクリプトエディタ"を開いてスクリプトを作成する。"スクリプトエディタ"の基本的な使い方は自分で調べてほしい。
以下をコピペで良いが、通知送信先メールアドレスだけは自分で変更すること。

作成したらmain関数を実行して、Gmailに送信された最新の"ご利用のお知らせ"の値がスプレッドシートに反映されることを確認すること。
通知は、スプレッドシートの残高の値が通知の値以上で、かつGmailから取得した現在の残高が通知の値より少ないときに送信される。
そのため、スプレッドシートの残高の値を、実際の残高の値より多く設定し、通知の値を実際の残高 +1に設定して実行するとテストできる。

// 通知送信先メールアドレス
const MAIL_ADDRESS = 'test@example.com'

// Gmailの"ご利用のお知らせ"を振り分けるラベル
const GMAIL_DCARD_LABEL = 'dカード' 

// スプレッドシートの名前付き範囲
const SPREAD_SHEET_BALANCE_RANGE_NAME = 'balance'
const SPREAD_SHEET_UPDATE_TIME_RANGE_NAME = 'update_time'
const SPREAD_SHEET_NOTIFY_LIMIT_RANGE_NAME = 'notify_limit'


function getBalanceFromMessage(message) {
  const pattern = /\r\n<ご利用後の残高>\r\n\r\n([\d,]+)円\r\n/
  const result = pattern.exec(message)
  if (!result) return null
  return parseInt(result[1].replace(',', ''))
}

function getBalanceFromGmail() {
  const label = GmailApp.getUserLabelByName(GMAIL_DCARD_LABEL);
  const threads = label.getThreads(0, 1);
  if (threads.length == 0) return
  const messages = threads[0].getMessages()
  const body = messages[messages.length - 1].getBody()
  return getBalanceFromMessage(body)
}

function sendUnderLimitMail(balance) {
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
  const previousBalance = spreadsheet.getRangeByName(SPREAD_SHEET_BALANCE_RANGE_NAME).getValue()
  const limit = spreadsheet.getRangeByName(SPREAD_SHEET_NOTIFY_LIMIT_RANGE_NAME).getValue()
  if (previousBalance >= limit && balance < limit) {
    const subject = `dカード残高 ${balance} 円になりました`
    GmailApp.sendEmail(MAIL_ADDRESS, subject ,null)
  }
}

function updateSpreadSheet(balance) {
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
  spreadsheet.getRangeByName(SPREAD_SHEET_BALANCE_RANGE_NAME).setValue(balance)
  const now = new Date().toLocaleString({ timeZone: 'Asia/Tokyo' })
  spreadsheet.getRangeByName(SPREAD_SHEET_UPDATE_TIME_RANGE_NAME).setValue(now)
}

function main() {
  const balance = getBalanceFromGmail()
  if (!balance) return
  sendUnderLimitMail(balance)
  updateSpreadSheet(balance)
}

トリガーの準備

スクリプトエディターから"編集 - 現在のプロジェクトのトリガー"を開いてトリガーを設定する。
実行する関数をmain, イベントのソースを"時間主導型"にして、あとは好きな間隔でタイマーを設定する。
1時間おきくらいでいいかと。わかると思うがリアルタイムではない。

スプレッドシートのリンクをスマホに登録する

スプレッドシートを見れば現在の残高がわかるのだが、Googleドライブやスプレッドシートアプリは反映が遅い場合がる。
編集しないのであればブラウザからリンクを見たほうが最新状態の反映が早い。

余談

ここからは単なる余談。
元々GASを使うのではなく、メールをIFTTT等の連携ツールでWebhookで送り、FirebaseのFunctionsからFirestoreに保存することを考えていた。
実際にFirebase側をを全て作った後で連携ツールを調べたら、IFTTTはメールをトリガーにできず、ZapierとPower AutomateはWebhookが有料ということで断念。
GASを調べたら、今ではV8対応もされてかなり使いやすくなっていた。GAS凄い。