>
献立の参考に。食材タグ一覧ページはこちら

備忘録 mail_notify_LINE

特定のメールをLINEに転送(通知)してくれるGAS(GoogleAppsScript)アプリケーションを多分学生の頃に作ってあったんだけど、今見るとあまりにかわいそうな出来だったので改修しました。メイン処理の関数が改修前は12000字近くあったのが、改修後は1200字程度に減りました。
(処理の一部をスプレッドシートに回した部分もあるので、一概にコードの効率だけではないけど。)

注意事項

私はこのアプリを、メールで届くワンタイムパスワードの転送や、AppleGiftCardなどのギフトカードを楽天で購入した際に、メールで届くコードをスマホに転送するなどの用途で使用していますが、言わずもがな、これらの情報をスプレッドシート、外部APIなどに渡すのはセキュリティ上全くもって褒められたことではないため、万が一真似する際は自己責任でお願いします。(私はまあいっか。と思っているのでやっています)

処理概要

使用するのは以下のAPI2つとGoogleのサービス2つです。
万が一真似する方はそれぞれAPIのアカウント作成、アプリケーション登録の上、チャンネルキー、トークン部分を自分のものに書き換えてください。(個人的に使う分には全て無料枠の範囲で使えます)

  • LINE Messaging API(テキスト用・画像用)
  • Bitly API
  • GmailApp
  • SpreadsheetApp

大まかな処理としては以下のイメージ

メインのmail_notify_LINE関数を実行対象関数として、GASのトリガーから毎分1回実行させています。

スプレッドシートの処理

メールの種類ごとにテキストに対する加工内容をコードで書くのはメンテが大変なので、その処理を代替するためにスプレッドシートを導入しました。

スプレッドシートの関数処理を使用して、org_msgに入ってくるテキストを元にそれぞれのメールの形式に合わせて、ワンタイムパスワード部分のみ抽出などの処理を行った本文データをconv_msg行に表示します。また、AppleGiftCardなどのメールに関しては、ギフトコードを含んだURLからチャージを行えるため、そのURLを生成しています。

また、サンプルには該当する物がありませんが、画像URLがメールに含まれる場合、それを抽出してimgURLに入るようにすることで、LINEに画像も転送することが出来ます。

サンプルドキュメント

スプレッドシートに対するGASの処理としては、メール送信元とFROMが合致するorg_msgの行にメール本文を記入して、conv_msg・URL・img_URLに生成される抽出結果を読み出すだけのシンプルな処理を行っています。
対応する送信元アドレスを増やしたい場合は例外処理用の99よりも上に行を足して、対応する関数処理を追加するのみで対応できます。
※dummy行はFROM条件に合致しないメールを処理するための行です。メール本文に対する処理は先頭1500文字を単純に抽出しています。

改修前はこの各アドレスに対応した個別のテキスト整形の処理を全てコードで、IFで分岐して書いていました。

var FindSubject_sms = 'label:(mail_notify_line) ';
var id = "***************************************";//スプレッドシートのID

function mail_notify_LINE(){
  //指定した件名のスレッドを検索して取得 (最新10件)
  var myThreads = GmailApp.search(FindSubject_sms, 0, 10); 
  //スレッドからメールを取得し二次元配列に格納
  var myMessages = GmailApp.getMessagesForThreads(myThreads);

  for(var i in myMessages){
    for(var j in myMessages[i]){
      if(!myMessages[i][j].isStarred()){//スターが付いていない物のみ処理

        var from = myMessages[i][j].getFrom();
        var org_msg = myMessages[i][j].getPlainBody();

        var sheetApp = SpreadsheetApp.openById(id);
        var sheet = sheetApp.getSheetByName("mail_notify_LINE_work");
        var lastrow = sheet.getLastRow();
        var master = sheet.getRange(1,1,lastrow,2);
        var master_lst = master.getValues();

        for(let k = 1 ; k <= lastrow - 1; k++){
          var master_from = master_lst[k][1];

          if(from == master_from ){
            sheet.getRange(k+1,3).setValue(org_msg);
            Utilities.sleep(500);
            var conv_msg = sheet.getRange(k+1,4).getValue();
            var org_url = sheet.getRange(k+1,5).getValue();
            var img_url = sheet.getRange(k+1,6).getValue();

            var message_text = conv_msg;

            if(org_url.length > 0 ){
              Logger.log(org_url)
              var message_text = message_text + "\r\n" + bitlyURL(org_url.replace(/[\r\n]+/g,""));
            }
            sendLine_text(message_text);

            if(img_url.length > 0 ){
              sendLine_img(img_url)
            }
            myMessages[i][j].star()
            break

          }else if(master_from == "dummy"){
            sheet.getRange(k+1,3).setValue(org_msg);

            var conv_msg = sheet.getRange(k+1,4).getValue();
            var message_text = conv_msg;

            sendLine_text(message_text);
            myMessages[i][j].star()
          }
        }    
      }
    }
  }
}

//LINEAPI_新API
function sendLine_text(strMessage) {


  var url = 'https://api.line.me/v2/bot/message/broadcast';
  var channelKey = '*******************************************************';

  var messages = [{
    'type': 'text',
    'text': strMessage,
  }];

  UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + channelKey,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'messages': messages,
    }),
  });
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

//LINEAPI_新API 画像用
function sendLine_img(imgURL) {

  var url = 'https://api.line.me/v2/bot/message/broadcast';
  var channelKey = '***********************************************';

  var messages = [{
    'type': 'image',
    'originalContentUrl': imgURL,
    'previewImageUrl':imgURL
  }];

  UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + channelKey,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'messages': messages,
    }),
  });
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}


//Bitly短縮URLAPI
function bitlyURL(targetURL){

  const ACCESS_TOKEN = '******************************************';
  const ACCESS_URL   = 'https://api-ssl.bitly.com/v4/shorten';

  var payload = {
      'long_url': targetURL,
  };

  var headers = {
      'Authorization' : 'Bearer ' + ACCESS_TOKEN,
      'Content-Type': 'application/json',
  }

  var options = {
      "method"      : 'POST',
      'headers'     : headers,
      'payload'     : JSON.stringify(payload),
  }

  var response = UrlFetchApp.fetch(ACCESS_URL, options);
  var content = response.getContentText("UTF-8");

  return JSON.parse(content).link;
}

コメント

タイトルとURLをコピーしました