GASでSlack・LINE通知を自動化|スプレッドシート更新を即通知する方法

しんたろ。

スプレッドシートが更新されたら自動でSlackやLINEに通知が届く仕組み、GASなら無料で作れます!コピペOKのコード付きで完全解説します。

この記事でわかること
  • GASからSlack・LINEに通知を送る仕組みと設定手順
  • Slack Incoming Webhook / LINE Messaging APIの取得方法
  • スプレッドシート更新時・フォーム回答時の自動通知コード
  • 定期レポート(日次・週次)の自動送信とトリガー設定
  • エラー対処・トラブルシューティングの実践ノウハウ
  • VBAとGASの外部通知機能の比較
Slack/LINE通知スクリプトの実行を体験してみよう!

「実行」ボタンを押すと、スプレッドシートの更新をトリガーにSlackやLINEへ通知を送るGASの動作をシミュレーション体験できます。

</> sendSlackMessage.gs
1function sendSlackMessage() { 2 const url = ‘https://hooks.slack.com/…’; 3 const message = ‘売上データが更新されました’; 4 5 const payload = { 6 text: message, 7 username: ‘GAS通知Bot’ 8 }; 9 10 UrlFetchApp.fetch(url, { 11 method: ‘post’, 12 payload: JSON.stringify(payload) 13 }); 14}
実行ログ ─ sendSlackMessage
14:00:01[INFO] Webhook URLに接続中…
14:00:02[INFO] payloadを送信: {“text”:”売上データが更新…”}
14:00:02[OK] Slack API レスポンス: 200 ok
14:00:02[DONE] Slack通知送信完了
G
GAS通知Bot 14:00
📢 売上データが更新されました
3月度 売上レポート
売上合計: ¥1,250,000
前月比: +12.3%
更新者: 田中太郎
</> sendLineMessage.gs
1function sendLineMessage() { 2 const token = ‘LINE_NOTIFY_TOKEN’; 3 const url = ‘https://notify-api.line.me/…’; 4 5 UrlFetchApp.fetch(url, { 6 method: ‘post’, 7 headers: { 8 Authorization: ‘Bearer ‘ + token 9 }, 10 payload: { message: msg } 11 }); 12}
実行ログ ─ sendLineMessage
14:00:01[INFO] LINE Notify APIに接続中…
14:00:02[INFO] Bearer認証でリクエスト送信
14:00:02[OK] LINE API レスポンス: 200 {“status”:200}
14:00:02[DONE] LINE通知送信完了
G
GAS通知Bot
🔔 売上データ更新通知

3月度の売上データが更新されました。
💲 売上合計: ¥1,250,000
📈 前月比: +12.3%
👤 更新者: 田中太郎

詳細はスプレッドシートを確認してください。
この記事の目次
  1. GASで通知を自動化するメリットと全体像
  2. Slack通知の設定方法
  3. LINEでExcelを気軽に学べる
  4. LINE Notify通知の設定方法
  5. 実践編|スプレッドシート更新時の自動通知
  6. 実践編|定期レポートの自動通知
  7. エラー対処とトラブルシューティング
  8. VBAとGASの通知機能比較
  9. よくある質問(FAQ)

GASで通知を自動化するメリットと全体像

スプレッドシートの更新確認やフォーム回答の把握を手動で行っていませんか?Google Apps Script(GAS)を使えば、SlackやLINEへの通知を完全自動化できます。サーバーもドメインも不要で、Googleアカウントさえあれば無料で構築できるのが最大の魅力です。

GASの基本がまだ不安な方は、まずGAS入門ガイドで全体像を把握しておくとスムーズに進められます。

GASで実現できる通知パターンは主に3つあります。

  • イベント駆動型: スプレッドシートの編集やフォーム送信をトリガーに即時通知
  • スケジュール型: 時間ベースのトリガーで定期レポートを自動送信
  • 条件型: データが閾値を超えたときだけアラート通知

Slack通知 vs LINE通知 — 用途別の使い分け

SlackとLINEはどちらもGASから通知を送れますが、適した用途が異なります。以下の表で使い分けを確認しましょう。

比較項目 Slack LINE
主な用途 チーム・業務連絡 個人・少人数への通知
メッセージ装飾 Block Kitでリッチ表現可 テキスト+画像+スタンプ
チャンネル指定 Webhook URL単位で指定 トークン発行先グループ
レート制限 1秒1メッセージ推奨 1時間1,000件(Notify)
費用 無料プランあり Messaging APIは無料枠あり

チームでの業務通知にはSlack、個人のスマホに素早くプッシュ通知を送りたい場合はLINEが適しています。もちろん、両方に同時通知する構成も可能です。

GAS通知の仕組み(Webhook/API連携)

GASから外部サービスに通知を送る仕組みは非常にシンプルです。UrlFetchApp.fetch()メソッドを使って、SlackやLINEが提供するWebhook URL(またはAPIエンドポイント)にHTTP POSTリクエストを送信します。

処理の流れは以下のとおりです。

  1. GASスクリプトが実行される(手動・トリガー・イベント)
  2. 通知メッセージをJSON形式で組み立てる
  3. UrlFetchApp.fetch()でWebhook URLにPOST送信
  4. Slack/LINEのサーバーがメッセージを受け取り、チャンネル/トークに配信

GASのメール自動送信機能と組み合わせれば、メール+チャット通知のハイブリッド運用も実現できます。詳しくはGASメール自動送信ガイドをご覧ください。

Slack通知の設定方法

Slack Incoming Webhookの取得手順

Slackに通知を送るためには、まずIncoming Webhook URLを取得する必要があります。以下の手順で進めてください。

  1. Slack APIにアクセスし、「Create New App」→「From scratch」を選択
  2. App Nameに任意の名前(例: GAS通知Bot)を入力し、通知先のワークスペースを選択
  3. 左メニューの「Incoming Webhooks」をクリックし、トグルを「On」に切り替え
  4. 「Add New Webhook to Workspace」をクリックし、通知先チャンネルを選択して「許可する」
  5. 生成されたWebhook URL(https://hooks.slack.com/services/T.../B.../xxx)をコピー
注意

Webhook URLは秘密情報です。GitHubなどの公開リポジトリにコミットしないでください。GASではスクリプトプロパティに保存するのが安全です。

GASからSlackにメッセージを送信するコード

Webhook URLを取得したら、以下のコードでSlackにメッセージを送信できます。

/**
 * Slackにシンプルなテキストメッセージを送信する
 * 事前にスクリプトプロパティ「SLACK_WEBHOOK_URL」にWebhook URLを設定してください
 */
function sendSlackMessage() {
  // スクリプトプロパティからWebhook URLを取得(セキュリティ対策)
  const webhookUrl = PropertiesService.getScriptProperties()
    .getProperty('SLACK_WEBHOOK_URL');

  // 送信するメッセージを組み立てる
  const payload = {
    text: '【スプレッドシート通知】データが更新されました',
    username: 'GAS通知Bot',
    icon_emoji: ':bell:'
  };

  // HTTP POSTリクエストの設定
  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload)
  };

  // Slackに送信
  const response = UrlFetchApp.fetch(webhookUrl, options);
  console.log('Slack送信結果: ' + response.getResponseCode());
}

スクリプトプロパティの設定方法: GASエディタの左メニュー「プロジェクトの設定」→「スクリプト プロパティ」で、プロパティ名をSLACK_WEBHOOK_URL、値にコピーしたWebhook URLを入力します。

リッチメッセージ(Block Kit)の送信

SlackのBlock Kitを使うと、ヘッダー・セクション・ボタンなどの構造化されたリッチメッセージを送信できます。業務通知では視認性が大幅に向上します。

/**
 * SlackにBlock Kit形式のリッチメッセージを送信する
 * セクション・フィールド・ボタンを含む構造化メッセージの例
 */
function sendSlackBlockKit() {
  const webhookUrl = PropertiesService.getScriptProperties()
    .getProperty('SLACK_WEBHOOK_URL');

  // Block Kit形式のペイロード
  const payload = {
    blocks: [
      {
        type: 'header',
        text: {
          type: 'plain_text',
          text: '📊 日次売上レポート',
          emoji: true
        }
      },
      {
        type: 'section',
        fields: [
          {
            type: 'mrkdwn',
            text: '*本日の売上:*\n¥1,234,567'
          },
          {
            type: 'mrkdwn',
            text: '*前日比:*\n+12.3% 📈'
          }
        ]
      },
      {
        type: 'section',
        fields: [
          {
            type: 'mrkdwn',
            text: '*受注件数:*\n45件'
          },
          {
            type: 'mrkdwn',
            text: '*平均単価:*\n¥27,435'
          }
        ]
      },
      {
        type: 'divider'
      },
      {
        type: 'actions',
        elements: [
          {
            type: 'button',
            text: {
              type: 'plain_text',
              text: 'スプレッドシートを開く'
            },
            url: 'https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit'
          }
        ]
      }
    ]
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload)
  };

  UrlFetchApp.fetch(webhookUrl, options);
  console.log('Block Kitメッセージを送信しました');
}

