[Flows100本ノック] FlowsからSlackに連携するためのGoogle Apps Scriptを開発してみた

 2025.12.01 Yudai Imai

はじめに

本記事は、Google Workspace Flowsの実践ノウハウを100本紹介する連載「Google Workspace Flows活用方法100本ノック」の一つとなります。  

今回は、FlowsからSlackへ直接メッセージを送れないという制約を解消するために、Google Apps Script(GAS)でSlack Bot経由の送信エンドポイントを自作し、Flowsから呼び出す方法を紹介します。社内でGoogle Workspaceを使いつつSlackも併用しているチームにとって、通知経路を一本化できる実用的なアプローチです。

難易度 中級者向け
実現すること FlowsからWebhook的にGASを呼び出し、Slack Bot経由でメッセージを投稿することで経路を一本化することができます
想定する対象者 Google Workspace中心だがSlackも併用しており、Flowsで作った自動化をSlackに届けたいチーム
利用サービス Google Apps Script、Slack

ユースケース

今回作成するフローの代表的なユースケースとしては以下のようなことが考えられると思います。

  • ハイブリッド通知の一元化
    • 社内の申請承認フローをFlowsで自動化し、その結果をSlackへも投稿できます。Slack中心で情報を確認しているメンバーへ即時展開することができます。
  • 障害・アラート連携
    • Google Workspace内の監視や異常検知をFlowsで捕捉し、重要アラートはSlackの専用チャンネルにも通知できます。
  • 営業活動の成果共有
    • GmailやSheetsで更新されたファイル状況をFlowsで拾い、Slackのチームチャンネルへ速報で連携できます。Slackに常駐するメンバーのモチベーション向上につなげられます。

前提条件

今回のフローを作成するための前提条件は以下となります。Google Workspace Flowsは2025年12月時点ではGemini Alphaプログラムのユーザーのみが利用できるサービスかつまだ提供されて間もないため、このブログの内容が最新ではなくなる可能性があることをご了承ください。
  • 利用環境:Google Workspace Flows(Gemini Alphaプログラム対象テナントで提供)にアクセスできるユーザーであること。
  • 利用アプリ:Google Apps Scriptが利用できること。Slack Botについても知識が既にあり、利用できるBotが存在していること。

構築手順

今回のブログではGoogle Apps Scriptの構築の概要については説明しません。もしGoogle Apps Scriptの構築について詳しく知りたい場合はGoogleの公式ドキュメントなどを確認するようにされてください。

また、SlackのBotについても詳しい説明はしません。すでにSlack Botが用意されており適切な権限を持っていること、そしてSlack Botがメッセージを送りたいチャンネルのIDも知っていることを前提に進めさせていただきます。

まずは、Google Apps Scriptのサイトにアクセスしてください。そして、新しいプロジェクトを作成して適当な名前をつけてください。今回は「Slack連携」という名前を付けました。

そして、サイドメニューの歯車ボタンから設定画面にアクセスして、全般設定の中の「「appsscript.json」マニフェスト ファイルをエディタで表示する」のチェックボタンにチェックを入れてください。

設定が完了したらエディタの画面に戻ってください。そして、ファイルの中の「appsscript.json」ファイルを選択して、エディタに以下の内容を入力して保存してください。

{
  "timeZone": "Asia/Tokyo",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Slack Notifier",
      "logoUrl": "https://cdn-icons-png.flaticon.com/512/2111/2111615.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "sendSlackAction",
          "state": "ACTIVE",
          "name": "Send to Slack",
          "description": "Posts a text message to a Slack channel.",
          "workflowAction": {
            "inputs": [
              {
                "id": "messageText",
                "description": "Message content",
                "cardinality": "SINGLE",
                "dataType": { "basicType": "STRING" }
              }
            ],
            "outputs": [
              {
                "id": "status",
                "description": "Result status",
                "cardinality": "SINGLE",
                "dataType": { "basicType": "STRING" }
              }
            ],
            "onConfigFunction": "onConfigSlack",
            "onExecuteFunction": "onExecuteSlack"
          }
        }
      ]
    }
  }
}

そして、ファイルの中の「コード.gs」ファイルを選択して、エディタに以下の内容を入力して保存してください。

// ---------------------------------------------------------
// Slack設定
// ---------------------------------------------------------
const SLACK_BOT_TOKEN = "xoxb-xxxx-xxxx-xxxx"; // Bot User OAuth Token
const SLACK_CHANNEL_ID = "Cxxxxxxxxx";         // 送信先チャンネルID

/**
 * ■ 設定画面生成 (Configuration)
 * 入力欄を1つだけ表示します。
 */
function onConfigSlack() {
  var card = {
    "sections": [
      {
        "header": "Slack Notification Settings",
        "widgets": [
          {
            "textInput": {
              "name": "messageText",
              "label": "Message Text",
              "multiline": true, // 複数行入力を許可
              "hostAppDataSource" : {
                "workflowDataSource" : { "includeVariables" : true }
              }
            }
          }
        ]
      }
    ]
  };
  return pushCard(card);
}

