Google Chatは、Webhookを利用すればChatの画面以外からでもメッセージを送ることができます。
もちろん、Google Apps Scriptからもメッセージを送ることができるので、1. スプレッドシートのデータを元にしたメッセージをチャットに自動投稿したり、2. Googleフォームに回答が届いたらチャットに自動投稿する・・・ということも可能です。
この記事では、Google Apps ScriptとWebhookを使ったGoogle Chatへの投稿方法の基本と、上記1. 2. のサンプルを紹介します。
なお、記事執筆時点では、無料版のGoogleアカウントではWebhookは利用できませんでしたので、ご注意ください。
WebhookのURLを取得
Webhookを使ってチャットにメッセージを送信するには、WebhookのURLが必要です。
URLはGoogle Chatの画面で取得することができます。




以上で、WebhookのURLが取得できました。
GASからチャットに投稿する
続いて、Google Apps Scriptからメッセージを投稿してみます。
拡張機能メニューより、Apps Scriptを起動します。

あらかじめ入力されているコード(myFunction)を削除し、当記事のコードを貼り付けます。
貼り付け後、保存してください。

Google Workspaceのガイドのコードを(ほぼ)そのまま使ってみます。
2行目のURLは、先ほど取得したWebhookのURLに、9行目の”Hello from…”は、ご希望の文言に書き換えてください。
function sendToChat() {
const url = "https://chat.googleapis.com/v1/spaces/XXXXXXXXXXX/messages?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
const options = {
"method": "post",
"headers": {
"Content-Type": "application/json; charset=UTF-8"
},
"payload": JSON.stringify({
"text": "Hello from Apps Script!"
})
};
const response = UrlFetchApp.fetch(url, options);
}
▷実行で実行すればチャットにメッセージが投稿されます。
初回の実行時は、権限の承認が必要です。
「承認が必要です」というダイアログが表示されますので、権限を確認 をクリックします。
* この部分の解説画像は、他の記事から流用しているため、実際のものと若干異なる場合があります。

このスクリプトを使うGoogleアカウントを選択します。

(この画面が表示された場合のみ)左下の 詳細 をクリックします。

(この画面が表示された場合のみ)左下の プロジェクト名(安全ではないページ)に移動 をクリックします。

右下の 許可 をクリックします。


GASからスレッドを指定してチャットに投稿する
GASからGoogle Chatにメッセージを投稿する際、任意のthreadKeyを設定しておくと、あとからそのスレッドにwebhookを使って返信することができるようになります。
先ほどのコードを修正して、threadKeyを設定して投稿されるようにします。
たとえば、毎朝1つスレッドを立てて、同日中はそのスレッドにしか投稿しないというスクリプトの場合は、threadKeyに日付を指定すると簡単です。
サンプルとして、threadKeyに20230526のようなyyyyMMdd形式の日付を設定してみました。
function sendToChat() {
const url = "https://chat.googleapis.com/v1/spaces/XXXXXXXXXXX/messages?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
const threadKey = Utilities.formatDate(new Date(), "JST", "yyyyMMdd");
const options = {
"method": "post",
"headers": {
"Content-Type": "application/json; charset=UTF-8"
},
"payload": JSON.stringify({
"text": "Hello from Apps Script! with threadKey!"
})
};
const response = UrlFetchApp.fetch(
`${url}&threadKey=${threadKey}&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD`,
options
);
}
▷実行ボタンでチャットにメッセージを送信しました。
新しく送信したメッセージは、見た目は先ほどと変わりませんが、threadKeyを保持しているはずです。

そして、再度メッセージを送信してみます。
判別するために、メッセージを少し変えてから▷実行ボタンを押しました。
"payload": JSON.stringify({
"text": "Reply from Apps Script! with threadKey!"
})
前回のメッセージと同じthreadKeyを指定しているので、新たなスレッドが立つのではなく、既存のスレッドに返信する形でメッセージが投稿されます。
Google Chatの画面を見てみると、スレッドに返信する形で投稿されたことがわかります。

カード型のメッセージを投稿する
先ほどまでの、シンプルなテキストメッセージだけでなく、カード型のメッセージを投稿することもできます。

上図のカードを投稿したスクリプトは下記のとおりです。
function sendToChat() {
const url = "https://chat.googleapis.com/v1/spaces/XXXXXXXXXXX/messages?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
const options = {
"method": "post",
"headers": {
"Content-Type": "application/json; charset=UTF-8"
},
"payload": JSON.stringify({
"cardsV2": [
{
"cardId": "unique-card-id2",
"card": {
"header": {
"title": "ユーザー新規登録依頼",
"subtitle": "2023年5月28日 川田 新一(営業部)",
"imageUrl": "https://web-breeze.net/wp-content/uploads/2019/12/cropped-favicon-1.jpg"
},
"sections": [
{
"header": "申請内容",
"widgets": [
{
"textParagraph": {
"text": "5月末までに、以下のユーザーの新規登録をお願いいたします。"
}
},
{
"divider": {}
},
{
"decoratedText": {
"startIcon": { "knownIcon": "PERSON" },
"text": "山 智子",
},
},
{
"decoratedText": {
"startIcon": { "knownIcon": "EMAIL" },
"text": "yama@web-breeze.net",
}
},
{
"buttonList": {
"buttons": [
{
"text": "却下",
"onClick": {
"openLink": { "url": "https://example.com/reject" }
}
},
{
"text": "承認",
"onClick": {
"openLink": { "url": "https://example.com/approve" }
}
},
],
}
},
],
},
]
},
},
]
})
};
const response = UrlFetchApp.fetch(url, options);
}
結構細かく設定できるようになっているため、各パーツの詳細については割愛させていただきます。
詳細はGoogleの公式Docに記載されていますが、基本的な使い方は下記のとおりです。
- options > payloadには、cardsV2オブジェクトを格納します。
- cardsV2 > cardオブジェクトには、下記を含めることができます。
活用例: チームメンバーの勤務予定をチャットに毎朝自動投稿する
GAS、Webhookを使っての自動投稿の活用例として、毎朝、チームメンバーの勤務予定を自動投稿する方法を紹介します。
勤務予定表をスプレッドシートで作成する
前提として、下図のようなスプレッドシートの勤務表が使われているものとします。