Block KitのレイアウトはBlock Kit Builderでプレビューしながら作成できます。JSONをコピーしてGASのペイロードに貼り付けるだけなので、デザイン調整も簡単です。

この操作でよくある疑問

Q: Slack Incoming Webhookが非推奨と聞きましたが、今から使っても大丈夫ですか?

A: Slackの「カスタムインテグレーション」は非推奨ですが、Slack App経由のIncoming Webhookは現在も公式にサポートされています。Slack Appを作成し、そこからWebhook URLを発行する方法なら問題なく利用できます。将来的な互換性の面でもこちらが推奨です。

筆者の実務Tips

Slack通知を導入する際、最初は全ての更新を通知していたのですが、1日50件以上の通知が飛んで「通知疲れ」が発生しました。そこで通知を「エラー発生時」「閾値超過時」「日次サマリー」の3種類に絞ったところ、チームの確認率が20%→85%に改善。通知は”本当に見てほしいもの”だけに厳選するのが成功のコツです。

期間限定でChatGPT✖︎Googleスプレットシートのコンテンツ配布中!

LINEでExcelを気軽に学べる

しんたろ。
しんたろ。
Excel歴10年以上 → アプリ開発者
Profile
大手メーカーに15年以上勤務。製造部門で海外拠点の立ち上げ支援や、現場責任者として採算管理・納期管理・設備オペレートを経験。 2023年にDX人材育成プログラム第1期生として活動後、現在は製造現場のスケジュール運用を支えるアプリの企画・開発をメインに活動中。工程表示表作成の内製化SaaSを構築し、年間1,300万円のコスト改善を実現。 Excelによる業務改善で年間240時間の残業削減を達成した経験を活かし、ブログやSNSでも情報発信しています。
プロフィールを読む

