Gmailで購読しているメルマガをLINEで閲覧できるbotつくった。

#はじめに
　最近では、LINE＠を導入しているアカウントも多いですが、私は今でも複数メルマガを登録しています。決まった時間に届くものもあれば、いつ届くかわからない不定期のものまで。しかし、問題はGmailだとついつい忘れがちになってしまうこと。
　そこで今回、メルマガをLINEで見ることができるメルマガbotを開発しようと思います。

##目次
1.LINE Developersにログインし、新規チャネルを作成
2.GoogleAppScriptに転送するコードを記入
3.ライブラリ「Moment.js」を追加
4.Webhook URLの設定
5.手動実行で動作確認
6.定期実行のトリガーを設定

#1.LINE Developersにログインし、新規チャネルを作成
　まずは、こちらからLINE Developersにアクセスして、ログインを済ませましょう。初めての方は登録から。続いてMessagingAPIを選択し、新規チャネルを作成します。

#2.GoogleAppScriptに転送するコードを記入
　とても便利で今話題のGAS（GoogleAppScript）を使用します。まずはページにアクセスし、新しいプロジェクトを作ります。次にメルマガをLINEに転送するためのコードを記入していきます。いったん下記のコードをコピペして貼り付けます。

```js

// LINE Developersに書いてあるChannel Access Token
var access_token = "アクセストークン";
var userID = "ユーザー🆔";


var member_name = {"メールアドレス1": "名称1",
                   "メールアドレス2": "名称2",
                  }

var member_image = {"メールアドレス1": "画像URL1",
                    "メールアドレス2": "画像URL2",
                   }

function sendLine() {
  sendAll(get_allmail(), userID);
}

function push(message, to) {
  var url = "https://api.line.me/v2/bot/message/push";
  var headers = {
    "Content-Type" : "application/json; charset=UTF-8",
    'Authorization': 'Bearer ' + access_token,
  };
  var postData = {
    "to" : to,
    "messages" : message 
  };

  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  return UrlFetchApp.fetch(url, options);
}


function get_allmail() {
  const interval = 30;
  const date = new Date() ;//現在時刻を取得
  const unixTime = date.getTime();//UNIX時間に変換
  const now = Math.floor(unixTime/1000); //ミリ秒を秒に変換
  const term = now - 60 * interval; //現在時刻から60分前
  const termStr = term.toString(); //検索期間を文字列に変換
  //該当のドメインを持つアドレス＋未読のものを検索対象にします
  const condition = "メールアドレス" + " after:" + term + " is:unread";
  var thds = GmailApp.search(condition, 0, 20);
  var messe = GmailApp.getMessagesForThreads(thds);
  var res = [];
  for(var i = 0; i < messe.length; i++) {
      for(var j = 0; j < messe[i].length; j++){
        var target = messe[i][j];
        var body = target.getBody();
        var myRegexp = /img src="([\s\S]*?)">/g;
        var email_body = target.getPlainBody();
        var from = target.getFrom();
        //既読にする
        target.markRead();
        var mail_date = Moment.moment(target.getDate());
        var now_date = Moment.moment();
        var diff = now_date.diff(mail_date, 'minutes');
        //スレッド対策
        if (diff > interval) {
           Logger.log('以前のものはスキップ');
           continue;
        }

        var title = messe[i][j].getSubject();
        urls = body.match(myRegexp);
        var mail_res = {"title": title, "body": email_body, "image": [], "from" : from };
        //画像が複数枚あるので
        if(urls) {
            var tmp_arr = [];
            for(var k = 0; k < urls.length; k++ ) {
               url = urls[k].slice(9,-2);
               url = url.replace('http', 'https');
               tmp_arr.push(url)
            }
            mail_res["image"] = tmp_arr;
        }
        res.push(mail_res);
      }
  }
  return res;
}
function sendAll(mobame, to){
   var messages = [];
    for (var i=0; i < mobame.length; i++) {
      text = mobame[i]["title"] + "\n" + mobame[i]["body"];
      text = convert_emoji(text);
      mail = mobame[i]["from"].slice(1,-1);
      message_text = {
        "type": "text",
        "text": text,
        'sender': {
          'name': member_name[mail],
          'iconUrl': member_image[mail]
        }
      };
      messages.push(message_text);
      if (mobame[i]["image"]) {
        urls = mobame[i]["image"];
        for(var j = 0; j < urls.length; j++ ){
          message_image = {'type':'image',
                           'originalContentUrl':urls[j],
                           'previewImageUrl':urls[j],
                           'sender': {
                            'name': member_name[mail],
                            'iconUrl': member_image[mail]
                            }
                           };
          messages.push(message_image);
        }
      }
    }
    //対象がなければ終了
  if (messages.length == 0){
    return;
  }
  if (messages.length <= 5) {
    //5件以下ならそのまま送信
    push(messages, to);
  }else{
    var max = messages.length;
    var start = 0;
    var end = 5;
    //5件以上ある場合5件ずつにわけて複数回送る
    while(end <= max){
       push(messages.slice(start,end), to);
       start += 5;
       end += 5;
    }
    push(messages.slice(start), to);
  }
}
//絵文字を変換する
function convert_emoji(text) {
   var reg = /&#\d+;/g;
   var emoji = text.match(reg);
   if (emoji) {
    for (var i=0; i < emoji.length; i++) {
       var reg = /\d+/;
       var decimal = Number(emoji[i].match(reg))
       Logger.log(decimal);
       var unic = String.fromCodePoint(decimal);

       text = text.replace(emoji[i], unic)
    }
  }
  return text
}
```

 少し手を加えて編集します。

