楽天ペイの利用記録をGmailとGASを使ってスプレッドシートに収集する方法

スポンサーリンク

QRキャッシュレス決済手段として便利な楽天ペイ。私は普段ほとんどの買い物を楽天ペイにしています。そんな楽天ペイ、支払履歴はアプリから見ることができるのですが、自動でGoogleスプレッドシートにまとめたい!ということで、利用時にGmailに送られてくる「ご利用内容確認メール」を読み取って、GoogleスプレッドシートにまとめるGoogle Apps Scriptを作ってみました。

※Google Apps Scriptを用いてメールを読み取るため、「ご利用確認メール」はGmailに送る設定にする必要があります。
※メールを抽出するので、ご利用確認メールを削除してしまっていると当然抽出できません。アーカイブならOKです。

スポンサーリンク

Google Apps Script コード

まず適当なGoogleスプレッドシートを作成し、「拡張機能」→「Apps Script」を選択して、スクリプトを新規作成します。

下記のコードを入力して、「実行」をクリックすると処理が走ります。実行ログに、抽出結果も表示されます。

function extractRakutenPayEmails() {

  // 新旧どちらの件名もヒットするように検索
  var query = 'from:pay.rakuten.co.jp subject:("楽天ペイアプリご利用内容確認メール" OR "お支払い完了のお知らせ")';
  var threads = GmailApp.search(query);

  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName("楽天ペイ") || spreadsheet.insertSheet("楽天ペイ");

  if (sheet.getLastRow() === 0) {
    sheet.appendRow(["ご利用日時", "決済総額", "ご利用店舗"]);
  }

  var existingData = sheet.getDataRange().getValues();
  var newData = [];

  for (var i = 0; i < threads.length; i++) {
    var messages = threads[i].getMessages();

    for (var j = 0; j < messages.length; j++) {
      var body = messages[j].getPlainBody();

      // ご利用日時:▼の有無に関わらず、日付+時刻の形を直接拾う
      var usageDate = null;
      var dMatch = body.match(/ご利用日時[\s\S]*?([0-9]{4}\/[0-9]{1,2}\/[0-9]{1,2}\([^)]*\)\s*[0-9]{1,2}:[0-9]{2})/);
      if (dMatch) {
        usageDate = dMatch[1].replace(/\s+/g, ' ').trim();
      }

      // 決済総額:旧「1,870円」も新「¥100」も拾う(数字だけ取り出してカンマ除去)
      var totalAmount = null;
      var aMatch = body.match(/決済総額[\s\S]*?[¥¥]?\s*([\d,]+)\s*円?/);
      if (aMatch) {
        totalAmount = aMatch[1].replace(/,/g, '');
      }

      // ご利用店舗:項目名の次行の店舗名を拾う。
      // 罫線文字(━─-)、改行、または「電話番号/▼」までを終端とする
      var shop = null;
      var sMatch = body.match(/ご利用店舗[\r\n\s]*([^\r\n━─]+?)(?:[\r\n]|電話番号|▼|━|─|-{10,})/);
      if (sMatch) {
        shop = sMatch[1].replace(/^[▼\s]+/, '').trim();
      }

      // どれか取れなければスキップ
      if (!usageDate || !totalAmount || !shop) {
        Logger.log(["抽出失敗・スキップ", messages[j].getSubject(), usageDate, totalAmount, shop]);
        continue;
      }

      // 既存データと比較
      var isExisting = false;
      for (var k = 0; k < existingData.length; k++) {
        var row = existingData[k];
        if (row[0] == usageDate && row[1] == totalAmount && row[2] == shop) {
          isExisting = true;
          Logger.log(["記載済み", usageDate, totalAmount, shop]);
          break;
        }
      }

      if (!isExisting) {
        newData.push([usageDate, totalAmount, shop]);
        Logger.log([usageDate, totalAmount, shop]);
      }
    }
  }

  // 日時が古い順にソート
  newData.sort(function(a, b) {
    return new Date(a[0]) - new Date(b[0]);
  });

  newData.forEach(function(row) {
    sheet.appendRow(row);
  });
}

コードが実行している内容としては、Gmailから「楽天ペイアプリご利用確認メール」という件名のメールを抽出し、その中から「ご利用日時」「決済総額」「ご利用店舗/お支払先」の情報を抽出、配列に格納した上で、スプレッドシートの「楽天ペイ」というシートに記入するというものです。GASにそこまで詳しくないのでAIの力など借りながらなんとか作成しましたw

2024/6/25追記:楽天Payで税金などを支払った際、メールの内容が「ご利用店舗」から「お支払先」に変わるため、それに対応できるようにコードを変更しました。コメントいただいた方ありがとうございました。

//変更前
//var shop = body.match(/ご利用店舗\s*([\s\S]*?)(?:\n|-{40})/)[1].trim();
//変更後
var shop = body.match(/(ご利用店舗|お支払先)\s*([\s\S]*?)(?:\n|-{40})/)[2].trim();

2025/05/31追記:すでに記載済みの項目でもLoggerでログ出力することで、実行ログで様子を見やすくしました

Logger.log(["記載済み", usageDate, totalAmount, shop]);

2026/5/28追記:メールのパターン認識が失敗することがあったので正規表現を修正

//変更前
      // ご利用日時、ご利用店舗、決済総額を抽出
      var usageDate = body.match(/ご利用日時\s*([\s\S]*?)\n/)[1].trim();
      var totalAmount = body.match(/決済総額\s*([\s\S]*?)\s*円/)[1].trim().replace(/,/g, '');
      var shop = body.match(/(ご利用店舗|お支払先)\s*([\s\S]*?)(?:\n|-{40})/)[2].trim();
