※本記事はプロモーションを含みます
目次
スプレッドシートで毎日のデータ集計や顧客リストの更新を行ったあと、その処理完了をSlackへ送る自動化は、業務を効率化する上で非常に頻繁に作られる構成です。処理が終わったかどうかを何度もシートを開いて確認する無駄を省くので、チーム全体で更新のタイミングをリアルタイムに共有するためには、Webhookを使った通知機能が役立ちます。ただし、Web上のサンプルコードをそのままコピーするだけでは、送信失敗時に気づけなかったりします。というのは、コード内に直接Webhook URLを記述してセキュリティリスクを抱えたり、通信パラメータの指定ミスで予期せぬエラーを起こすといったトラブルが発生しがちだからです。なので、ここでは、現場で直面しやすい問題点とその回避策を整理しながら、安全かつ確実に通知を飛ばす仕組みを記述します。
UrlFetchApp.fetch で陥る contentType と payload の落とし穴
GASから外部のWebサービスへリクエストを送る場合、基本となるのは UrlFetchApp.fetch メソッドです。GAS Slack 通知 Webhook の連携を行う際もこのメソッドを使用します。ただし、ここで最もつまずきやすいのは options オブジェクト内で指定する contentType と payload の組み合わせです。
通常、SlackのWebhookに対してJSON形式のデータを送る場合、HTTPリクエストのヘッダーに application/json を明示しなければなりません。ただし、GASの UrlFetchApp.fetch では、payload にJavaScriptのオブジェクト(例えば {text: “完了しました”} など)をそのまま渡してしまうと、GAS側の仕様により自動的に application/x-www-form-urlencoded としてデータが送信されようとします。というのは、この挙動のズレが発生すると、Slack側は送られてきたペイロードを正しく解析できないからです。なので、Slack側は invalid_payload や no_text といったエラーレスポンスを返し、メッセージの投稿が失敗します。
また、contentType に application/json を明示的に指定していたとしても、payload 側に JSON.stringify を通していない生のオブジェクトを渡してしまうと、内部的な型ミスマッチやエンコード処理の不整合により、リクエスト自体が不正な形式になります。というのは、contentType を application/json に設定した場合は、必ず payload も文字列化されたJSONデータ(JSON.stringify の実行結果)に揃えなければならないからです。なので、この両者の整合性が崩れていると、GASの実行ログには HTTP Response Code 400 や 400 Bad Request が記録され、なぜメッセージが送信できないのか原因を特定するのに余計な時間を費やすことになります。
スプレッドシートの処理完了をSlackへ送る処理の実装
この処理は、スプレッドシート上で時間のかかるデータ加工や、夜間にタイマー実行される日次バッチ処理が正常に終了したタイミングで使用します。処理の末尾で通知関数を実行させます。なので、手動での確認作業を完全に無くすことができます。
ここで発生しやすいズレは、通知メッセージの文言だけに気を取られて、Webhookの接続先URLをコード内に直接文字列として書き込んでしまう点です。ただし、通知先のURLをコード内に直接記述すると、通知先のチャンネルを変更したいときに毎回コードを修正しなければならなくなります。というのは、プロジェクトを共有した際に第三者へ送信権限が漏洩するリスクも高まるからです。
なので、この問題を回避するために、WebhookのURLは必ず PropertiesService(スクリプトプロパティ)から動的に取得する構成にします。そして UrlFetchApp.fetch を呼び出す際には、contentType に “application/json” を指定し、payload には JSON.stringify でシリアライズしたオブジェクトを渡します。以下が、スプレッドシートの処理完了をSlackへ送る最小限かつ確実なコード例です。
const url = PropertiesService.getScriptProperties().getProperty("SLACK_WEBHOOK");
UrlFetchApp.fetch(url, {
method: "post",
contentType: "application/json",
payload: JSON.stringify({text: "日次集計が完了しました"})
});
上記のコードでは、まず PropertiesService.getScriptProperties().getProperty(“SLACK_WEBHOOK”) を呼び出し、安全に保存されたSlackのWebhook URLを取得しています。続いて UrlFetchApp.fetch の第2引数として設定オブジェクトを渡し、HTTPメソッドを “post”、contentType を “application/json” に指定しています。ただし、送信するメッセージ本体である {text: “日次集計が完了しました”} は、JSON.stringify によって正しくJSON文字列へと変換されてから payload に渡されます。なので、Slack側が要求する厳密なフォーマットを満たすことができ、通信エラーを起こさずにスプレッドシートの処理完了を通知できます。
プロパティサービスによる認証情報の保護とエラー送信の回避
GAS Slack 通知 Webhook の構成を作る上で、スクリプトプロパティを活用した認証情報の隠蔽は不可欠です。というのは、SlackのIncoming Webhook URLは、特定のチャンネルに対して認証なしで外部からメッセージを投稿できる権限を持っているため、パスワードと同等に厳重な管理が求められるからです。
コード内に直接URLを書き込む運用を行うと、Googleドライブ上でスプレッドシートの閲覧権限を持つ全員にURLが見えてしまいます。ただし、コードのバージョン履歴(改訂履歴)にもURLが残り続けるため、後からURLを消去したとしても安全とは言えません。なので、スクリプトプロパティを使用すれば、コード自体には鍵の情報が含まれないため、開発用アカウントと本番用アカウントでプロパティの値を変更するだけで、コードを書き換えることなく通知先を切り替えることも可能になります。
ただし、プロパティサービスを利用する際にも避けるべき落とし穴があります。スクリプトプロパティに設定したキー名(上記の例では “SLACK_WEBHOOK”)を打ち間違えたり、設定自体を忘れてスクリプトを実行した場合、getProperty メソッドは null を返します。なので、その状態で UrlFetchApp.fetch(null, …) が実行されると、GASは Invalid argument という例外を発行し、スクリプト全体の実行がその場で中断されます。というのは、本来であればスプレッドシート上のデータ集計自体は正常に完了しているにもかかわらず、最後の通知処理で発生したエラーのせいで、処理全体が失敗したかのように扱われてしまうからです。
なので、このズレを回避するには、UrlFetchApp.fetch を呼び出す直前に、取得したURLが正しい文字列であるかどうかを確認するチェック処理(ガード節)を挟むのが効果的です。URLが null や空文字であった場合は、ログ出力を行って処理を安全に抜けるか、あるいは try-catch ブロックで通信エラーを捕捉して、メインであるスプレッドシートの処理結果に悪影響を与えない構造にしておく必要があります。設定や書き方は、対象のコードで確認しましょう。
スプレッドシート側の例外処理とタイムアウトを考慮した通知設計
実務で運用を続けると、スプレッドシートのデータ件数が増大するにつれて、GASの実行時間制限に直面するケースが増えてきます。一般的なGoogleアカウントでは1回のリクエストの上限が6分に設定されており、大規模なセル操作や複雑な集計を行っている途中でタイムアウトが発生すると、コードの末尾に配置されたSlack通知まで処理が到達しません。なので、結果として「処理は途中で止まっているのに、エラー通知も完了通知も届かないため放置される」という最悪の状況に陥ります。
また、セルの値の取得失敗や、外部APIとの通信エラーなど、スプレッドシートの操作中に予期せぬ例外が発生した場合も同様です。というのは、通知コードを単に処理の最後に置いているだけでは、異常終了した際に何もアクションが起きず、トラブルの発見が遅れる原因になるからです。
なので、こうした運用上の不都合を回避するためには、集計や更新を行う主処理全体を try-catch ブロックで包み込む設計が必須となります。正常に最後まで処理が進んだ場合は「完了通知」を送信します。ただし、catch ブロックに捕獲された場合は発生したエラー内容を含めた「異常通知」をSlackに飛ばす仕組みを構築します。というのは、これにより、処理が正常に終わったのか、あるいは途中で落ちたのかをSlack上で即座に判別できるようになるからです。
さらに、ネットワークの一時的な不安定さによって UrlFetchApp.fetch 自体が失敗する可能性もゼロではありません。なので、送信処理を関数化し、エラーが発生した際には数秒のウェイトを置いて1〜2回再試行(リトライ)するロジックを組んでおくことで、通知の不達率を限りなくゼロに近づけることができます。スプレッドシートの自動化処理を単に動かすだけでなく、こうした堅牢な通知設計を施すことで、日常の業務運用における信頼性を大幅に高めることが可能になります。実際の動作は確認しましょう。

