GASでSlack通知を自動送信する方法|Webhook連携の手順
スプレッドシートの更新やフォームの回答があるたびに、Slackを開いて手動で報告する。こうした作業を毎日繰り返していると、1回あたりは数十秒でも、月単位では無視できない時間になります。Google Apps Script(GAS)とSlackのIncoming Webhookを組み合わせれば、こうした通知作業をゼロにできます。この記事では、Webhook URLの取得からGASのコード実装、運用時に押さえておきたいエラー処理やセキュリティ対策まで、Slack通知の自動化に必要な手順を一つずつ解説します。
目次
GASとSlack Webhookで通知を自動化する仕組み
GASからSlackへ通知を送る仕組みは、Incoming Webhookという機能を使います。Incoming Webhookは、Slackが提供するURLに対してHTTPリクエスト(POST)を送信すると、指定したチャンネルにメッセージが投稿される仕組みです。
GASにはUrlFetchAppというHTTP通信用のクラスが標準で用意されています。このUrlFetchAppのfetchメソッドを使い、Webhook URLに対してJSON形式のペイロードをPOSTするだけで、Slackにメッセージを投稿できます。外部ライブラリのインストールやサーバーの構築は不要です。
全体の処理フロー
処理の流れを整理すると、次のようになります。
- Slackワークスペースの管理画面でIncoming Webhook Appを追加し、Webhook URLを発行する
- GASのスクリプトエディタにコードを書き、Webhook URLに対してPOSTリクエストを送る関数を作成する
- GASのトリガー機能で「スプレッドシート編集時」「フォーム送信時」「毎日○時」などの条件を設定する
- 条件が満たされると自動的にGASが起動し、Slackの指定チャンネルにメッセージが届く
この仕組みのメリットは、Google Workspaceの各アプリケーション(スプレッドシート、フォーム、カレンダーなど)と直接連携できる点にあります。GASはこれらのアプリケーションのデータに直接アクセスできるため、「スプレッドシートの特定セルの値が変わったら通知」「フォームの回答内容をそのまま通知」といった連携がコードだけで完結します。
Incoming WebhookとSlack APIの違い
Slackへの通知方法は、大きく分けてIncoming WebhookとSlack API(Web API)の2種類があります。用途に合わせて選ぶ必要がありますが、「決まったチャンネルにメッセージを送るだけ」であればIncoming Webhookで十分です。
| 比較項目 | Incoming Webhook | Slack Web API |
|---|---|---|
| セットアップ | URLを1つ取得するだけ | OAuth認証とスコープ設定が必要 |
| 送信先 | URL発行時に固定されたチャンネル | 任意のチャンネルやDMに動的に指定可能 |
| 機能範囲 | メッセージ投稿のみ | メッセージ投稿・ファイルアップロード・チャンネル操作など多機能 |
| 適した用途 | 定型通知・アラート・日報 | 双方向のやりとりが必要なBot開発 |
この記事では、導入のハードルが低く実務での利用頻度が高いIncoming Webhookを中心に解説します。
事前準備 ── Slack側でWebhook URLを取得する
GASのコードを書く前に、まずSlack側でWebhook URLを発行します。この作業はSlackのワークスペース管理者、またはアプリのインストール権限を持つメンバーが行えます。
手順1: Slack Appを作成する
Slack APIの公式サイト(api.slack.com/apps)にアクセスし、「Create New App」をクリックします。作成方法は「From scratch」を選択してください。App Nameには「GAS通知」など用途がわかる名前を入力し、通知を送りたいワークスペースを選択します。
手順2: Incoming Webhookを有効化する
作成したAppの設定画面で、左側メニューから「Incoming Webhooks」を選び、画面上部のトグルスイッチをONにします。
手順3: Webhook URLを発行する
「Add New Webhook to Workspace」ボタンをクリックすると、通知先のチャンネルを選択する画面が表示されます。投稿先のチャンネルを選んで「許可する」をクリックすると、Webhook URLが発行されます。
発行されるURLは以下の形式です。
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
このURLは認証情報そのものです。外部に漏洩すると、誰でもそのチャンネルにメッセージを投稿できてしまいます。URLの管理方法については後半のセキュリティの章で詳しく解説します。
GASでSlack通知を送る基本コード
Webhook URLを取得したら、GASのスクリプトエディタでコードを書いていきます。スプレッドシートの「拡張機能」メニューから「Apps Script」を開くか、script.google.comに直接アクセスしてプロジェクトを新規作成してください。
最小構成のコード
まずは動作確認用の最小コードです。このコードを実行して、Slackにメッセージが届くことを確認してください。
function sendSlackNotification() {
const webhookUrl = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK_URL');
const payload = {
text: 'GASからのテスト通知です。'
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
};
const response = UrlFetchApp.fetch(webhookUrl, options);
Logger.log(response.getContentText());
}
UrlFetchApp.fetchの戻り値であるHTTPResponseオブジェクトのgetContentTextメソッドを呼ぶと、正常に送信できた場合は「ok」という文字列が返ります。エラーの場合は「invalid_payload」などのエラーメッセージが返ります。
Webhook URLをスクリプトプロパティに保存する
上のコードでは、Webhook URLをソースコードに直接書かず、スクリプトプロパティから読み込んでいます。Webhook URLは認証情報に該当するため、コード内にハードコードするのは避けるべきです。
スクリプトプロパティの設定手順は次のとおりです。
- Apps Scriptエディタの左側メニューで歯車アイコン(プロジェクトの設定)をクリックする
- 画面下部の「スクリプトプロパティ」セクションで「スクリプトプロパティを追加」をクリックする
- プロパティ名に「SLACK_WEBHOOK_URL」、値にWebhook URLを貼り付けて保存する
これにより、コードをGitHubなどで共有する場合でもWebhook URLが漏洩するリスクを回避できます。
送信者名とアイコンをカスタマイズする
payloadオブジェクトに「username」と「icon_emoji」を追加すると、通知の送信者名とアイコンを変更できます。
const payload = {
text: '日次売上レポートを送信します。',
username: '売上レポートBot',
icon_emoji: ':bar_chart:'
};
ただし、この機能はSlack Appの設定で「Customize the name and icon」が有効になっている場合のみ動作します。Slack Appの管理画面で設定を確認してください。
業務自動化でできること100選
経理・人事・営業・CS・総務・ITの6部門100事例を収録。各事例に月間削減時間と導入難易度を明記。今日から始められるチェックリスト付き。
実務で使える応用パターン5選
基本の送信方法が理解できたら、実務で頻出するパターンを見ていきましょう。いずれもGASの標準機能だけで実装できます。
パターン1: スプレッドシートの更新をSlackに通知する
最も利用頻度が高いパターンです。スプレッドシートのonEditトリガーを使い、特定のセルが変更されたときにSlackへ通知を送ります。
function onEditNotification(e) {
const sheet = e.source.getActiveSheet();
const range = e.range;
// 「受注管理」シートのステータス列(C列)が変更された場合のみ通知
if (sheet.getName() !== '受注管理' || range.getColumn() !== 3) return;
const row = range.getRow();
const clientName = sheet.getRange(row, 1).getValue();
const projectName = sheet.getRange(row, 2).getValue();
const newStatus = range.getValue();
const message = `*ステータス更新*\n顧客: ${clientName}\n案件: ${projectName}\n新ステータス: ${newStatus}`;
sendToSlack(message);
}
function sendToSlack(text) {
const webhookUrl = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK_URL');
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({ text: text })
};
UrlFetchApp.fetch(webhookUrl, options);
}
onEditトリガーはGASの「編集時」イベントで発火します。シート名やカラム番号で条件を絞ることで、不要な通知を防げます。
パターン2: Googleフォームの回答をSlackに即時通知する
問い合わせフォームやアンケートの回答が届いたときに、Slackで即座にチームに共有するパターンです。
function onFormSubmit(e) {
const responses = e.namedValues;
let message = '*新しいお問い合わせ*\n';
for (const key in responses) {
message += `${key}: ${responses[key]}\n`;
}
sendToSlack(message);
}
このスクリプトはフォームに紐づくApps Scriptプロジェクトに配置し、「フォーム送信時」トリガーを設定します。e.namedValuesを使うと、フォームの質問名をキーとして回答を取得できるため、通知メッセージに質問と回答をそのまま含められます。
パターン3: 毎朝の日次レポートを定時送信する
スプレッドシートの集計結果を毎朝9時にSlackへ送信するパターンです。時間主導型トリガーを使います。
function sendDailyReport() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('売上サマリ');
const today = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd');
const totalSales = sheet.getRange('B2').getValue();
const orderCount = sheet.getRange('C2').getValue();
const message = `*${today} 日次レポート*\n売上合計: ${totalSales.toLocaleString()}円\n受注件数: ${orderCount}件`;
sendToSlack(message);
}
パターン4: エラー発生時にアラートを飛ばす
GASで別の自動処理(データ連携やファイル生成など)を動かしている場合、その処理がエラーで失敗したときにSlackへアラートを飛ばせると便利です。try-catchで例外を捕捉し、エラー情報をSlackに送ります。
function runDataSync() {
try {
// データ連携処理
syncExternalData();
} catch (error) {
const message = `*エラー発生*\n関数: runDataSync\nエラー: ${error.message}\nスタック: ${error.stack}`;
sendToSlack(message);
}
}
パターン5: 期限切れタスクを毎日チェックして通知する
スプレッドシートのタスク管理表を毎日チェックし、期限が今日または過ぎているタスクをSlackに通知するパターンです。
function checkDeadlines() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('タスク');
const data = sheet.getDataRange().getValues();
const today = new Date();
today.setHours(0, 0, 0, 0);
const overdueTasks = [];
for (let i = 1; i < data.length; i++) {
const taskName = data[i][0];
const deadline = new Date(data[i][2]);
const status = data[i][3];
deadline.setHours(0, 0, 0, 0);
if (status !== '完了' && deadline <= today) {
overdueTasks.push(`- ${taskName}(期限: ${Utilities.formatDate(deadline, 'Asia/Tokyo', 'MM/dd')})`);
}
}
if (overdueTasks.length > 0) {
const message = `*期限切れ・本日期限のタスク(${overdueTasks.length}件)*\n${overdueTasks.join('\n')}`;
sendToSlack(message);
}
}
Block Kit対応 ── 通知のデザインを整える
テキストだけの通知でも十分に機能しますが、Slackの「Block Kit」を使うと、見出し・区切り線・ボタンなどの視覚要素を含んだリッチなメッセージを送れます。通知の量が増えてきたときに情報の視認性を上げる手段として有効です。
Block Kitの基本構造
Block KitはJSON配列でメッセージのブロックを定義します。payloadの「blocks」プロパティに配列を渡すことで、複数のブロックを組み合わせたメッセージを構築できます。
function sendRichNotification() {
const webhookUrl = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK_URL');
const payload = {
blocks: [
{
type: 'header',
text: { type: 'plain_text', text: '月次売上レポート' }
},
{
type: 'section',
fields: [
{ type: 'mrkdwn', text: '*売上合計*\n1,250,000円' },
{ type: 'mrkdwn', text: '*前月比*\n+12.5%' }
]
},
{ type: 'divider' },
{
type: 'section',
text: { type: 'mrkdwn', text: '詳細はスプレッドシートをご確認ください。' },
accessory: {
type: 'button',
text: { type: 'plain_text', text: 'シートを開く' },
url: 'https://docs.google.com/spreadsheets/d/xxxxx'
}
}
]
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
};
UrlFetchApp.fetch(webhookUrl, options);
}
よく使うBlock Kitのブロックタイプ
| ブロックタイプ | 用途 | 使用例 |
|---|---|---|
| header | メッセージのタイトルを大きく表示する | 「月次レポート」「アラート」などの見出し |
| section | テキストやフィールドを表示する | 本文の表示、KPIの並列表示 |
| divider | 水平の区切り線を表示する | セクション間の視覚的な区切り |
| actions | ボタンやメニューを配置する | 「承認する」「確認する」ボタン |
| context | 補足情報を小さい文字で表示する | 送信日時、データソースの注記 |
Block Kitのレイアウトを視覚的に設計したい場合は、Slackが提供するBlock Kit Builderが便利です。画面上でブロックを配置しながらJSONを生成できるため、コードに手で書くよりも効率的に設計できます。
エラー処理とリトライの実装
GASからSlackへの通知は通常であれば安定して動作しますが、ネットワークの一時的な問題やSlack側の障害によって送信に失敗するケースがあります。特に業務の重要な通知に使う場合は、エラー処理とリトライの仕組みを入れておくと安心です。
HTTPステータスコードによるエラー判定
UrlFetchApp.fetchは、HTTPステータスコードが200以外の場合に例外をスローします。muteHttpExceptionsオプションをtrueに設定すると例外を抑制でき、ステータスコードを自分で判定できるようになります。
function sendToSlackWithRetry(text, maxRetries) {
maxRetries = maxRetries || 3;
const webhookUrl = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK_URL');
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({ text: text }),
muteHttpExceptions: true
};
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const response = UrlFetchApp.fetch(webhookUrl, options);
const statusCode = response.getResponseCode();
if (statusCode === 200) {
Logger.log('送信成功');
return true;
}
Logger.log('送信失敗 (試行 ' + attempt + '/' + maxRetries + '): ' + statusCode + ' - ' + response.getContentText());
if (attempt < maxRetries) {
Utilities.sleep(2000 * attempt); // 指数バックオフ風に待機
}
}
Logger.log('全リトライ失敗');
return false;
}
よく発生するエラーと対処法
| ステータスコード | 原因 | 対処法 |
|---|---|---|
| 400 | payloadのJSON形式が不正 | JSON.stringifyの結果をログで確認する |
| 403 | Webhook URLが無効化された | Slack Appの管理画面でWebhookが有効か確認する |
| 404 | Webhook URLが削除された | 新しいWebhook URLを再発行する |
| 429 | レート制限に該当した(1秒1リクエスト超過) | 送信間隔を空ける。バッチ処理の場合はUtilities.sleepを挟む |
| 500 | Slack側の障害 | 時間をおいてリトライする |
特に注意が必要なのは429(レート制限)です。Incoming Webhookは1秒あたり1リクエストが目安とされています。ループ処理で連続送信する場合はUtilities.sleep(1000)を挟んで、1秒以上の間隔を確保してください。
セキュリティとWebhook URLの管理
Incoming Webhookは手軽に使える反面、URLの管理を怠るとセキュリティリスクにつながります。Webhook URLを知っている人は、認証なしでそのチャンネルにメッセージを投稿できるためです。
Webhook URLの安全な管理方法
前述のとおり、GASのスクリプトプロパティに保存するのが基本です。加えて以下の点を守ることで、漏洩リスクを下げられます。
- ソースコードにWebhook URLを直接記述しない。スクリプトプロパティかGASのシークレットマネージャーを使う
- Webhook URLをメールやチャットで共有しない。必要な場合はSlack Appの管理画面のURLを案内し、権限のあるメンバーが自分で確認する
- Webhook URLを含むスクリプトファイルをGitHubなどのパブリックリポジトリにプッシュしない
- 使わなくなったWebhook URLはSlack Appの管理画面から削除する
チャンネルごとにWebhookを分ける
複数のチャンネルに通知を送る場合は、チャンネルごとに個別のWebhook URLを発行してください。1つのWebhook URLは1つのチャンネルに紐づく仕様のため、複数チャンネルへの通知にはそれぞれ別のURLが必要です。
スクリプトプロパティには複数の値を保存できるため、「SLACK_WEBHOOK_SALES」「SLACK_WEBHOOK_SUPPORT」のようにプロパティ名を分けて管理すると、コードの可読性も上がります。
定期的なURLのローテーション
長期間同じWebhook URLを使い続けると、退職者や異動者が過去のURLを保持している可能性があります。半年に1回程度、Webhook URLを再発行してスクリプトプロパティの値を更新することで、不正利用のリスクを低減できます。
トリガー設定で完全自動化する
ここまでのコードは手動で実行しても動作しますが、GASのトリガー機能を使うことで完全に自動化できます。トリガーには大きく分けて「イベント駆動型」と「時間主導型」の2種類があります。
イベント駆動型トリガー
スプレッドシートの編集やフォームの送信といったイベントをきっかけに関数を実行します。
| トリガー種別 | 発火タイミング | 適用例 |
|---|---|---|
| onEdit | スプレッドシートのセルが編集されたとき | ステータス変更通知 |
| onChange | 構造変更(行追加・シート追加)があったとき | 新規データ追加通知 |
| onFormSubmit | Googleフォームに回答が送信されたとき | 問い合わせ通知 |
時間主導型トリガー
指定した時間間隔や時刻で関数を実行します。日次レポートや定期チェックに使います。
トリガーの設定は、Apps Scriptエディタの左側メニューにある時計アイコン(トリガー)から行います。「トリガーを追加」をクリックし、実行する関数・イベントソース・時間を選択してください。
トリガー設定時の注意点
GASのトリガーにはいくつかの制限があります。実務で運用する前に把握しておくと、トラブルを防げます。
- 1つのプロジェクトに設定できるトリガーは最大20個です。通知の種類が多い場合は、1つの関数内で条件分岐するか、プロジェクトを分けてください
- GASの実行時間は1回あたり最大6分です。大量のデータを処理して通知する場合は、処理対象をページ分割するなどの工夫が必要です
- シンプルトリガー(function onEdit)ではUrlFetchAppが使えません。スプレッドシート編集時の通知にはインストーラブルトリガー(Apps Scriptエディタから設定)を使ってください
- 時間主導型トリガーで「毎日午前9時〜10時」を指定した場合、実際の実行時刻は9時00分〜9時59分のどこかになります。正確な秒単位の制御はできません
よくある質問
QIncoming Webhookは無料で使えますか。
Aはい、Incoming Webhookの利用自体に追加料金はかかりません。Slackの無料プラン・有料プランのどちらでも利用できます。ただし、無料プランでは過去のメッセージ閲覧に制限があるため、通知の履歴を長期間保持したい場合は有料プランの利用を検討してください。
Q1つのWebhook URLで複数のチャンネルに送信できますか。
Aいいえ、1つのWebhook URLは発行時に指定した1つのチャンネルに紐づきます。複数のチャンネルに通知を送りたい場合は、チャンネルごとにWebhook URLを発行し、スクリプトプロパティで個別に管理してください。
QGASの実行が「承認が必要です」と表示されて動きません。
AGASからUrlFetchAppなどの外部通信を行う関数を初めて実行する際に、Googleアカウントによる承認が必要になります。「権限を確認」をクリックし、Googleアカウントでログインして「許可」を選択してください。トリガーで自動実行する場合も、初回の手動実行時に承認を済ませておく必要があります。
QSlack側のレート制限はどのくらいですか。
AIncoming Webhookのレート制限は、1つのWebhook URLにつき1秒あたり1リクエストが目安です。短時間に大量のリクエストを送ると429エラーが返されます。ループ処理で複数の通知を送る場合はUtilities.sleep(1000)以上の待機を挟んでください。
Qメンション(@ユーザー名)を通知に含めるにはどうすればよいですか。
AIncoming Webhookのメッセージ内でメンションを送るには、表示名ではなくSlackのユーザーIDを使います。形式は <@U01XXXXXXX> です。ユーザーIDはSlackのプロフィール画面で確認できます。チャンネル全体への通知には <!channel> や <!here> を使用します。
まとめ
この記事のポイント
- GASのUrlFetchAppとSlack Incoming Webhookを組み合わせると、コードだけでSlack通知を自動化できる
- Webhook URLはスクリプトプロパティに保存し、ソースコードへの直接記述は避ける
- スプレッドシート編集・フォーム回答・定時実行など、GASのトリガー機能で用途に合わせた自動化が可能
- Block Kitを使うとリッチな通知メッセージを構築できる
- エラー時のリトライ処理とレート制限(1秒1リクエスト目安)への対応を入れておくと運用が安定する
- Webhook URLは定期的にローテーションし、不要になったURLは速やかに削除する
※本記事の情報は2026年4月時点のものです。