//変更後
      // 改行や空白の揺れを吸収するためのヘルパー
      function pick(regex) {
        var m = body.match(regex);
        return m ? m[m.length - 1].trim() : null;
      }

      // ご利用日時:日付と時刻の形だけを直接拾う(改行に依存しない)
      var usageDate = pick(/ご利用日時\s*([0-9]{4}\/[0-9]{1,2}\/[0-9]{1,2}\([^)]*\)\s*[0-9]{1,2}:[0-9]{2})/);

      // 決済総額:次に「円」が来るまでの数字(カンマ除去)
      var totalAmount = null;
      var amtMatch = body.match(/決済総額\s*([\d,]+)\s*円/);
      if (amtMatch) {
        totalAmount = amtMatch[1].replace(/,/g, '');
      }

      // ご利用店舗:店舗名のあと「電話番号」または改行・区切り線まで
      var shop = pick(/(?:ご利用店舗|お支払先)\s*([\s\S]*?)(?:\s*電話番号|\n|-{10,})/);

      // どれか取れなければスキップ(フォーマット違いのメール対策)
      if (!usageDate || !totalAmount || !shop) {
        Logger.log(["抽出失敗・スキップ", message.getSubject(), usageDate, totalAmount, shop]);
        continue;
      }

2026/5/29追記:5月16日以降くらいに、メールの件名や内容が仕様変更したので、追従できるようにコード変更

以下、旧コード

function extractRakutenPayEmails() {
  // Gmailで該当メールを検索
  var query = 'subject:"楽天ペイアプリご利用内容確認メール"';
  var threads = GmailApp.search(query);
  
  // Googleスプレッドシートを開く
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName("楽天ペイ") || spreadsheet.insertSheet("楽天ペイ");

  // シートのヘッダー設定
  if (sheet.getLastRow() === 0) {
    sheet.appendRow(["ご利用日時", "決済総額", "ご利用店舗"]);
  }
  
  // スプレッドシートから既存のデータを取得
  var existingData = sheet.getDataRange().getValues();
  
  // 新しいデータを格納する配列を作成
  var newData = [];

  for (var i = 0; i < threads.length; i++) {
    var messages = threads[i].getMessages();
    
    for (var j = 0; j < messages.length; j++) {
var message = messages[j];
      var body = message.getPlainBody();

      // 改行や空白の揺れを吸収するためのヘルパー
      function pick(regex) {
        var m = body.match(regex);
        return m ? m[m.length - 1].trim() : null;
      }

      // ご利用日時:日付と時刻の形だけを直接拾う(改行に依存しない)
      var usageDate = pick(/ご利用日時\s*([0-9]{4}\/[0-9]{1,2}\/[0-9]{1,2}\([^)]*\)\s*[0-9]{1,2}:[0-9]{2})/);

      // 決済総額:次に「円」が来るまでの数字(カンマ除去)
      var totalAmount = null;
      var amtMatch = body.match(/決済総額\s*([\d,]+)\s*円/);
      if (amtMatch) {
        totalAmount = amtMatch[1].replace(/,/g, '');
      }

      // ご利用店舗:店舗名のあと「電話番号」または改行・区切り線まで
      var shop = pick(/(?:ご利用店舗|お支払先)\s*([\s\S]*?)(?:\s*電話番号|\n|-{10,})/);

      // どれか取れなければスキップ(フォーマット違いのメール対策)
      if (!usageDate || !totalAmount || !shop) {
        Logger.log(["抽出失敗・スキップ", message.getSubject(), usageDate, totalAmount, shop]);
        continue;
      }

      // 既存のデータと比較して、新しいデータのみを追加
      var isExisting = false;

      for (var k = 0; k < existingData.length; k++) {
        var existingRow = existingData[k];
        if (existingRow[0] == usageDate && existingRow[1] == totalAmount && existingRow[2] == shop) {
          isExisting = true;
          Logger.log(["記載済み", usageDate, totalAmount, shop]);
          break;
        }
      }

      if (!isExisting) {
        newData.push([usageDate, totalAmount, shop]);
        Logger.log([usageDate, totalAmount, shop]);
      }
    }
  }

  // 新しいデータを日時が古い順にソート
  newData.sort(function(a, b) {
    var dateA = new Date(a[0]);
    var dateB = new Date(b[0]);
    return dateA - dateB;
  });

  // ソートされた新しいデータをスプレッドシートに追加
  newData.forEach(function(row) {
    sheet.appendRow(row);
  });
}

コメント

  1. てれびくん より:

    まさにやりたいことを実現できました。
    素晴らしい記事ありがとうございます。

    楽天payで都税を払ったところ、
    メール本文に「ご利用店舗」という文字列がなく、代わりに「お支払い先」という文字がでてきたので、

    この部分を
    var shop = body.match(/ご利用店舗\s*([\s\S]*?)(?:\n|-{40})/)[1].trim();

    以下のように修正させていただき使わせていただきました。
    var shop = body.match(/(ご利用店舗|お支払先)\s*([\s\S]*?)(?:\n|-{40})/)[2].trim();

    有益な情報ありがとうございました。

    • CGBeginner より:

      コメントありがとうございます。変更を反映させていただきました。こちらこそ有益な情報ありがとうございます。

タイトルとURLをコピーしました