スプレッドシートにスクリプトを追加する
Google Apps Scriptでこのシートを参照し、本日の勤務予定を取得してチャットに送信します。
勤務予定シートをもとにチャット投稿メッセージを作る関数createMessageを作成しました。
メッセージを送信するsendToChat関数は先ほどまでとほぼ同じですが、“text”へはcreateMessage関数の実行結果をセットするよう修正します。
function sendToChat() {
const url = "https://chat.googleapis.com/v1/spaces/XXXXXXXXXXX/messages?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
const options = {
"method": "post",
"headers": {
"Content-Type": "application/json; charset=UTF-8"
},
"payload": JSON.stringify({
"text": createMessage()
})
};
const response = UrlFetchApp.fetch(url, options);
}
function createMessage() {
// 「勤務予定」シートを取得
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('勤務予定');
// 本日の 0時 0分 0秒 0ミリ秒 のDateオブジェクトを作成
const today = new Date(new Date().setHours(0, 0, 0, 0));
// チャットに送信するメッセージ(1行目は <MM/dd 勤務予定> とする)。 **で囲うと太字になる
let message = `*<${today.getMonth() + 1}/${today.getDate()} 勤務予定>*`;
for (let col = 2; col <= sheet.getLastColumn(); col++) {
// 1行目が本日日付の列を探す
if (sheet.getRange(1, col).getValue().getTime() === today.getTime()) {
// 3行目から最終行まで、氏名と勤務予定を取得し、メッセージに追加する
for (let row = 3; row <= sheet.getLastRow(); row++) {
const name = sheet.getRange(row, 1).getValue();
const cellValue = sheet.getRange(row, col).getValue();
const plan = cellValue ? cellValue : '出勤';
message += '\n' + `${name}:\t${plan}`;
}
}
}
return message;
}
webhook関数を選択して▷実行します。(初回は権限の確認が必要です)
すると、期待どおりのメッセージがチャットに送信されました。

トリガーを設定する
毎日8時〜9時ごろ(土日を除く)にチャットに自動投稿されるよう、トリガーを作成します。


これで、月曜日の8時〜9時ごろにチャットに自動投稿するトリガーが作成できました。
同様の手順で、火曜日〜金曜日のトリガーも作成すればOKです。
(このスクリプトですと、祝日にも投稿されてしまいますが、そのあたりの処理は当記事の本旨とは離れてしまいますので割愛させていただきます。)
活用例: Googleフォームに回答が送信されたらチャットに自動投稿する
GAS、Webhookを使っての自動投稿の活用例として、お問合せフォーム(Googleフォーム)に問合せが届いたら、問合せ内容をチャットに投稿する例を紹介します。
Googleフォームでお問合せフォームを作成する
前提として、下図のようなお問合せフォーム(Googleフォーム)が使われているものとします。

フォームにスクリプトを追加する
フォームが作成できたら、スクリプトエディタを起動します。
右上の三点メニューから、スクリプトエディタを起動します。

あらかじめ入力されているコード(myFunction)を削除し、当記事のコードを貼り付けます。
貼り付け後、保存してください。

下記のスクリプトを貼り付け、▷実行ボタンを押し、権限の承認を行なってください。
function webhook(e) {
const url = "https://chat.googleapis.com/v1/spaces/XXXXXXXXXXX/messages?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
const options = {
"method": "post",
"headers": {
"Content-Type": "application/json; charset=UTF-8"
},
"payload": JSON.stringify({
"text": createMessage(e.response)
})
};
const response = UrlFetchApp.fetch(url, options);
Logger.log(response);
}
function createMessage(response) {
// 質問・回答およびメールアドレスを取得
const itemResponses = response.getItemResponses();
const respondentEmail = response.getRespondentEmail();
// チャットに送信するメッセージ。 **で囲うと太字になる
let message = '*フォームに問合せが届きました*';
// 回答した質問すべてのタイトル・回答を取得し、メッセージにセット
for (const itemResponse of itemResponses) {
const title = itemResponse.getItem().getTitle();
const response = itemResponse.getResponse();
message += '\n\n' + `${title}:\n${response}`;
}
// メッセージ末尾に返信先のメールアドレスを記載
message += '\n\n' + `返信先:\n${respondentEmail}`;
return message;
}
このスクリプトは、フォームから回答が送信された時に動作する前提のスクリプトになっているので、▷実行ボタンで実行するとエラーが発生します。
しかし、今回は権限の承認を行うことが目的なので問題ありません。
トリガーを設定する
フォームから問合せが送信された時にスクリプトが実行されるよう、トリガーを作成します。


これでトリガーの準備は完了です。
実際にフォームから問合せを送信してみると、チャットにメッセージが投稿されました。

コメント