はじめに
知人にタイトルの依頼がきたので、興味本位でやってみた。(GAS触れる自慢がしたかったのです)ロジックは非常にシンプルです。箇条書きすると下記になります。
- Gmail APIを使って特定のメールを取得
- 正規表現を使って必要な情報を本文から取得
- Google Calendar APIを使ってカレンダーに登録
その前に
ちなみにGmailには予約完了メール系を勝手にカレンダーに登録してくれる機能があります。 そういったメールをしたい場合は設定だけで済むのでこっちは不要です!また、今回はプログラムだけではなく、ラベルや自動振り分けなどのGmail自体の機能も使っています。
そちらは詳細に説明しないので調べてもらえればと思います!
このコードを使うには前もって情報を抽出したいメールを手動or自動振り分けでラベル付けとスターを付けていることが前提となります。
あと、スレッドに受信するメールがたまることを前提にコードを書いているので、一部美しくないところがあります。
やってみた
実際にコードを書いてみました!
業務でも使われるコードなので適当なコードになっているところもあります。ご了承ください。
// gmailに飛んできた楽天からの予約完了メールを自動的にカレンダーに登録するプログラム
function main() {
// オブジェクトの作成
const label = GmailApp.getUserLabelByName("ラベル");
console.log("メールから情報を取得");
const infomations = getMail(label);
console.log("カレンダーに登録");
setCalendar(infomations);
};
function getMail(label) {
// ラベルから必要なメールを取得して情報を取ってくる
let infomations = [];
let start = 0;
let max = 30;
while (true) {
let threads = label.getThreads(start, max); // 取得エラーの原因になるので一気に取得しない
if (threads.length <= 0) {
break;
};
start += (max - 1);
for (thread of threads) {
if (!thread.hasStarredMessages()) { // すべてのメッセージにスターが外れている場合は無視する
continue;
}
messages = thread.getMessages();
for (message of messages) {
// 本文から必要な情報を抜き出すスクリプト
if (!message.isStarred()) { // スターが外れているメッセージは無視
continue;
}
let body = message.getBody();
body = body.replace(/\u3000/g, "") // すべての全角空白を消す
body = body.replace(/\n/g, "").replace(/\s+/g, "") // すべての改行を消す
infomations.push(extractRegexp(body));
message = message.markRead(); // 既読にする
message = message.unstar(); // スターを外す
console.log("既読とアンスター処理の完了");
};
console.log("スレッドの読み込み完了")
};
};
return infomations;
};
function extractRegexp(body) {
/*
正規表現で美しくデータを抽出するスクリプト
*/
reg = /日時:(\d{4}-\d{1,2}-\d{1,2})/
let tmp = body.match(reg)[1];
info = {"日時" : tmp}
return info
};
function setCalendar(infomations) {
// googleカレンダーに取得した情報を説明付きで登録する
for (info of infomations) {
let event = CalendarApp.getDefaultCalendar().createEventFromDescription(
"いい感じのタイトル"
); // タイトル付きでカレンダーの作成
let startTime = new Date("正規表現で取得した日時とか (yyyy-mm-dd hh:MM:ss フォーマットで)");
let endTime = new Date("正規表現で取得した日時とか (yyyy-mm-dd hh:MM:ss フォーマットで)");
// 詳細設定
event.setTime(startTime, endTime); // 日時の登録
event.setDescription(
"本文または記載しておきたい予定の情報"
);
};
};
では順を追って説明していきます。(自分的に重要なコードのみの説明となります!)
Main部分の説明
// オブジェクトの作成
const label = GmailApp.getUserLabelByName("ラベル");
このコードで自作したラベルのオブジェクトの作成をしています。このオブジェクトからスレッドやメール本文の取得が可能になります。
ちなみにラベルとはGmailのサイドバーにある、こんなやつ。
自分で作る必要があります。
メールの本文抽出部分の説明
let threads = label.getThreads(start, max); // 取得エラーの原因になるので一気に取得しない
if (threads.length <= 0) {
break;
};
start += (max - 1);
ドキュメントに一度で読み込むメールの量が大きすぎるとエラー落ちすると記載があったので、エラー対策として書いています。
for (thread of threads) {
if (!thread.hasStarredMessages()) { // すべてのメッセージにスターが外れている場合は無視する
continue;
}
messages = thread.getMessages();
for (message of messages) {
// 本文から必要な情報を抜き出すスクリプト
if (!message.isStarred()) { // スターが外れているメッセージは無視
continue;
}
情報を抽出する対象となるメールはスターがついているもののみを対象としています。
thread.hasStarredMessages()
でスレッド内のメールにスターがついているか、
message.isStarred()
でメール単体にスターがついているかを確認しています。
受信時にスターをつけて、情報を抽出できてカレンダーに登録できたものはスターを外すとしているので、この処理をすることで同じメールを処理しないようにしてます。
let body = message.getBody();
body = body.replace(/\u3000/g, "") // すべての全角空白を消す
body = body.replace(/\n/g, "").replace(/\s+/g, "") // すべての改行を消す
infomations.push(extractRegexp(body));
message = message.markRead(); // 既読にする
message = message.unstar(); // スターを外す
メールの本文を取得して、正規表現で情報を抜き出す自作関数を呼んでいます。
本文から情報を取得する際に面倒なのは、スクショのように整った形(改行がしっかり入る。)で取得してしまうことです。
なので、 body.replace(/\n/g, "").replace(/\s+/g, "")
を使って改行や空白を削除して、一行の文字列になるように変更します。これをしないと正規表現が上手く使えないので MUSTです
必要であれば全角削除をするために body.replace(/\u3000/g, "")
も使うといいかもしれません。
正規表現部分の説明
function extractRegexp(body) {
/*
正規表現で美しくデータを抽出するスクリプト
*/
reg = /日時:(\d{4}-\d{1,2}-\d{1,2})/
let tmp = body.match(reg)[1];
info = {"日時" : tmp}
return info
};
すべてを見せることができないのですが、こんな感じで、正規表現で情報を取ります。
body.match(reg)[1]
とすることで (\d{4}-\d{1,2}-\d{1,2})
この()部分の情報のみを取得出来ます。
正規表現は非常に考えるのが面倒ですが、chatGPTさんが優秀なので、考えてもらいましょう。
カレンダー登録部分の説明
function setCalendar(infomations) {
// googleカレンダーに取得した情報を説明付きで登録する
for (info of infomations) {
let event = CalendarApp.getDefaultCalendar().createEventFromDescription(
"いい感じのタイトル"
); // タイトル付きでカレンダーの作成
let startTime = new Date("正規表現で取得した日時とか (yyyy-mm-dd hh:MM:ss フォーマットで)");
let endTime = new Date("正規表現で取得した日時とか (yyyy-mm-dd hh:MM:ss フォーマットで)");
// 詳細設定
event.setTime(startTime, endTime); // 日時の登録
event.setDescription(
"本文または記載しておきたい予定の情報"
);
};
let event = CalendarApp.getDefaultCalendar().createEventFromDescription(
"いい感じのタイトル"
); // タイトル付きでカレンダーの作成
ここで event(カレンダー)の作成を行います。
createEventFromDescription
desciption となってややこしいですが、カレンダーのタイトルになります。
// 詳細設定
event.setTime(startTime, endTime); // 日時の登録
event.setDescription(
"本文または記載しておきたい予定の情報"
);
日時の登録と詳細の情報の記入を行っています。
日時は dateオブジェクトを入れる必要があるので注意です!
さいごに
Gmailはスレッドの概念があり、ちょっとコーディングめんどいなと思った。(スレッド単位でラベル付けしちゃうところとか)APIのドキュメントはめちゃくちゃ分かりやすいので、是非参照しながらコードをかいてみてください!
APIドキュメント