Google App Script 投資 自動化

【GAS】楽天証券投信積立完了メールから積立完了日をカレンダー登録

はじめに

楽天証券では、投信積立完了をメールで連絡してくれます。この内容をもとにGoogle Apps Scriptを使用してカレンダーに自動登録することを考えます。

ちなみに、楽天証券では投信積立「完了」日と、投信積立「予定」日のメールを受け取れます。

今回は、「完了」日の案内が対象です。

ちなみに、投信積立予定日の記事は以下を参照ください。

また、Google App Scriptについては以下の記事を参照ください。

ここで紹介する内容は、以下の条件を満たす方が対象となります。

対象読者

  • 楽天証券で投信積立を行っている
  • 楽天証券からの投信積立完了メールをGmailで受信している
  • 投信積立完了日をGoogleカレンダーに自動登録させたい

投信積立完了日をGoogleカレンダーに自動登録する

ほとんどの処理は積立予定日のカレンダー登録と同様です。

主な違いは以下の3点です。

  • メール検索文字が楽天証券からの積立完了の案内である
  • メール本文内容解析
  • カレンダーに登録する文字が「投信積立完了」である

以下では、異なる部分のみについて説明します。

未処理メールの抽出

楽天証券からの積立完了メールを抽出します。

メールの抽出条件の構文は、Gmailの抽出条件に設定できる構文と同じです。

// 処理済み後に付けるラベル名(ラベルが存在しなければ自動的に作られる)
var LABEL = '自動処理済';

// GMail検索文字列(楽天証券からの投信積み立て完了メール)
var SEARCH_QUERY = 'is:unread -label:' + LABEL +' from:service@rakuten-sec.co.jp subject:【投資信託】積立購入が完了しました ';

イベント内容説明

  • メールのプレーンテキストをmessage.getPlainBody()で取得します。
  • contaractDayに積立完了日を格納。
  • イベントに積み立てた内容を登録するためにcontentsにメールの内容を抽出。
  • イベントタイトルは「投信積立完了」。
  • イベント色はCalendarApp.EventColor.REDで指定する赤色。
  • カレンダーに登録後、該当メールに「自動処理済」のラベルをputLabel()で付与します。
// 検索文字列
var CONTRACT_DATE = 'に完了(約定)した注文';
var ORDER_DAY = '注文日 ';
var CONFIRM_RETAINMENT = '保有状況の確認';

function registInvestmentTrustContractInformationToCalendar() {

  // デフォルトカレンダーを取得
  var calendar = CalendarApp.getDefaultCalendar();

  var threads = GmailApp.search(SEARCH_QUERY, 0, 1);
  if (threads.length === 0) {
    Logger.log('メールが見つかりません');
    return;
  }

  for(var k in threads){
    var thread = threads[k]
    var messages = thread.getMessages();
    for (var j in messages){
      var message = messages[j];
      var body = message.getPlainBody();    // HtmlメールからPlain textの本文を取得する
      //Logger.log("body=" + body);

      var contractDay = null;   // 約定日
      var orderDay = null;      // 注文日
      var orderYear = null;     // 注文年
      var contents = null;      // 登録内容
      var flgAdd = 0;           // 追加フラグ(0:追加しない、1:追加する)

      // 投資信託約定情報メールの内容確認
      var rows = body.split("\n");
      for (var i in rows) {
        var row = rows[i];

        if (row.indexOf(CONTRACT_DATE) >= 0) {
          contractDay = row.replace(CONTRACT_DATE, '');
          contractDay = contractDay.replace('月', '/');
          contractDay = contractDay.replace('日', '');
          flgAdd = 1;
        } 
        else if(row.indexOf(ORDER_DAY) >= 0){
          orderDay = row.replace(ORDER_DAY, '');
          orderDay = orderDay.replace('年', '/');
          orderDay = orderDay.replace('月', '/');
          orderDay = orderDay.replace('日', '');
          orderYear = orderDay.substring(0, 4);
        }
        else if (row.indexOf(CONFIRM_RETAINMENT) >= 0) {
          flgAdd = 0;
        }

        // CONTRACT_DATEからCONFIRM_RETAINMENTの前の行までを取得する
        if(flgAdd){
          if(contents == null){
            contents = row;
          }
          else{
            contents = contents + row + '\n';
          }
        }
      }
      contractDay = orderYear + "/" + contractDay;

      // Google Calendarに登録
      var registerDate = new Date(contractDay);   // 登録日
      var orderDate = new Date(orderDay);         // 注文日 ※投信積立完了日
      if (contractDay && contents) {
        var title = '投信積立完了';

        // カレンダーに追加
        if(checkConflict(calendar, registerDate, title) == false){
          var options = {
            description : contents
          }
          var event = calendar.createAllDayEvent(title, registerDate, options); 
          event.setColor(CalendarApp.EventColor.PALE_RED);
          event.removeAllReminders();   // 通知は必要ないのでしない
        }

        // 処理済みメールとしてラベルを付ける
        putLabel(thread); 
      }
    }
  }
}