LINE Notify通知の設定方法

LINE Notifyは2025年3月末でサービス終了が発表されています。ここではLINE Messaging APIを使った代替方法も併せて紹介します。既存のLINE Notify実装からの移行にも対応できる内容です。

LINE Notifyトークンの取得手順

LINE Messaging APIの設定手順(LINE Notify終了後の推奨方法):

  1. LINE Developersにログインし、新しいプロバイダーを作成
  2. 「Messaging API」チャンネルを新規作成
  3. チャンネルアクセストークン(長期)を発行
  4. 作成されたBotアカウントを友だち追加またはグループに招待
  5. チャンネルアクセストークンとユーザーID(またはグループID)をGASのスクリプトプロパティに保存

GASからLINE Notifyにメッセージを送信するコード

以下のコードはLINE Messaging APIを使った送信例です。LINE Notify終了後も動作する方法です。

/**
 * LINE Messaging APIでテキストメッセージを送信する
 * スクリプトプロパティに以下を設定:
 *   LINE_CHANNEL_TOKEN: チャンネルアクセストークン
 *   LINE_USER_ID: 送信先のユーザーID(またはグループID)
 */
function sendLineMessage() {
  const token = PropertiesService.getScriptProperties()
    .getProperty('LINE_CHANNEL_TOKEN');
  const userId = PropertiesService.getScriptProperties()
    .getProperty('LINE_USER_ID');

  const url = 'https://api.line.me/v2/bot/message/push';

  // 送信するメッセージ
  const payload = {
    to: userId,
    messages: [
      {
        type: 'text',
        text: '【スプレッドシート通知】\nデータが更新されました\n\n更新日時: ' +
              Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss')
      }
    ]
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': 'Bearer ' + token
    },
    payload: JSON.stringify(payload)
  };

  const response = UrlFetchApp.fetch(url, options);
  console.log('LINE送信結果: ' + response.getResponseCode());
}

