やりたいこと
Gmailで特定のラベルがついたメールを、自動でLINEに転送して通知させたい
きっかけ
家族と一緒に生活している中で、水道代や電気代のお知らせメールなどを私が一元管理していたのですが、重要なメールなども基本的には家族内で共有しておきたいと思い、自動でGmailに転送したら楽だなと思ったためです
みんなのためにも「これ知らないんだけど!!」が起こりづらい環境構築をしておきましょう。
使用するもの
- Google Apps Script(GAS)
- LINE Notifiy API
- Gmail
- 上記に必要なアカウント
LINE Notify API
LINEが提供している通知をしてくれるサービス
https://notify-bot.line.me/ja/
LINE Messaging API(いわゆるbot)も考えたのですが通知だけなのでLINE Notify APIで十分かと思います
Google App Script
通称GAS
Microsoft OfficeでいうVBAのようなもの
スプレッドシートやGmailなど、さまざまなGoogleサービスを連携して使用することができる
Webスクレイピングもできる模様
事前準備
アカウントの作成は割愛
GmailからLINEに通知するラベルを作成
転送するメールを絞るために転送するメールにラベルをつけておきます
今回は自分で管理するように既にラベルをつけていて家
というラベルにしています
あと、実装方法にもよりますが転送済みのメールを再度転送させないために通知済み
ラベルも作成しておきます
Gmailで転送したいメールのラベルに自動振り分け
転送したメールをわざわざ手動でラベルつけていたら自動化の意味がないので、自動で振り分けしてもらえるようにGmailで設定しておきます
検索からフィルタを作るでも良いと思います
自分は水道や電気などのメールのドメインをOR
でフィルタをかけて、ヒットしたものにはラベルをつけています
LINE Notify APIトークンの発行
- LINE Notify APIにアクセスしてログイン
- マイページから
トークンを発行する
からトークンの作成
- トークン名とトークルームを選択
今回はグループで送りたかったのでLINEでグループを作成しておいてそれを設定しました
- 発行されたトークンを控える
トークンは絶対に公開しないでください
公開すると知らない人にメッセージを送られる危険があります
トークンは再度表示できません
忘れないように他の人がわからないところに保管しておいてください
実装
GASでの実装になります
自分もGAS自体は初めてだったのですがJavascriptはかじっていたので難しくはなかったです
スクリプトファイルの生成はいくつかあるみたいですが
Googleドライブから新規
> その他
> Google Apps Script
がわかりやすい気がしました
Editorが立ち上がるのでそこに書いていきます
今回書いたプログラム
const HOME_LABEL = '家';
const READ_LABEL = '通知済み';
const BODY_MAX_LENGTH = 300;
function main() {
const newMessages = fetchHomeMail();
newMessages.forEach(message => {
sendLine(message);
});
}
/** LINEヘ送信 */
function sendLine(message) {
const lineToken = PropertiesService.getScriptProperties().getProperty('LINE_TOKEN');
const payload = { 'message': message };
const options = {
"method": "post",
"headers": { "Authorization": "Bearer " + lineToken },
"payload": payload
};
UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}
/** メールを取得 */
function fetchHomeMail() {
const sendLabel = GmailApp.getUserLabelByName(READ_LABEL);
const searchTerms = Utilities.formatString("label:%s -label:%s", HOME_LABEL, READ_LABEL);
//取得
const fetchedThreads = GmailApp.search(searchTerms);
const fetchedMessages = GmailApp.getMessagesForThreads(fetchedThreads);
const sendMessages = [];
// 送信メッセージ配列に詰める
fetchedMessages.forEach(message => {
sendMessages.push(gmailToString(message[message.length - 1]));
});
// 通知済みラベルを追加
fetchedThreads.forEach(thread => {
thread.addLabel(sendLabel);
});
// LINE用に配列の順番を反転させる
return sendMessages.reverse();
}
/** メールの整形 */
function gmailToString(mail) {
const mailFrom = mail.getFrom();
const subject = mail.getSubject();
const body = mail.getPlainBody().slice(0, BODY_MAX_LENGTH);
return Utilities.formatString("\n%s\n\n件名:\n%s\n\n内容:\n%s", mailFrom, subject, body);
}
わりと見たまんまな気がします
sendLine(message)
の引数にlineToken
を追加するとか、fetchHomeMail()
の引数に検索条件を渡すのもありかと思います
メール取得
メールの取得してLINEに送信するメッセージを返しています
↓通知済みのラベルを定義
const sendLabel = GmailApp.getUserLabelByName(READ_LABEL);
↓転送したいメールの検索条件
const searchTerms = Utilities.formatString("label:%s -label:%s", HOME_LABEL, READ_LABEL);
今回は label:家 -label:通知済み
にして通知済み
になっていない家
のラベルがついたメールを検索しています
自分はGmail上でも確認したくて未読/既読状態を保持するためにラベルを使用しましたが、未読なら未転送の判定にして、転送したメールは既読にする方法もありかなと思います
↓メールを取得して転送メッセージに変換
//取得
const fetchedThreads = GmailApp.search(searchTerms);
const fetchedMessages = GmailApp.getMessagesForThreads(fetchedThreads);
const sendMessages = [];
// 送信メッセージ配列に詰める
fetchedMessages.forEach(message => {
sendMessages.push(gmailToString(message[message.length - 1]));
});
message[0]`なのは、返信なども含めてスレッドになっているのですが、今回は基本お知らせメールを転送したいのでfirstのみを詰めています
全部渡したい場合はさらにforEachとか必要になると思います
2024/06/05 更新
配列最後のもの(message[message.length - 1]
)が最新のメッセージになるので変更しました。
// 通知済みラベルを追加
fetchedThreads.forEach(thread => {
thread.addLabel(sendLabel);
});
// LINE用に配列の順番を反転させる
return sendMessages.reverse();
}
あとは通知済みラベルを付与して再度転送しないようにする処理と
LINEは古いメッセージが上、新しいメッセージが下なので、配列の順序を反転させています
LINEヘ送信
LINEヘ送信する文字列を受け取ってLINEへ送信しています
先ほど取得したAPIトークンを渡しています
const lineToken = PropertiesService.getScriptProperties().getProperty('LINE_TOKEN');
こちらはプロジェクトプロパティにトークンを格納していて、そこから取得しています
プロジェクトの設定
からスクリプト プロパティで設定ができます
別にセキュアな保管ではないのですがトークンやAPIキーはハードコーディング避けたいのでこれを活用しました
機密情報であれば閲覧範囲が決められているスプレッドシートに保存してそこらか取得するのが良さそうです
あとはmainでメールを取得する関数を実行して、forEachでLINEに送信しています
定期実行
プログラムができたのであとは定期実行をさせるだけです
これで15分おきにメールを取得して、未転送のメールはLINEに通知してくれるようになりました
所感
GASを始めて触りましたがほぼJavascriptだったので簡単でした
ネットの情報も結構転がっているので、もっと調べれば他のことにもできそう