LINEボットでチャット内容をメールに転送する

# 目的
LINEのチャット内容をメールに転送する。


# 背景
趣味のグループの話だが、
メンバー間の連絡にLINEとメールを利用している。
ただし、まだLINEを利用できていない(メールは利用できている)メンバーがいるので、
LINEで相談したら、その内容を電話やメールで伝えていた。
LINEを利用できていないメンバーが一人だったので、
それほど問題にはならなかったが、
もし多数いたら、LINEの利用をあきらめていたかもしれない。
LINEのチャット内容をメールに転送できたら、
もっとLINEを活用できると思い、本ツールの作成に取り組んだ。


# 環境
- iPhoneX 14.4.2
  - LINE 11.6.5
- Google Apps Script(GAS) [March 15, 2021](https://developers.google.com/apps-script/releases/#march_15_2021)
- Windows10 バージョン2004(OSビルド19041.928)
  - Google Chrome バージョン: 90.0.4430.93(Official Build) (64 ビット)


# やったこと
- プロバイダとMessaging APIのチャネルを作成 → 公式のドキュメント[Messaging APIを始めよう](https://developers.line.biz/ja/docs/messaging-api/getting-started/) を見ればすぐにできる
- メールアドレススプレッドシートの作成
- GASスクリプトファイルの作成&テスト&公開


## メールアドレススプレッドシートの作成
Google Driveで新規作成ボタンをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/a1bb7908-5a1e-c8ef-c867-93bb60171229.png)
「Googleスプレッドシート」から「空白のスプレッドシート」を選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/c465f4a7-77b5-4716-7fa2-3ddaa88f9143.png)
Gmailアドレスのエイリアスを利用して複数のメールアドレスを記載する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/ffa435dd-b1c3-64e9-6adb-81515d5965d7.png)
共有ボタンをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/3d1534bd-5002-a505-c531-7b7a8aca1103.png)
名前を付けて「保存」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/f0456486-6a6b-0dc7-d2f4-2c33da8b5aa7.png)
「リンクを知っている全員に変更」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/cb6d8e33-fc81-faa0-ae61-386361a0383b.png)
「閲覧者」を「編集者」に変更して、
「リンクをコピー」をクリックして、どこかに保存しておく（後で「GASスクリプトファイルの作成」で使用する）
「完了」をクリックする。


## GASスクリプトファイルの作成
今回は他のメンバーにスクリプトを変更されたくないので、スプレッドシートとは別にスクリプトファイルを作成する。(アドレスのスプレッドシートは他のメンバーにも編集させたい)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/0f992c12-57a9-4dff-ede5-c464c193ff91.png)
作成したスクリプトに以下のコードを記載する。

```javascript:line.js
var CHANNEL_ACCESS_TOKEN = '';
var SHEET_NAME = 'シート1'  // 処理対象となるシート名
var TRANSFER_MAIL_ROW = 'A'  // 転送メールアドレスが記載されている列
// スプレッドシートのURLは
// https://docs.google.com/spreadsheets/d/XXXXXXX/edit
// のような形になっています。XXXXXXXの部分がIDになります。
// 名簿の「スプレッドシート」
var MEMBER_SPREADSHEET_ID = ''

// ブラウザでスクリプトのURLにアクセスすると、GETで通知が来る
function doGet(e) {
  return ContentService.createTextOutput("SUCCESS");
}

// LINE bot はPOSTで通知が来る
function doPost(e) {
  var reply_token= JSON.parse(e.postData.contents).events[0].replyToken;
  if (typeof reply_token === 'undefined') {
    return;
  }
  var user_message = JSON.parse(e.postData.contents).events[0].message.text;
  var mailAddressList = getMailAddressList();
    Logger.log(mailAddressList);
  var ret = sendEmail(mailAddressList, user_message)
  if (!ret) {
    return;
  }
  return ContentService.createTextOutput("SUCCESS");
}

function getMailAddressList() {
  var spreadsheet = SpreadsheetApp.openById(MEMBER_SPREADSHEET_ID);
  // スプレッドシートの「シート」を取得
  var sheet = spreadsheet.getSheetByName(SHEET_NAME);
  // 転送メールアドレス列のRangeを取得する
  var lastRow = sheet.getRange(TRANSFER_MAIL_ROW + ':' + TRANSFER_MAIL_ROW).getLastRow();
  var range = sheet.getRange(TRANSFER_MAIL_ROW + '2:' + TRANSFER_MAIL_ROW + String(lastRow)); // タイトル行を除いた列を指定
  // 転送メールアドレス配列の取得
  var values = range.getValues();
  var clean = values.filter(v => v[0]);  // 配列から空要素だけ削除
  Logger.log(clean);
  return clean;
}

// 無料のGoogleアカウントの場合、GASのメール送信回数は1日100通が上限。
function sendEmail(mailAddressList, user_message) {
  if (typeof mailAddressList === 'undefined') {
    Logger.log("sendEmail():typeof mailAddressList === 'undefined'");
    return false;
  }
  if (mailAddressList == null){
    Logger.log("sendEmail():mailAddressList == null");
    return false;
  }
  if (mailAddressList.length == 0) {
    Logger.log("sendEmail():mailAddressList == 0");
    return false;
  }
  const subject = 'LINEチャットからの転送';
  const body = `${user_message}`;
  const options = {name: 'ボット'};
  mailAddressList.forEach(function(key){
    const recipient = key; //送信先のメールアドレス
    GmailApp.sendEmail(recipient, subject, body, options);
  });
  return true;
}
```