画像・スタンプ付きの通知送信

LINE Messaging APIでは、テキスト以外にも画像やスタンプを送信できます。業務通知にグラフ画像を添付する場合に便利です。

/**
 * LINEに画像付きメッセージとスタンプを送信する
 * 画像はURLで指定(Googleドライブの共有リンクなども利用可能)
 */
function sendLineRichMessage() {
  const token = PropertiesService.getScriptProperties()
    .getProperty('LINE_CHANNEL_TOKEN');
  const userId = PropertiesService.getScriptProperties()
    .getProperty('LINE_USER_ID');

  const url = 'https://api.line.me/v2/bot/message/push';

  const payload = {
    to: userId,
    messages: [
      // テキストメッセージ
      {
        type: 'text',
        text: '📊 本日の売上レポートです'
      },
      // 画像メッセージ(グラフのスクリーンショットなど)
      {
        type: 'image',
        originalContentUrl: 'https://example.com/chart-full.png',
        previewImageUrl: 'https://example.com/chart-preview.png'
      },
      // スタンプメッセージ(任意)
      {
        type: 'sticker',
        packageId: '11537',
        stickerId: '52002734'
      }
    ]
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': 'Bearer ' + token
    },
    payload: JSON.stringify(payload)
  };

  UrlFetchApp.fetch(url, options);
  console.log('画像付きLINEメッセージを送信しました');
}

画像URLにはHTTPSのアクセス可能なURLを指定します。Googleドライブの場合は共有設定を「リンクを知っている全員」に変更し、https://drive.google.com/uc?id=FILE_ID形式で指定してください。

実践編|スプレッドシート更新時の自動通知

ここからは、スプレッドシートのイベントと連動した実践的な自動通知の実装を解説します。Googleフォームとの連携についてはGASフォーム連携ガイドも参考にしてください。

特定セルの変更を検知して通知

onEdit(e)トリガーを使えば、特定のセルが編集されたときだけ通知を送ることができます。以下は「ステータス」列が変更されたらSlackに通知するコードです。

/**
 * 特定セルの変更を検知してSlackに通知する
 * onEditトリガーで自動実行される
 * 対象: 「ステータス」列(D列)が変更されたとき
 */
function onEdit(e) {
  const sheet = e.source.getActiveSheet();
  const range = e.range;

  // 対象シートとD列(ステータス列)のみ処理
  if (sheet.getName() !== '案件管理' || range.getColumn() !== 4) return;

  const row = range.getRow();
  const newValue = e.value;
  const oldValue = e.oldValue || '(空欄)';

  // 案件名(B列)を取得
  const projectName = sheet.getRange(row, 2).getValue();

  // Slackに通知
  const webhookUrl = PropertiesService.getScriptProperties()
    .getProperty('SLACK_WEBHOOK_URL');

  const payload = {
    text: '📝 *ステータス変更通知*\n' +
          '案件名: ' + projectName + '\n' +
          '変更内容: ' + oldValue + ' → ' + newValue + '\n' +
          '変更者: ' + Session.getActiveUser().getEmail() + '\n' +
          '更新日時: ' + Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm')
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload)
  };

  UrlFetchApp.fetch(webhookUrl, options);
}
ポイント

onEdit(e)はシンプルトリガーのため、UrlFetchAppを使う場合はインストール可能トリガーとして設定する必要があります。GASエディタの「トリガー」から「編集時」にonEdit関数を登録してください。

新しい行の追加を検知して通知

