GASとLINE Notifyでクレジットカードの利用履歴を通知、記録してみた

# 概要
みなさん、消費者還元事業はご存知ですか？
キャッシュレス決済するとポイント還元が受けられるアレです。期間限定なのが悲しいです。
今まで現金派だったのですが、これを機にキャッシュレス生活に目覚めて、今やほとんど全てクレジットカードで支払いをしています。
他のクレジットカードもそうなのかは分かりませんが、私が使っているクレジットカードは利用するとすぐに登録したメールアドレスにメールが飛ぶようになっています。私はGmailのアドレスを登録しています。
ただ、Gmailだとカード利用以外のメールもバンバンくるので、カード利用の通知だけ見たいなって思いました。
Gmail使ってるしGASでカード利用のメールだけ取ってきてLINEに通知、ついでにスプレッドシートに記録して利用履歴作成みたいなことできるのでは？と思ってやってみました。

# Gmailで特定のメールを受信したらLINEで通知する
## LINE Notifyのトークン発行
LINEに通知を送るために、LINE Notifyを利用します。
LINE Notifyは、Webサービスと連携すると、LINEが提供する公式アカウント「LINE Notify」から通知を送ることができます。

[LINE Notify](https://notify-bot.line.me/ja/)にアクセスしてログインし、トークンを発行します。
トークン名はLINEの通知に表示されるので、何の通知か分かりやすいものをつけるといいかと思います。
そして通知を送りたいトークルームを選びます。
今回私はLINE Notifyと私だけの個人のトークルームに通知を受け取りたいので、「1:1でLINE Notifyから通知を受け取る」を選択します。
LINE Notifyのアカウントを加えたグループを作成して、そこに通知することも可能です。
トークンが発行されたら、コピーしてどこかに保存しておきます。

## Google Apps Scriptでスクリプトを書く
LINEに通知を送る準備ができたので、Google Apps Scriptでスクリプトを書いていきます。
今回はスプレッドシートに履歴として記録していきたいので、スプレッドシートに紐づいたスクリプトを作成しました。「Container Bound Script」というそうです。

コードは以下を参考にさせていただきました。
https://asatte.biz/gmail-line/

私が書いたのはこんな感じ

```JavaScript
function getMail(){
  
  //検索する件名を指定
  var FindSubject = 'subject:(カードご利用のお知らせ)';
  //指定した件名のスレッドを検索して取得
  var myThreads = GmailApp.search(FindSubject, 0, 10);
  //スレッドからメールを取得し二次元配列に格納
  var myMessages = GmailApp.getMessagesForThreads(myThreads);
  
  for(var i in myMessages){
    for(var j in myMessages[i]){
      
      //スターがないメッセージのみ処理
      if(!myMessages[i][j].isStarred()){
        
        //LINEにメッセージを送信
        sendLine(fetchData(strMessage, 'ご利用日時：', '円'));
        
        //処理済みのメッセージにスターをつける
        myMessages[i][j].star();
      }
    }
  }
}

function fetchData(str, pre, suf) {
  var reg = new RegExp(pre + '[\\s\\S]*?' + suf);
  var data = '';
  data = str.match(reg);
  return data;  
}

function sendLine(strMessage){
  
  //LINEに送信するためのトークン
  var strToken = "発行したトークン";
  var options =
  {
    "method" : "post",
    "payload": "message=" + "\n" + strMessage,
    "headers": {"Authorization" : "Bearer " + strToken}
  };

  UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}
```

コードの解説は先ほどのリンク先に詳しい解説が載っているため割愛します。

私が少しいじった部分としては、
まず検索する件名は「カードご利用のお知らせ」にしました。
カード利用のメールでは件名に必ず「カードご利用のお知らせ」が入ります。

LINEに通知するメッセージ内容に関しては、
メール本文をそのまま送るのではなく、利用日時、場所、金額のみを通知する形にしたいと思いました。
もともと送られてくるメールに
> ご利用日時：xxxx年xx月xx日xx:xx
> ご利用場所：xxxx
> ご利用金額：x,xxx円

という形式で記載されているので、これをそのままLINEに通知したいと思い、
以下を参考にさせていただきました。
https://tonari-it.com/gas-regexp-replace-new/

詳しい解説はリンク先を参照していただければと思いますが、
やったことは、Gmail本文から「ご利用日時」で始まり「円」で終わる部分を抽出したということです。

つまずいた点としては、
参考元ではfetchData関数が

```JavaScript
function fetchData(str, pre, suf) {
  var reg = new RegExp(pre + '.*?' + suf);
  var data = str.match(reg)[0]
    .replace(pre, '')
    .replace(suf, '');
  return data;  
}
```
となっていますが、このままでは複数行にわたる検索ができなかったので、new RegExpの部分を



```JavaScript
var reg = new RegExp(pre + '[\\s\\S]*?' + suf);
```
に変更しました。

「.」では複数行の取得ができず、改行を含む複数行を取得するには「[\\s\\S]」にする必要があるそうです。
参考は以下です。
http://www.initialsite.com/w01/13914

LINEに通知する部分はこんな感じで想定通りになりました。

# Gmailの本文から値を取得してスプレッドシートに書き出す
次に、メールで送られてきたカードの利用情報をスプレッドシートに書き出して、履歴として見れるようにします。

以下を参考にさせていただきました。
https://tonari-it.com/gas-gmail-regexp-append-row/

私が書いたコードはこれです。

```JavaScript
var sheet = SpreadsheetApp.getActiveSheet();

function getMail(){
  
  //検索する件名を指定
  var FindSubject = 'subject:(カードご利用のお知らせ)';
  //指定した件名のスレッドを検索して取得
  var myThreads = GmailApp.search(FindSubject, 0, 10);
  //スレッドからメールを取得し二次元配列に格納
  var myMessages = GmailApp.getMessagesForThreads(myThreads);
  
  for(var i in myMessages){
    for(var j in myMessages[i]){
      
      //スターがないメッセージのみ処理
      if(!myMessages[i][j].isStarred()){
        
        var strMessage = myMessages[i][j].getPlainBody();
        
        //記録するデータを取得
        var date = fetchData(strMessage, 'ご利用日時：', '\r').toString().replace('ご利用日時：', '').replace('\r', '');
        var charge = fetchData(strMessage, 'ご利用金額：', '円').toString().replace('ご利用金額：', '').replace('円', '');
        var place = fetchData(strMessage, 'ご利用場所：', '\r').toString().replace('ご利用場所：', '').replace('\r', '');
        
        //シートに記録
        sheet.appendRow([
          date,
          charge,
          place
        ]);
        
        //LINEにメッセージを送信
        sendLine(fetchData(strMessage, 'ご利用日時：', '円'));
        
        //処理済みのメッセージにスターをつける
        myMessages[i][j].star();
      }
    }
  }
}
```

解説はリンク先をご確認ください。分かりやすいです。
メール本文から利用日時、金額、場所を取得してスプレッドシートに書き出していきました。

書き出すデータを取得する際、最初は

```JavaScript
var date = fetchData(strMessage, 'ご利用日時：', '\r').replace('ご利用日時：', '').replace('\r', '');
```

としており、```.replace```でエラーが出てしまったのですが、
```.toString()```を間に入れたらうまくいきました。　
値に数値が入っていて変換できなかったようです。
参考は以下です。
https://chaika.hatenablog.com/entry/2019/11/15/083000

これでスプレッドシートにカードの利用情報を記録することができました。

コード全体はこちらです。

```JavaScript:コード.gs
var sheet = SpreadsheetApp.getActiveSheet();

function getMail(){
  
  //検索する件名を指定
  var FindSubject = 'subject:(カードご利用のお知らせ)';
  //指定した件名のスレッドを検索して取得
  var myThreads = GmailApp.search(FindSubject, 0, 10);
  //スレッドからメールを取得し二次元配列に格納
  var myMessages = GmailApp.getMessagesForThreads(myThreads);
  
  for(var i in myMessages){
    for(var j in myMessages[i]){
      
      //スターがないメッセージのみ処理
      if(!myMessages[i][j].isStarred()){
        
        var strMessage = myMessages[i][j].getPlainBody();
        
        //記録するデータを取得
        var date = fetchData(strMessage, 'ご利用日時：', '\r').toString().replace('ご利用日時：', '').replace('\r', '');
        var charge = fetchData(strMessage, 'ご利用金額：', '円').toString().replace('ご利用金額：', '').replace('円', '');
        var place = fetchData(strMessage, 'ご利用場所：', '\r').toString().replace('ご利用場所：', '').replace('\r', '');
        
        //シートに記録
        sheet.appendRow([
          date,
          charge,
          place
        ]);
        
        //LINEにメッセージを送信
        sendLine(fetchData(strMessage, 'ご利用日時：', '円'));
        
        //処理済みのメッセージにスターをつける
        myMessages[i][j].star();
      }
    }
  }
}

function fetchData(str, pre, suf) {
  var reg = new RegExp(pre + '[\\s\\S]*?' + suf);
  var data = '';
  //data = str.match(reg).toString().replace(pre, '').replace(suf, '');
  data = str.match(reg);
  return data;  
}

function sendLine(strMessage){
  
  //LINEに送信するためのトークン
  var strToken = "発行したトークン";
  var options =
  {
    "method" : "post",
    "payload": "message=" + "\n" + strMessage,
    "headers": {"Authorization" : "Bearer " + strToken}
  };

  UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}
```

# 最後に
今回は利用情報をひたすらシートに追記していく形になりましたが、せっかくなら月ごとにシートを分けたり、月末に月の利用額の合計を通知したりできるようにしたいと思いました。できるといいな...

参考まとめ:
https://asatte.biz/gmail-line/
https://tonari-it.com/gas-regexp-replace-new/
http://www.initialsite.com/w01/13914
https://tonari-it.com/gas-gmail-regexp-append-row/
https://chaika.hatenablog.com/entry/2019/11/15/083000