ABCABC Tech Catalog

Googleフォームで回答を受け付けたらSlackに通知するGASをちゃんと作る

GoogleフォームからSlackへ通知するGAS

Google Workspaceを使うなら活用したいGAS

皆さん Google Apps Script(以下GAS) 使ってますか?

Google Workspaceを使っているなら、GASを使えると便利になるシーンってとても多いですよね。

今日はその代表例とも言える、GoogleフォームからGASを用いてSlackへ通知する方法についてまとめます。例としてSlackを出していますが、Google Chat等でもWebhookを用いることで同様の手順で通知を出すことが出来ます。

個人的にはもはや標準で搭載していて欲しいとさえ思えるくらい、ほとんどのGoogleフォームに仕込んでいる設定です。

GAS作成手順

まずは、対象のGoogleフォームにGASを仕込む手順です。

とりあえず、フォームを作ります。今回はサンプルにある「イベントの出欠確認」をそのまま使います。

作成したら、 フォームの右上のメニューから「スクリプト エディタ」を選択 します。

file1

スクリプトエディタが立ち上がります。

file2

というわけで、いったん myFunction() は消してから、コードを書いていきます。

まず、定数系を外出ししていきます。Slack関連だと

const SLACK_WEBHOOK_URL = "(SLACKのWebhook URL)";
const SLACK_USER_NAME = "Google Form";
const SLACK_ICON = ":information_source:";
const SLACK_CHANNEL = "#notifications"

こんなところでしょうか。Webhook URLの発行手順等は本記事では扱いませんがSlackの管理画面より簡単に発行することができます。

あとは、回答のスプレッドシートへのリンクも合わせて通知するために、Googleフォームの画面から作成して

file3

URLをコピーして

const FORM_SPREADSHEET_URL = "(回答スプレッドシートのURL)";

も足しておきましょう。

ここまで出来たら、まずはSlackに送信する部分を作ります。

送信内容のblockの集合を blocks 、送信先channelを channel として引数にとり、実際に送信まで行ってしまう関数として作成します。

const sendToSlack = (blocks, channel) => {
  const url = SLACK_WEBHOOK_URL;
  const data = { "channel" : channel, "username" : SLACK_USER_NAME, "blocks" : blocks, "icon_emoji" : SLACK_ICON };
  const payload = JSON.stringify(data);
  const options = {
    "method" : "POST",
    "contentType" : "application/json",
    "payload" : payload
  };
  const response = UrlFetchApp.fetch(url, options);
};

これはシンプルに情報をWebhookにPOSTするだけの関数です。Slack以外のツールでもここを各Webhook所定の形に整えればOKです。

続いて、実際にForm提出時にトリガされる予定の関数 onFormSubmit を作成します。

const onFormSubmit = (e) => {
  const itemResponses = e.response.getItemResponses();
  const slackBlocks = generateSlackBlocks(itemResponses);
  sendToSlack(slackBlocks, SLACK_CHANNEL);
}

e.response.getItemResponses() にて提出されたフォームの内容が取得出来るので、それをSlackメッセージ生成用の関数 generateSlackBlocks にそのまま渡しています。

それで出来上がったブロックを、チャンネル指定しながら sendToSlack に渡して送信完了、というわけですね。

最後に本丸の itemResponses からSlackへのメッセージを作成する generateSlackBlocks です。

const generateSlackBlocks = (itemResponses) => {
    const headerBlocks = [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "Google フォームに回答がありました!"
      }
    },
    {"type": "divider"}
  ]
  const responseBlocks = itemResponses
    .map((item) => {
      const title = item.getItem().getTitle();
      const res = item.getResponse();
      if (res === "" || res === null) return null

      return {
        "type": "section",
        "text": {
          "type": "mrkdwn",
          "text": `*${title}* \n${res}`
        }
      }
    })
    .filter(item => item !== null);
  const blocks = headerBlocks.concat(responseBlocks)

  blocks.push({"type": "divider"})

  blocks.push({
    "type": "actions",
    "elements": [{
      "type": "button",
      "text": {
        "type": "plain_text",
        "text": "スプレッドシートで開く",
        "emoji": true
      },
      "value": "click_btn",
      "url": FORM_SPREADSHEET_URL
    }]
  })

  return blocks;
};

headerBlocks と最後のスプレッドシートで開くボタン用のblockはオマケみたいなもので、

肝心なのは、

const responseBlocks = itemResponses
  .map((item) => {
    const title = item.getItem().getTitle();
    const res = item.getResponse();
    if (res === "" || res === null) return null

    return {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": `*${title}* \n${res}`
      }
    }
  })
  .filter(item => item !== null);

のところです。 itemResponses から中身を取り出して順次整形加工することで、 フォームの内容に関係なく汎用的に回答内容をSlackに送信できる ようにしています。

ここまで貼り付けたコードを上から順にでも貼り付けてやればコードそのものは完成です。 どんなフォームでも設定しなくてはならないのは冒頭の定数部分だけ! です。

GASのトリガ設定

コードが完成したら、実際にフォームの提出時にGASが実行されるよう、最後に忘れずトリガ設定しておきます。

左側のタイマーアイコンを選択し、右下の 「トリガーを追加」 を選択します。

file4

すると、トリガー追加画面になりますので、下記のように 「onFormSubmit」「フォーム送信時」 に実行するよう指定します。

file5

ここで、 右側のエラー通知設定は「今すぐ通知を受け取る」としておく ことをオススメします。たまにエラーで正しく送信されない場合がありますが、そういったときにもエラー検知できていれば回答が来ているのにSlackに到達していないことを迅速に確認出来ます。

ここまで設定が完了したら、下記のようになっているかと思います。これで設定完了です。

file6

GASの動作確認

最後に実際にフォームから提出を行って動作確認します。

file7

問題無くフォームへの提出内容がSlackに到達していることを確認出来ました!

まとめ

今回はGASを用いてGoogleフォームの提出内容をSlackに通知する方法についてまとめました。冒頭にも述べましたが、これはSlackに限った話でなく、様々なプラットフォームに対して応用出来ます。

たとえば、不具合報告フォームを作成して、そこから提出された内容をもとにGitHubで自動でIssueを立てる、等ですね。また、GAS内で複数の内容を実施することもできますので、応用の幅も広いです。

GASはなかなかコードの品質を保つのが難しい ので、今回のように出来るだけ汎用性高くコードを書くことも大事かと思います。広く使われているぶん検索すると色々なコードが出てきますが、ちょっと品質的に怪しいコードもたくさん引っかかってきてしまうので、そこが落とし穴なのではないか…と思ったりもします。

それはさておいて、Googleフォームは標準でとても使い勝手が良いですが、ぜひこういったプラスアルファでの活用を取り入れてさらに便利に使っていきたいですね!

AUTHOR

伴 拓也

朝日放送グループホールディングス株式会社 デジタル・アーキテック局 データ戦略チーム

アプリケーションからインフラ、ネットワーク、データエンジニアリングまで幅広い守備範囲が売り。最近はデータ基盤の構築まわりに力を入れて取り組む。 主な実績として、M-1グランプリ敗者復活戦投票システムのマルチクラウド化等。

WORK@ABC

技術力を培うための
環境と文化

ABCに昔から根付く「自分たちで開発する」文化を支える環境や取り組みをご紹介します
ABCについてもっと知る