フォーム回答やデータ追加で新しい行が増えたことを検知して通知するパターンです。スクリプトプロパティに前回の行数を記録して差分を検出します。

/**
 * 新しい行の追加を検知してSlack・LINE両方に通知する
 * 時間ベースのトリガー(1分おき等)で定期実行する
 */
function checkNewRows() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName('回答一覧');
  const currentLastRow = sheet.getLastRow();

  // 前回チェック時の最終行を取得
  const props = PropertiesService.getScriptProperties();
  const previousLastRow = parseInt(props.getProperty('LAST_ROW') || '1');

  // 新しい行がなければ終了
  if (currentLastRow <= previousLastRow) return;

  // 新しい行のデータを取得
  const newData = sheet.getRange(
    previousLastRow + 1, 1,
    currentLastRow - previousLastRow,
    sheet.getLastColumn()
  ).getValues();

  // 通知メッセージを組み立て
  let message = '🆕 新しい回答が ' + newData.length + '件 追加されました\n\n';
  newData.forEach(function(row, i) {
    message += '【回答' + (i + 1) + '】' + row[1] + ' / ' + row[2] + '\n';
  });

  // Slackに送信
  sendToSlack(message);
  // LINEにも送信
  sendToLine(message);

  // 最終行を更新
  props.setProperty('LAST_ROW', String(currentLastRow));
}

/** Slack送信の共通関数 */
function sendToSlack(message) {
  const webhookUrl = PropertiesService.getScriptProperties()
    .getProperty('SLACK_WEBHOOK_URL');
  UrlFetchApp.fetch(webhookUrl, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({ text: message })
  });
}

/** LINE送信の共通関数 */
function sendToLine(message) {
  const token = PropertiesService.getScriptProperties()
    .getProperty('LINE_CHANNEL_TOKEN');
  const userId = PropertiesService.getScriptProperties()
    .getProperty('LINE_USER_ID');
  UrlFetchApp.fetch('https://api.line.me/v2/bot/message/push', {
    method: 'post',
    contentType: 'application/json',
    headers: { 'Authorization': 'Bearer ' + token },
    payload: JSON.stringify({
      to: userId,
      messages: [{ type: 'text', text: message }]
    })
  });
}

条件付き通知(閾値超過アラート)

在庫数が基準値を下回ったときや、売上目標を達成したときなど、条件を満たした場合だけ通知するパターンです。不要な通知を減らして、本当に重要なアラートだけを受け取れます。

/**
 * 在庫数が閾値を下回ったらアラート通知を送信する
 * 時間ベースのトリガーで定期チェック
 */
function checkThresholdAlert() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName('在庫管理');
  const data = sheet.getDataRange().getValues();
  const header = data[0]; // ヘッダー行

  // 閾値を下回った商品を収集
  const alerts = [];
  for (let i = 1; i < data.length; i++) {
    const productName = data[i][0]; // A列: 商品名
    const stock = data[i][2];       // C列: 現在在庫
    const threshold = data[i][3];   // D列: 発注点

    if (stock <= threshold) {
      alerts.push({
        name: productName,
        stock: stock,
        threshold: threshold
      });
    }
  }

  // アラートがなければ終了
  if (alerts.length === 0) return;

  // 通知メッセージを組み立て
  let message = '⚠️ *在庫アラート* — ' + alerts.length + '件の商品が発注点以下です\n\n';
  alerts.forEach(function(item) {
    message += '• ' + item.name +
               ': 在庫 *' + item.stock + '個*(発注点: ' + item.threshold + '個)\n';
  });

  sendToSlack(message);
}
この操作でよくある疑問

Q: onEditトリガーで通知を送ると、自分の編集でも通知が来てしまいます。除外する方法は?

A: イベントオブジェクトのe.user.emailで編集者を判定し、自分のアドレスと一致する場合はreturnで早期終了させるのが定番です。また、特定のシートや列だけを監視対象にするフィルター条件を入れると、不要な通知をさらに減らせます。

筆者の実務Tips