スクリプト中に出現する以下の定義を自身の環境に合わせて更新すること。
- CHANNEL_ACCESS_TOKEN：先の説明「プロバイダとMessaging APIのチャネルを作成」で出てくるアクセストークンを指定する。
- MEMBER_SPREADSHEET_ID：先の説明「メールアドレススプレッドシートの作成」でコピーしたスプレッドシートのリンクアドレスからIDを指定する。


## GASスクリプトファイルのテスト
doPostをテストできればよいが、すぐには引数を処理できないのでパスする。(GAS向けのmockにJestと言うのがあるそうですが、今回はパスする。試しにテストしたらエラーになった。後のログにも出ている。)
アドレスの取得箇所だけテストする。
「関数を選択」から確認したい関数「getMailAddressList」を選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/b47a62a1-a51f-626c-b956-322b52825cf5.png)
「getMailAddressList」コードには以下のログ出力処理が記載されていた。
再生ボタンをクリックする。

```
Logger.log(clean);
```
※引数に見たい変数を指定しておけば、変数の値がログに出力される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/32b76a2f-b2e9-b128-11cb-2442aeaa270c.png)
メニュー[表示]-[ログ]を選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/3b024533-8418-b362-8e43-764fdfe2090c.png)
「Apps Scriptダッシュボード」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/6b5bb16e-60cb-0a3a-2c78-90766eab0848.png)
アドレスが二つ表示されており、問題なさそうなので、次に公開する。

## GASスクリプトファイルの公開
よくわからないが、
最新のエディタには公開ボタンが表示されていないので、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/f46bdf2d-69f4-9b08-ba41-bc5bdfefc43a.png)
「以前のエディタを使用」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/f6aa2f88-2f34-3ec5-7290-b07ed34d84ef.png)
メニュー「公開」から「ウェブアプリケーションとして導入...」を選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/2c51dff9-599e-d72c-85e8-e33c124bed2c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201344/d1f0b058-2994-bb1b-ad5f-fb06e83e680c.png)
以下の通り選び「更新」をクリックする。
- 「Project version」から「New」※
- 「Who has access to the app」から「Anyone, even anonymous」
※バージョンを更新するまでは、スクリプトを編集しても実際の動作には反映されない。

LINEでLINEボットとトークする。
適当なメッセージを送り、メールアドレスに転送メールが届けば成功となる。

ちなみに
画像を送ると、転送先にはメール本文が「undefined」で届いた。
(無料のGoogleアカウントは自動転送制限のため）一日に最大100通までしか転送されないらしい。
(LINEの無料利用枠のため)LINE ボットは一か月間に1000通までしかメッセージを処理できないらしい。


# おわりに
GAS素晴らしい。こんな簡単にLINEボットをデプロイできるとは思わなかった。
当たり前だがGoogleアプリとの連携が容易なので、今後もいろいろ活用していきたい。


# 関連リンク
## 参考サイト
[LINE Botをサーバーレスで開発！Google Apps ScriptとLINE Messaging APIを使ってチャットボットを作ってみた](https://devpixiv.hatenablog.com/entry/2016/11/14/150000)
[初心者でも簡単！Google Apps ScriptでGmailを操作してメールを送る方法](https://tonari-it.com/gas-gmail-sendemail/)
[GASのメール送信は実行上限に注意！残り回数確認と上限以上のメールを送る方法](https://auto-worker.com/blog/?p=2638#:~:text=%E7%84%A1%E6%96%99%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%AEGAS%E3%83%A1%E3%83%BC%E3%83%AB%E9%80%81%E4%BF%A1%E3%81%AF1%E6%97%A5100%E9%80%9A%E3%81%AE%E4%B8%8A%E9%99%90,-Google%20Apps%20Script&text=%E7%84%A1%E6%96%99%E3%81%AEGoogle%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81GAS%E3%81%AE%E3%83%A1%E3%83%BC%E3%83%AB%E9%80%81%E4%BF%A1,100%E9%80%9A%E3%81%8C%E4%B8%8A%E9%99%90%E3%81%A7%E3%81%99%E3%80%82)


## ドキュメント
[LINE Developersドキュメント](https://developers.line.biz/ja/docs/)
[Google Apps Script Reference](https://developers.google.com/apps-script/reference)