上記コードは説明のために抜粋したものなので、このままでは動作しません。

コードの全体については「全てのコード」を確認ください。

登録済み情報チェック

カレンダーに追加する前に、同じ時間の同じタイトルで、既にカレンダーへの登録があるかチェックします。

/*
 * 登録済み情報があるかチェック
 */
function checkConflict(calendar, registerDate, registerTitle){

  // registerDateで指定する日付のイベントリスト取得
  var events = calendar.getEventsForDay(registerDate);

  // イベントリスト中のイベント毎に登録済みかチェックする
  for (var i in events) {
    var event = events[i];                          // イベントひとつ取得
    var eventTitle = event.getTitle();              // イベントタイトル取得
    if(event.isAllDayEvent()){                      // 終日イベントかチェック
      if(eventTitle.indexOf(registerTitle) >= 0) {  // イベント登録済みかチェック
        Logger.log('登録済:event.getTitle()=' + event.getTitle() + 'registerTitle=' + registerTitle);

        // イベント登録済み
        return true;
      }
    }
  }
  // イベント未登録
  return false;
}

処理済みラベル

カレンダーに何度も登録しないように、処理済みメールに「自動処理済」のラベルを付けます。

※ラベルにつける文字は好みで変えてください。

/*
 * 処理済みとしてスレッドにラベルを付ける
 * 
 * LABELで指定されるラベルが存在しない場合は作成する
 */

// 処理済み後に付けるラベル名(ラベルが存在しなければ自動的に作られる)
var LABEL = '自動処理済';

function putLabel(thread){
  var label = GmailApp.getUserLabelByName(LABEL);
  if(label){
    thread.addLabel(label);
    Logger.log('既存ラベル使用');
  }
  else{
    var newlabel = GmailApp.createLabel(LABEL);
    thread.addLabel(newlabel);
    Logger.log('新規ラベル追加');
  }
}

「自動処理済」のラベルが付いたメールは、処理対象のメールとして抽出されなくなります。

実行結果

Googleカレンダーには以下のように登録されます。

イベントをクリックすることで、積立完了銘柄と積立金額を確認することができます。

全てのコード

/*
 * 楽天証券からの投資信託積立購入完了情報をGoogle Calendarに登録する
 * 
 * Google Calenderに以下のフォーマットで終日イベントが作成される。
 * 「投信積立完了」
 * 
 * 2021/09/13 Created by N.Sekiya
 */

// 処理済み後に付けるラベル名(ラベルが存在しなければ自動的に作られる)
var LABEL = '自動処理済';

// GMail検索文字列(楽天証券からの投信積み立て完了メール)
var SEARCH_QUERY = 'is:unread -label:' + LABEL +' from:service@rakuten-sec.co.jp subject:【投資信託】積立購入が完了しました ';

// 検索文字列
var CONTRACT_DATE = 'に完了(約定)した注文';
var ORDER_DAY = '注文日 ';
var CONFIRM_RETAINMENT = '保有状況の確認';