在庫管理の閾値アラートを導入した倉庫では、欠品率が月平均8%→1.2%に改善しました。ポイントは、閾値をスプレッドシート上の「設定」シートで管理し、商品ごとに個別設定できるようにしたこと。季節商品は閾値を高めに設定するなど、現場の担当者がコード修正なしで調整できる仕組みにしたのが運用定着の鍵でした。

実践編|定期レポートの自動通知

日次サマリーの自動送信

毎日決まった時刻に売上サマリーをSlackに自動送信するコードです。時間ベースのトリガーで毎朝9時に実行する設定と組み合わせます。

/**
 * 日次売上サマリーをSlackに送信する
 * 時間主導型トリガーで毎日9:00に実行
 */
function sendDailySummary() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName('売上データ');
  const data = sheet.getDataRange().getValues();

  // 本日の日付(時間部分をリセット)
  const today = new Date();
  today.setHours(0, 0, 0, 0);

  // 本日分のデータを集計
  let totalSales = 0;
  let orderCount = 0;

  for (let i = 1; i < data.length; i++) {
    const rowDate = new Date(data[i][0]); // A列: 日付
    rowDate.setHours(0, 0, 0, 0);

    if (rowDate.getTime() === today.getTime()) {
      totalSales += data[i][3]; // D列: 売上金額
      orderCount++;
    }
  }

  // 前日データ(比較用)
  const yesterday = new Date(today);
  yesterday.setDate(yesterday.getDate() - 1);
  let yesterdaySales = 0;

  for (let i = 1; i < data.length; i++) {
    const rowDate = new Date(data[i][0]);
    rowDate.setHours(0, 0, 0, 0);
    if (rowDate.getTime() === yesterday.getTime()) {
      yesterdaySales += data[i][3];
    }
  }

  // 前日比の計算
  const diff = yesterdaySales > 0
    ? ((totalSales - yesterdaySales) / yesterdaySales * 100).toFixed(1)
    : '—';
  const diffEmoji = diff > 0 ? '📈' : (diff < 0 ? '📉' : '➡️');

  // Block Kitメッセージを送信
  const webhookUrl = PropertiesService.getScriptProperties()
    .getProperty('SLACK_WEBHOOK_URL');

  const payload = {
    blocks: [
      {
        type: 'header',
        text: {
          type: 'plain_text',
          text: '📊 日次売上サマリー(' +
                Utilities.formatDate(today, 'Asia/Tokyo', 'M/d') + ')',
          emoji: true
        }
      },
      {
        type: 'section',
        fields: [
          { type: 'mrkdwn', text: '*売上合計:*\n¥' + totalSales.toLocaleString() },
          { type: 'mrkdwn', text: '*受注件数:*\n' + orderCount + '件' }
        ]
      },
      {
        type: 'section',
        fields: [
          { type: 'mrkdwn', text: '*前日比:*\n' + diff + '% ' + diffEmoji },
          { type: 'mrkdwn', text: '*平均単価:*\n¥' +
            (orderCount > 0 ? Math.round(totalSales / orderCount).toLocaleString() : '0') }
        ]
      },
      { type: 'divider' },
      {
        type: 'context',
        elements: [
          { type: 'mrkdwn', text: '自動送信 | ' +
            Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm') }
        ]
      }
    ]
  };

  UrlFetchApp.fetch(webhookUrl, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload)
  });

  console.log('日次サマリーを送信しました');
}

週次レポートの自動生成と通知

週次レポートでは、1週間分のデータを集計して曜日別の傾向やトップ商品を含めた詳細なサマリーを送信します。日次サマリーのコードを拡張し、getDay()で曜日別集計を追加する形で実装できます。

週次トリガーは「毎週月曜日の9時」に設定するのが一般的です。集計対象期間は前週の月曜日から日曜日までとしましょう。

トリガー設定のベストプラクティス

GASのトリガーを適切に設定することで、安定した自動通知を実現できます。

