Google Apps Scriptでカード決済情報をLINEに通知する

この記事は最終更新日から6年以上経過しています。
内容が古い可能性がありますのでご注意ください。

2枚持っていたクレジットカードのうち1枚をデビットカードに切り替えた。

カードを使うたびにGmailに決済情報が届くようにしたので、不正利用されたら早い段階で気づけるのはいいのだが、毎回中身を開かないと内容が確認できないのがややめんどい。直近5件ぐらいのデータを一瞬で確認したい。

あとカード会社の決済情報一覧画面が非常にアクセスしづらいうえに、見にくい。

サクッと見られるようにしたいなあとネットで色々調べてみた結果、Google Apps Scriptでなんとかできそうだったのでやってみた。

やったことはこの2つ。

  1. 決済完了メールが届いたら、メール内の金額と店名の部分をLINEに通知する
  2. 決済完了メールの内容をGoogleスプレッドシートに記録する

下準備

LINE Notifyトークンの取得

LINEに通知を送るには、LINE Notifyというコマンドラインからメッセージを送れる機能があるので、これを利用する。

Main - LINE ENGINEERING
2022-LINE-engineering-site

メッセージの送信にはトークンが必要なので、予め取得しておく。

  1. 以下のサイトにLINEのアカウントでログイン
    LINE Notify
    LINE NotifyはGitHub,IFTTT,MackerelなどのWebサービスからの通知を、LINEで受信することが出来る便利なサービスです。
  2. ログインしたら右上のユーザー名→マイページを開く。
  3. 「トークンを発行」するをクリック。
    トークン名は適当な名前にして、トークルームは「1:1」を選択して、「発行する」。
  4. トークンが表示されるので、コピペしてどこかに保存すること。忘れてしまうとトークンの発行からやり直しになる。

Gmailでラベルを付ける

取り出すメールを探しやすいように、フィルターを使って決済情報メールに自動でラベルがつくようにしておく。

Googleスプレッドシートにスクリプトを書く

GoogleDriveに新しいスプレッドシートファイルを作成して名前をつける。 次に「ツール」→「スクリプトエディタ」を開く。

試運転にとりあえずシートに「Hello World」と書き込んでみます。
以下のこのスクリプトを書いて保存したあと、実行ボタンを押す。

function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  sheet.appendRow(['hello', 'world']);
}

アクセス許可を求められるので、以下の手順で許可する。
コードを書いていくと何度かこの許可を求められるので、その都度許可してください。

  1. 「許可を確認」をクリック。
  2. 自分のアカウントを選択。
  3. 「詳細」をクリック。
  4. 一番下の「安全ではないページへ移動」をクリック。
  5. 「許可」をクリック。

実行が完了したらスプレッドシートを確認。最初の行にhello worldと書き込まれていれば成功。

LINE Notify 関数

さっきのHello Worldのスクリプトは消していいです。

メインの処理を書く前に、LINE Notifyに通知を送るための関数を作る。 Google Apps Scriptから送る場合はこんなかんじでいいみたい。

function sendLineNotify(message){
  var token = 'トークン'; // LINE Notifyに登録したときに発行されたトークンを入れる
  var options =
   {
     'method'  : 'post',
     'payload' : 'message=' + message,
     'headers' : {'Authorization' : 'Bearer '+ token}
   };
   UrlFetchApp.fetch('https://notify-api.line.me/api/notify',options);
}
Google Apps ScriptからLINE NotifyでLINEにメッセージを送る - Qiita
##LINE Notifyとは?Webサービスと連携すると、LINEが提供する公式アカウント"LINE Notify"から通知が届きます。複数のサービスと連携でき、グループでも通知を受信すること…

メールから必要なデータを取り出す関数

もうひとつ、決済完了メールの内容から必要な部分を取り出す関数も作っておく。

メールの決済情報の部分はこんなカンジの表記になっている。

お客さまの代表口座普通預金の残高や入出金明細をご確認ください。

【取引情報】
承認番号   : 999999
利用日時   : 2018/01/01 12:00:00
利用加盟店 : AMAZON CO JP
通  貨   : JPY
引落金額   : 2,000.00

※利用日時は日本標準時刻となります。

ここから必要な情報を抜き出すには、

  1. 見出しとなる単語("承認番号"とか)と「:」を含む行を探し、その行末までを取り出す
  2. 取り出した文字列から、見出し~「: 」までを削除

という処理で行けそう。

function fetchData(str, label) {
  // 正規表現による検索条件の定義:指定文字と「:」を含む行(\r)を探す
  var reg = new RegExp(label + '.*?:.*\r');
  var data = str.match(reg)[0]
    .replace(/^.*: /, '') // 取り出した文字列の先頭から「: 」までを削る
    .replace(/\r/, ''); // 行末の改行も削る
  return data;
}