- 最初に作成したLINEbotチャネルのMessagingAPI設定から、チャネルアクセストークンをコピーして貼り付け
- 同様にチャネル基本設定からチャネル🆔をコピーして貼り付け
- member_nameのメールアドレスの部分を自分が購読しているメルマガのものに書き換え
- member_imageのメールアドレスを画像URLに書き換え。画像のURLには必ずhttpsから始まるものを使用

メルマガの件数によっては、適宜追加してください。
また、画像や絵文字にも対応するようにコードを記入しています。

#3.ライブラリ「Moment.js」を追加
　「日付関連」の色々便利な機能をまとめたライブラリを追加します。詳しくは以下の記事で解説してくれています。(https://tonari-it.com/gas-moment-js-moment/)

- スクリプトエディタから「リソース」→「ライブラリ」をクリック
- 「Add a library」という箇所に、以下GAS用Moment.jsのスクリプトIDを入力

```:スクリプトID
MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48
```
- 「追加」をクリックして保存

#4.Webhook URLの設定
　LINEbotとGoogleAppScriptを紐付けるため、WebhookURLを取得します。

- [公開]->[ウェブアプリケーションとして導入]
- アプリケーションにアクセスできるユーザーを[全員（匿名ユーザーを含む）]にしてOK
- URLを取得し、コピー
- MessagingAPI設定のWebhook設定に貼り付けて検証


#5.手動実行で動作確認
 次はGoogleAppScriptで手動実行を試してみます。

- 「実行」→「関数を実行」→「sendline」
- 「許可を確認」→「自分のアカウントを選択」
- 「安全ではないページに移動」→「許可」

　これで一度スクリプトが手動実行します。一度自身のLINEに友達登録をして確認してみましょう。あくまでテストなので無事にLINEに転送されていればOKです。

#6.定期実行のトリガーを設定
　今後は自動で設定したメルマガを取得できるようにします。そのために定期実行のトリガーを設定します。

- スクリプトのページから「編集」→「現在のプロジェクトのトリガー」
- 「トリガー」を追加
- 下の画像のように設定

![スクリーンショット 2020-10-14 16.08.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/774875/7c9b072e-1329-daa0-e44b-8f2a274d6542.png)


　トリガーのタイプや時間の間隔などは、お好みで変更してください。

#まとめ
　無料で使うには、１ヶ月の総メール数に制限がありますが、それでも複数のメルマガを登録できるので大変便利です。見落とすこともないので作って良かったと実感しています。