通知パターン 推奨トリガー 注意点
セル変更通知 インストール可能な「編集時」 シンプルトリガーではUrlFetchApp不可
新規行チェック 時間主導型(1〜5分おき) 実行時間制限(6分/回)に注意
日次レポート 時間主導型(特定時刻) 指定時刻の±15分で実行される
週次レポート 時間主導型(毎週特定曜日) 祝日チェックを追加すると便利
閾値アラート 時間主導型(5〜15分おき) 連続通知防止のフラグ管理が必要

トリガーの総数制限: 1つのプロジェクトで設定できるトリガーは最大20個です。不要なトリガーは定期的に整理しましょう。

エラー対処とトラブルシューティング

「UrlFetchApp呼び出しに失敗しました」エラー

このエラーは以下の原因で発生します。

  • Webhook URLが間違っている: コピペミスや末尾の空白がないか確認
  • ネットワークエラー: Slack/LINEのサーバーが一時的にダウンしている場合。try-catchでリトライ処理を入れる
  • 権限不足: シンプルトリガー(onEdit)からUrlFetchAppを呼んでいる場合。インストール可能トリガーに変更する
  • リクエスト上限: 無料アカウントは1日20,000回まで。超過するとエラーになる

安全なリトライ処理の実装例:

/**
 * リトライ機能付きのHTTPリクエスト送信
 * 一時的なエラーに対して最大3回リトライする
 */
function fetchWithRetry(url, options, maxRetries) {
  maxRetries = maxRetries || 3;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = UrlFetchApp.fetch(url, options);
      return response; // 成功したらレスポンスを返す
    } catch (error) {
      console.log('送信失敗(' + attempt + '/' + maxRetries + '回目): ' + error.message);

      if (attempt === maxRetries) {
        // 最大リトライ回数に達した場合はメールで通知
        MailApp.sendEmail(
          Session.getActiveUser().getEmail(),
          '【GAS通知エラー】送信に失敗しました',
          'エラー内容: ' + error.message + '\nURL: ' + url
        );
        throw error;
      }

      // 次のリトライまで待機(指数バックオフ)
      Utilities.sleep(1000 * Math.pow(2, attempt));
    }
  }
}

Webhook URLの無効化・期限切れ対策

Slack Webhook URLが突然動かなくなる原因と対策をまとめます。

  • Appが削除された: Slack管理者がAppを削除するとWebhookも無効になる。Appの管理権限を確認
  • チャンネルがアーカイブされた: 通知先チャンネルがアーカイブされると送信不可。別チャンネルにWebhookを再設定
  • セキュリティ対策で無効化: URLが漏洩した場合、管理者がWebhookを無効化することがある。新しいWebhookを再発行

予防策として、送信処理のレスポンスコードをチェックし、200以外が返ったらメール通知で管理者に知らせる仕組みを入れておくと安心です。

LINE Notifyのレート制限と対策

LINE Messaging APIにもレート制限があります。無料プラン(コミュニケーションプラン)では月200通までのプッシュメッセージが送信可能です。

  • 通知の重複を防ぐため、送信済みフラグをスクリプトプロパティで管理する
  • 複数の通知をまとめて1通にバッチ送信する
  • 重要度の低い通知はSlack側に回してLINEの通数を節約する

VBAとGASの通知機能比較

Excel VBAでもSlack通知は可能ですが、GASと比べると実装の手軽さや運用性に大きな差があります。

VBAでSlack通知を送るコード例

VBAからSlackに通知を送るには、MSXML2.XMLHTTPオブジェクトを使用します。

' VBAからSlackにメッセージを送信する
' 参照設定: Microsoft XML, v6.0 が必要
Sub SendSlackFromVBA()
    Dim http As Object
    Set http = CreateObject("MSXML2.XMLHTTP")

    Dim webhookUrl As String
    webhookUrl = "https://hooks.slack.com/services/T.../B.../xxx"

    Dim payload As String
    payload = "{""text"":""【Excel通知】VBAからのテスト送信です""}"

    http.Open "POST", webhookUrl, False
    http.setRequestHeader "Content-Type", "application/json"
    http.Send payload

    If http.Status = 200 Then
        MsgBox "Slackに送信しました", vbInformation
    Else
        MsgBox "送信失敗: " & http.Status & " " & http.statusText, vbCritical
    End If

    Set http = Nothing
