Google Apps ScriptでLINEのMessaging APIを使ってメッセージを送信する

# 概要
タイトルの通りです。Messaging APIにはいくつかメッセージを送信する方法がありますがこの記事では、

- 単純なメッセージの送信
- Botがいるトークルーム（またはグループ）のメッセージに対する返信

の仕方について紹介します。

# 共通で必要なもの
Messaging APIの使用にはチャンネルトークンが必要です。
下記の公式ドキュメントか、その他記事を参照してください。
https://developers.line.biz/ja/docs/messaging-api/channel-access-tokens/#page-title

# 単純なメッセージの送信
公式ドキュメントではプッシュメッセージと呼ばれているメッセージの種類です。
公式ドキュメントをみることでどのようなリクエストによってメッセージを送信できるかわかります。
https://developers.line.biz/ja/reference/messaging-api/#send-push-message
## 必要なもの
宛先の指定のために以下のいずれかが必要です。

- userId
- groupId
- roomId

ユーザやグループ、チャットルームから送信されたメッセージを受信したときに見れるイベントオブジェクトの中にそれらは含まれています。
イベントオブジェクトは以下のような形になっています。
https://developers.line.biz/ja/reference/messaging-api/#webhook-event-objects

受信したイベントオブジェクトの中身をみる方法については一番最後のサンプルコードをご覧ください。
## 実際のコード
```js:コード.gs
// 「共通で必要なもの」で紹介したチャンネルトークンです。
// Google Apps Scriptの環境変数的なものに設定してから使います。
// 参考： https://qiita.com/0Delta/items/7d8303eebbff4062069e
const LINE_TOKEN = PropertiesService.getScriptProperties().getProperty("LINE_TOKEN");
const DEFAULT_DEST_ID = PropertiesService.getScriptProperties().getProperty("DEFAULT_DEST_ID");

// messages: 送信したい文字列の配列
// destID: userId, groupId, roomIdのいずれか
function sendMessages(messages, destID="") {
    if (!messages.length) return;
    if (!destID) destID = DEFAULT_DEST_ID;

    // 送信するテキストの配列を作成する
    const messages = [];
    messages.forEach(text => messages.push({ type: "text", text }));
    const postData = { to: destID, messages };

    const options = {
        "method": "post",
        "contentType": "application/json",
        "headers": {
            "Authorization": `Bearer ${LINE_TOKEN}`
        },
        "payload": JSON.stringify(postData)
    };
    UrlFetchApp.fetch("https://api.line.me/v2/bot/message/push", options);
}
```

# メッセージの返信
公式ドキュメントでは応答メッセージと呼ばれているメッセージの種類です。
公式ドキュメントをみることでどのようなリクエストによってメッセージを送信できるかわかります。
https://developers.line.biz/ja/reference/messaging-api/#send-reply-message
## 必要なもの
受信したメッセージに含まれている返信に必要なためのトークン（replyToken）が必要です。
https://developers.line.biz/ja/reference/messaging-api/#send-reply-message

ユーザやグループ、チャットルームから送信されたメッセージを受信したときに見れるイベントオブジェクトの中にそれらは含まれています。
イベントオブジェクトは以下のような形になっています。
https://developers.line.biz/ja/reference/messaging-api/#webhook-event-objects

受信したイベントオブジェクトの中身をみる方法については一番最後のサンプルコードをご覧ください。
## 実際のコード
```js:コード.gs
// 「共通で必要なもの」で紹介したチャンネルトークンです。
// Google Apps Scriptの環境変数的なものに設定してから使います。
// 参考： https://qiita.com/0Delta/items/7d8303eebbff4062069e
const LINE_TOKEN = PropertiesService.getScriptProperties().getProperty("LINE_TOKEN");

// messages: 送信したい文字列の配列
// replyToken: userId, groupId, roomIdのいずれか
function replyText(messages, replyToken) {
    if (!messages.length) return;
    if (!replyToken) return;

    // 送信するテキストの配列を作成する
    const messages = [];
    messages.forEach(text => messages.push({ type: "text", text }));
    const postData = { replyToken: replyToken, messages };

    const options = {
        "method": "post",
        "contentType": "application/json",
        "headers": {
            "Authorization": `Bearer ${LINE_TOKEN}`
        },
        "payload": JSON.stringify(postData)
    };
    UrlFetchApp.fetch("https://api.line.me/v2/bot/message/reply", options);
}
```

# サンプルコード
```js:コード.gs
const LINE_TOKEN = PropertiesService.getScriptProperties().getProperty("LINE_TOKEN");
const DEFAULT_DEST_ID = PropertiesService.getScriptProperties().getProperty("DEFAULT_DEST_ID");

// https://developers.line.biz/ja/reference/messaging-api/#send-reply-message
function replyText(messages, replyToken) {
    if (!messages.length) return;
    if (!replyToken) return;

    // 送信するテキストの配列を作成する
    const messages = [];
    messages.forEach(text => messages.push({ type: "text", text }));
    const postData = { replyToken: replyToken, messages };

    const options = {
        "method": "post",
        "contentType": "application/json",
        "headers": {
            "Authorization": `Bearer ${LINE_TOKEN}`
        },
        "payload": JSON.stringify(postData)
    };
    UrlFetchApp.fetch("https://api.line.me/v2/bot/message/reply", options);
}

// https://developers.line.biz/ja/reference/messaging-api/#send-push-message
function sendMessages(messages, destID="") {
    if (!messages.length) return;
    if (!destID) destID = DEFAULT_DEST_ID;

    // 送信するテキストの配列を作成する
    const messages = [];
    messages.forEach(text => messages.push({ type: "text", text }));
    const postData = { to: destID, messages };

    const options = {
        "method": "post",
        "contentType": "application/json",
        "headers": {
            "Authorization": `Bearer ${LINE_TOKEN}`
        },
        "payload": JSON.stringify(postData)
    };
    UrlFetchApp.fetch("https://api.line.me/v2/bot/message/push", options);
}

// Google Apps Scriptの公開URLにPOSTリクエストすると、自動的に"doPost"という関数が呼ばれます。
// 参考: https://developers.google.com/apps-script/guides/web
function doPost(e) {
    // GASでPOSTを受け取った時の中身
    const body = JSON.parse(e.postData.contents);
    // このbodyがMessaging APIのWebhookの中身
    // https://developers.line.biz/ja/reference/messaging-api/#webhook-event-objects

    // 以下のWebhookイベントオブジェクトの"events"というオブジェクトでイテレート
    // https://developers.line.biz/ja/reference/messaging-api/#webhook-event-objects
    const events = body.events;
    events.forEach(event => {
        // Botが友達追加された場合やグループに追加された場合に発生するイベント
        // DEFAULT_DEST_IDを自分のIDにしていれば、Webhookイベントオブジェクトの中身が見れる
        if (event.type == "join") {
            sendMessages([JSON.stringify(event)]);
            return;
        }
        if (event.type != "message") return;

        // 以下のようにしてWebhookイベントオブジェクトからIDを取得
        // const groupId = event.source.groupId;
        // const userId = event.source.userId;
        // const roomId = event.source.roomId;

        // 受信テキスト
        const text = event.message.text;
        const replyToken = event.replyToken;

        // 以下二行をコメントアウトして、自分でBotにメッセージを送れば、自分のIDがわかる。自分のIDをDEFAULT_DEST_IDにしておくとデバッグに便利
        // replyText([JSON.stringify(event)], replyToken);
        // return;
        
        replyText(["Thanks for your message!"], replyToken);
    });
}
```