/**
 * ■ 実行関数 (Execution)
 * Flowsからテキストを受け取り、Slackに送信します。
 */
function onExecuteSlack(event) {
  console.log("Event: " + JSON.stringify(event));

  // 1. 入力値の取得
  const inputs = event.workflow.actionInvocation.inputs;
  const text = getStringValue(inputs["messageText"]);

  var statusResult = "";

  try {
    if (!text) {
      throw new Error("Message text is empty.");
    }

    // 2. Slack送信処理
    const response = postSimpleTextToSlack(text);
    statusResult = "Success: " + response;

  } catch (e) {
    console.error(e);
    statusResult = "Failed: " + e.toString();
  }

  // 3. 結果をFlowに返す
  const variableDataMap = {
    "status": AddOnsResponseService.newVariableData().addStringValue(statusResult)
  };
  
  return outputVariables(variableDataMap);
}

/**
 * Slack APIへテキストをPOSTする関数
 */
function postSimpleTextToSlack(text) {
  const url = "https://slack.com/api/chat.postMessage";
  
  const payload = {
    "channel": SLACK_CHANNEL_ID,
    "text": text // シンプルなテキスト送信
    // 必要であればここに "blocks": [...] を追加してリッチにすることも可能
  };

  const options = {
    "method": "post",
    "contentType": "application/json",
    "headers": {
      "Authorization": "Bearer " + SLACK_BOT_TOKEN
    },
    "payload": JSON.stringify(payload),
    "muteHttpExceptions": true // エラーレスポンスも取得できるようにする
  };

  const response = UrlFetchApp.fetch(url, options);
  const json = JSON.parse(response.getContentText());

  if (!json.ok) {
    throw new Error("Slack API Error: " + json.error);
  }

  return "Message sent";
}

// ---------------------------------------------------------
// Helper Functions (Flowsの作法に必要な関数群)
// ---------------------------------------------------------

function getStringValue(inputItem) {
  if (!inputItem) return "";
  if (inputItem.stringValues && inputItem.stringValues.length > 0) return inputItem.stringValues[0];
  if (inputItem.integerValues && inputItem.integerValues.length > 0) return String(inputItem.integerValues[0]);
  return "";
}

function pushCard(card) {
  return { "action": { "navigations": [{ "push_card": card }] } };
}

function outputVariables(variableDataMap) {
 const workflowAction = AddOnsResponseService.newReturnOutputVariablesAction().setVariableDataMap(variableDataMap);
 const hostAppAction = AddOnsResponseService.newHostAppAction().setWorkflowAction(workflowAction);
 return AddOnsResponseService.newRenderActionBuilder().setHostAppAction(hostAppAction).build();
}

そして、コードの冒頭にあるSlack設定のところを実際のBotのトークン文字列とチャンネルIDに変更してください。

// ---------------------------------------------------------
// Slack設定
// ---------------------------------------------------------
const SLACK_BOT_TOKEN = "xoxb-xxxx-xxxx-xxxx"; // Bot User OAuth Token
const SLACK_CHANNEL_ID = "Cxxxxxxxxx";         // 送信先チャンネルID

すべての保存が完了したら画面右上にある「デプロイ」ボタンを選択した後に、「デプロイをテスト」を選択してください。

デプロイをテストのポップアップ画面が出てくると思いますので、この画面の中の「Application(s): Flows」の右側に出てくる「インストール」ボタンを選択してください。はじめてインストールする時には認証画面が出てくると思いますがその時は画面の表示に従って認証を実施してください。

インストールが完了するとFlows側の中に作成した処理が追加されます。この時にFlowsに表示されない場合は画面の再読み込みを試してみてください。

初めてこのStepを設定すると以下のような認証を要求する画面が出てきます。「Grant permission」を選択して認証を順番に実施してください。

認証がすべて完了すると以下のような入力フォームのある画面に更新されます。

実行テスト

今回はこちらのブログのStepの末尾にSlackへ送る処理を追加してどのようにメッセージが送られてくるかを確認してみます。「Send to Slack」のStepにあるMessage Textの欄にStep2で要約した内容を追加します。

そして、Test runからテスト用のメールでテスト実行してみました。以下の内容が実行履歴から確認することができました。この時のStep2の内容がSlackに連携されます。

そして連携された結果が以下の画像の通りとなります。正常にSlackに連携されていることが確認できました。味気ない内容になっていますが今回はメッセージを連携できることを確認するためなので、この機能はいろいろな用途に利用できるのではないかと感じています。

まとめ

FlowsはGoogleアプリ連携に強みがある一方で、現時点ではSlackへの直接通知機能は備わっていません。そこでGASとSlack Botを組み合わせて橋渡しをすることで、既存の自動化フローをそのままSlackにも展開できるようになりました。

少し手間はかかりますが、Apps Script側の共通関数を整えておけば、さまざまなFlowから再利用可能です。Google WorkspaceとSlackのハイブリッド運用をしている組織なら、ぜひ導入を検討してみてください。

 


BACK TO LIST