End Sub

GASとVBAの外部通知比較表

比較項目 GAS Excel VBA
HTTP通信 UrlFetchApp(標準搭載) MSXML2.XMLHTTP(参照設定が必要)
自動実行 トリガーで24時間稼働 Excelを開いている間のみ
スケジュール実行 時間主導型トリガーで簡単 タスクスケジューラとの連携が必要
JSON処理 JSON.stringify/parseで簡単 文字列結合または外部ライブラリ
環境依存 ブラウザのみ(OS不問) Windows + Excel必須
セキュリティ スクリプトプロパティで安全管理 ソースコード内にURL直書きになりがち
おすすめシーン クラウド型の自動通知全般 社内PCからの手動実行

自動通知の用途ではGASが圧倒的に有利です。VBAはExcelを閉じると実行できませんが、GASはGoogleのサーバー上で24時間365日トリガー実行されるため、通知の取りこぼしがありません。

よくある質問(FAQ)

Q. LINE Notifyは2025年3月で終了しませんか?

LINE Notifyは2025年3月末でサービス終了が発表されています。代替としてLINE Messaging APIの利用を推奨します。本記事ではLINE Messaging APIの方法も紹介しています。

Q. SlackのWebhook URLが漏洩した場合のリスクは?

第三者がそのWebhook URLを使って任意のメッセージを送信できるリスクがあります。漏洩した場合は即座にWebhookを無効化し、新しいURLを再発行してください。スクリプトプロパティに保存し、コードに直書きしないことが予防策です。

Q. GASの通知にタイムラグはありますか?

トリガー実行は通常1〜30秒で開始されます。UrlFetchAppの外部API呼び出しは数秒程度です。時間主導型トリガーは指定時刻の前後15分程度のずれが生じることがあるため、秒単位の正確性が必要な用途には向きません。

Q. 1つのGASスクリプトからSlackとLINE両方に通知できますか?

はい、1つのfunction内でSlackとLINEの両方にUrlFetchAppで送信できます。本記事の「新しい行の追加を検知して通知」セクションで、両方への同時通知コードを紹介しています。

Q. Discord通知もGASでできますか?

はい、DiscordもWebhook URLに対してUrlFetchAppでPOSTすれば通知可能です。Slackとほぼ同じ実装方法です。ペイロードのtextキーをcontentに変更するだけで動作します。


まとめ
  • Slack通知: Incoming Webhookを取得し、UrlFetchApp.fetch()でJSON形式でPOST送信
  • LINE通知: LINE Messaging APIのチャンネルアクセストークンを使い、プッシュメッセージで送信
  • 自動通知: onEditトリガーでセル変更検知、時間主導型トリガーで定期レポートを実現
  • エラー対策: リトライ処理・レスポンスチェック・メール通知のフォールバックを実装
  • VBAとの違い: GASはサーバーレスで24時間稼働、VBAはExcel起動中のみ。通知自動化にはGASが最適

GASによる通知自動化は、一度設定すれば手間なく運用できるのが最大のメリットです。まずはSlackの基本送信から試して、徐々に条件通知や定期レポートへと拡張していきましょう。

GAS・業務自動化
その手作業、自動化しませんか?

GAS通知設定・Slack/LINE連携・定期レポート自動化まで、
業務に合わせた最適な自動化をご提案します。

1,600部ツール販売実績
15年製造業の業務経験
無料で相談する →
初回相談無料・お見積りだけでもOK

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT ME
しんたろ。
しんたろ。
Excel歴10年以上 → アプリ開発者
大手メーカーに15年以上勤務。製造部門で海外拠点の立ち上げ支援や、現場責任者として採算管理・納期管理・設備オペレートを経験。 2023年にDX人材育成プログラム第1期生として活動後、現在は製造現場のスケジュール運用を支えるアプリの企画・開発をメインに活動中。工程表示表作成の内製化SaaSを構築し、年間1,300万円のコスト改善を実現。 Excelによる業務改善で年間240時間の残業削減を達成した経験を活かし、ブログやSNSでも情報発信しています。
記事URLをコピーしました