13
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GmailをLINE Notifyを使用してLINEに転送する

Last updated at Posted at 2022-11-06

やりたいこと

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でフィルタをかけて、ヒットしたものにはラベルをつけています
スクリーンショット 2022-11-06 16.33.46.png

LINE Notify APIトークンの発行

  1. LINE Notify APIにアクセスしてログイン
  2. マイページからトークンを発行するからトークンの作成
    スクリーンショット 2022-11-06 16.13.20.png
  3. トークン名とトークルームを選択
    今回はグループで送りたかったのでLINEでグループを作成しておいてそれを設定しました
    スクリーンショット 2022-11-06 16.15.22.png
  4. 発行されたトークンを控える

トークンは絶対に公開しないでください
公開すると知らない人にメッセージを送られる危険があります

トークンは再度表示できません
忘れないように他の人がわからないところに保管しておいてください

実装

GASでの実装になります
自分もGAS自体は初めてだったのですがJavascriptはかじっていたので難しくはなかったです

スクリプトファイルの生成はいくつかあるみたいですが
Googleドライブから新規 > その他 > Google Apps Scriptがわかりやすい気がしました
スクリーンショット 2022-11-06 16.38.48.png

Editorが立ち上がるのでそこに書いていきます
今回書いたプログラム

コード.gs
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');

こちらはプロジェクトプロパティにトークンを格納していて、そこから取得しています
プロジェクトの設定からスクリプト プロパティで設定ができます
スクリーンショット 2022-11-06 17.13.49.png
別にセキュアな保管ではないのですがトークンやAPIキーはハードコーディング避けたいのでこれを活用しました

機密情報であれば閲覧範囲が決められているスプレッドシートに保存してそこらか取得するのが良さそうです

あとはmainでメールを取得する関数を実行して、forEachでLINEに送信しています

定期実行

プログラムができたのであとは定期実行をさせるだけです

  1. トリガーからトリガーを追加
  2. 実行したい関数を選択(今回ではmain)
  3. トリガーを今回は時間手動型にして分ベース15分おきにしました
    メールの取得頻度はこれくらいで十分かと思います
    スクリーンショット 2022-11-06 17.36.18.png

これで15分おきにメールを取得して、未転送のメールはLINEに通知してくれるようになりました

所感

GASを始めて触りましたがほぼJavascriptだったので簡単でした
ネットの情報も結構転がっているので、もっと調べれば他のことにもできそう

13
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?