function registInvestmentTrustContractInformationToCalendar() {

  // デフォルトカレンダーを取得
  var calendar = CalendarApp.getDefaultCalendar();

  var threads = GmailApp.search(SEARCH_QUERY, 0, 1);
  if (threads.length === 0) {
    Logger.log('メールが見つかりません');
    return;
  }

  for(var k in threads){
    var thread = threads[k]
    var messages = thread.getMessages();
    for (var j in messages){
      var message = messages[j];
      var body = message.getPlainBody();    // HtmlメールからPlain textの本文を取得する
      //Logger.log("body=" + body);

      var contractDay = null;   // 約定日
      var orderDay = null;      // 注文日
      var orderYear = null;     // 注文年
      var contents = null;      // 登録内容
      var flgAdd = 0;           // 追加フラグ(0:追加しない、1:追加する)

      // 投資信託約定情報メールの内容確認
      var rows = body.split("\n");
      for (var i in rows) {
        var row = rows[i];

        if (row.indexOf(CONTRACT_DATE) >= 0) {
          contractDay = row.replace(CONTRACT_DATE, '');
          contractDay = contractDay.replace('月', '/');
          contractDay = contractDay.replace('日', '');
          flgAdd = 1;
        } 
        else if(row.indexOf(ORDER_DAY) >= 0){
          orderDay = row.replace(ORDER_DAY, '');
          orderDay = orderDay.replace('年', '/');
          orderDay = orderDay.replace('月', '/');
          orderDay = orderDay.replace('日', '');
          orderYear = orderDay.substring(0, 4);
        }
        else if (row.indexOf(CONFIRM_RETAINMENT) >= 0) {
          flgAdd = 0;
        }

        // CONTRACT_DATEからCONFIRM_RETAINMENTの前の行までを取得する
        if(flgAdd){
          if(contents == null){
            contents = row;
          }
          else{
            contents = contents + row + '\n';
          }
        }
      }
      contractDay = orderYear + "/" + contractDay;
      //Logger.log("contractDay=" + contractDay);
      //Logger.log("contents=" + contents);

      // Google Calendarに登録
      var registerDate = new Date(contractDay);   // 登録日
      var orderDate = new Date(orderDay);         // 注文日 ※投信積立予定日
      if (contractDay && contents) {
        var title = '投信積立完了';

        // カレンダーに追加
        if(checkConflict(calendar, registerDate, title) == false){
          var options = {
            description : contents
          }
          var event = calendar.createAllDayEvent(title, registerDate, options); 
          event.setColor(CalendarApp.EventColor.PALE_RED);
          event.removeAllReminders();   // 通知は鬱陶しいのでしない
        }

        // 処理済みメールとしてラベルを付ける
        putLabel(thread); 
      }
    }
  }
}

/*
 * 登録済みのイベントがあるかチェック
 */
function checkConflict(calendar, registerDate, registerTitle){

  // registerDateで指定する日付のイベントリスト取得
  var events = calendar.getEventsForDay(registerDate);

  // イベントリスト中のイベント毎に登録済みかチェックする
  for (var i in events) {
    var event = events[i];                          // イベントひとつ取得
    var eventTitle = event.getTitle();              // イベントタイトル取得
    if(event.isAllDayEvent()){                      // 終日イベントかチェック
      if(eventTitle.indexOf(registerTitle) >= 0) {  // イベント登録済みかチェック
        Logger.log('登録済:event.getTitle()=' + event.getTitle() + 'registerTitle=' + registerTitle);

        // イベント登録済み
        return true;
      }
    }
  }
  // イベント未登録
  return false;
}

/*
 * 処理済みとしてスレッドにラベルを付ける
 * 
 * LABELで指定されるラベルが存在しない場合は作成する
 */
function putLabel(thread){
  var label = GmailApp.getUserLabelByName(LABEL);
  if(label){
    thread.addLabel(label);
    Logger.log('既存ラベル使用');
  }
  else{
    var newlabel = GmailApp.createLabel(LABEL);
    thread.addLabel(newlabel);
    Logger.log('新規ラベル追加');
  }
}

最後に

ちゃんと積立できたのかをカレンダーから確認できるようになります。

情報の一元化は、効率向上の一つの手段だと思います。

いろいろ見て回るのは手間ですからね。

では、今日も良い一日を。

-Google App Script, 投資, 自動化
-, , , , ,