Gmail行末はキャリッジリターン(/r)なので注意。

実際にデータを取り出すときは

var amount = fetchData(mailbody, '引落金額');

のように使えば良い……のだが、決済お知らせメールのラベルの表記がたまに変わる。

【取引情報】
承認番号   : 999999
利用日時   : 2018/01/02 13:00:00
利用加盟店 : AMAZON CO JP
通  貨   : JPY
金  額   : 3,000.00

金額の部分が「引落金額」だったり「金  額」だったり。 あと「通貨」の間に入ってるスペースの数も変わりそうな予感がする。

というわけでこの2つに関してはラベルにも正規表現を使って、表記の揺れに対応。

var amount   = fetchData(body, '金.*?額');
var currency = fetchData(body, '通.*?貨');

メインの処理

いよいよメインの処理。コードの説明はコメントで入れました。

function myFunction() {
  // データと書き込むシートを指定する
  // 今開いているシート(getActiveSheet())を指定
  var sheet = SpreadsheetApp.getActiveSheet();
  // Gmailから取り出すメールの検索条件を指定
  // 指定したラベルがついていて、未読のメールを取り出す
  var query = 'label:デビットカード is:unread';
  // メールを取り出す件数。ここでは10件を指定。
  var threads = GmailApp.search(query, 0, 10);
  // Gmailからのデータ取り出しを実行
  var messages = GmailApp.getMessagesForThreads(threads);
  // 取り出した各メールからデータを取り出すためのループ
  for(var i=0; i < messages.length; i++) {
    for(var j=0; j < messages[i].length; j++) {
      var mes     = messages[i][j],
          body    = mes.getPlainBody(); // メール本文をplain textで取り出す
      // 本文内に決済情報がないメールはスキップする
      if ( body.match(/承認番号.*?:/) == null) continue;
      // 作った関数でデータの取り出して変数に入れる
      var no       = fetchData(body, '承認番号'),
          date     = fetchData(body, '利用日時'),
          shop     = fetchData(body, '利用加盟店'),
          amount   = fetchData(body, '金.*?額'),
          currency = fetchData(body, '通.*?貨');
      // シートの末尾に新しい行を追加(appendRow)、そこにデータを追加する
      sheet.appendRow([date, shop, amount, no, currency]);
      // 処理が終わったメールを既読にする
      mes.markRead();
      //LINE Notify にメッセージを送る
      var lineMes = "\n" + shop + "\n" + amount;
      sendLineNotify(lineMes);
    }
  }
}

コード最終形

先に作った関数2つと合わせて、コメントを削った完全バージョン。

function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var query = 'label:デビットカード is:unread';
  var threads = GmailApp.search(query, 0, 10);
  var messages = GmailApp.getMessagesForThreads(threads);
  for(var i=0; i < messages.length; i++) {
    for(var j=0; j < messages[i].length; j++) {
      var mes     = messages[i][j],
          body    = mes.getPlainBody();
      if ( body.match(/承認番号.*?:/) == null) continue;
      var no       = fetchData(body, '承認番号'),
          date     = fetchData(body, '利用日時'),
          shop     = fetchData(body, '利用加盟店'),
          amount   = fetchData(body, '金.*?額'),
          currency = fetchData(body, '通.*?貨');
      sheet.appendRow([date, shop, amount, no, currency]);
      mes.markRead();
      var lineMes = "\n" + shop + "\n" + amount;
      sendLineNotify(lineMes);
    }
  }
}

function fetchData(str, label) {
  var reg = new RegExp(label + '.*?:.*\r');
  var data = str.match(reg)[0]
    .replace(/^.*: /, '')
    .replace(/\r/, '');
  return data;
}

function sendLineNotify(message){
  var token = 'トークン';
  var options =
   {
     'method'  : 'post',
     'payload' : 'message=' + message,
     'headers' : {'Authorization' : 'Bearer '+ token}
   };
   UrlFetchApp.fetch('https://notify-api.line.me/api/notify',options);
}

定期的に実行させる

メニューの時計のアイコンをクリック。

トリガーを作成する。ここではとりあえず10分に1回とした。

LINEにはこんなふうに届きます。絵文字を追加してみた。

今回参考にさせてもらったサイト

【保存版】初心者向け実務で使えるGoogle Apps Script完全マニュアル
Googleが提供しているJavaScriptベースの開発環境Google Apps Script(GAS)。このページは初心者がGASを実務に活用できるようになるまでを支援するまとめ記事です。

コメント