はじめに
楽天証券では、投信積立完了をメールで連絡してくれます。この内容をもとに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('新規ラベル追加');
}
}
最後に
ちゃんと積立できたのかをカレンダーから確認できるようになります。
情報の一元化は、効率向上の一つの手段だと思います。
いろいろ見て回るのは手間ですからね。
では、今日も良い一日を。