「問い合わせメールが埋もれて、対応が遅れてしまった…」

「誰がどのお問い合わせに対応済みか、すぐに分からない…」

「CRMツールを導入したいけど、月額費用が高すぎる…」

コンタクトフォーム7(Contact Form 7、以下CF7)を使っていると、こういう悩みって意外とあるんですよね。SalesforceやHubSpotのようなCRMツールで解決できるのは分かっていても、月額費用を考えると「うちの規模ではまだ早いかな」となりがちです。

今回は、CF7のお問い合わせデータをGoogle Apps Script(GAS)経由でGoogleスプレッドシートに自動保存する方法を紹介します。プラグインもCRMの月額費用もいらないので、0円でお問い合わせの一元管理を始められます。

目次

なぜコンタクトフォームのスプレッドシート連携が必要なのか

メール通知だけでは問い合わせの保存に限界がある

CF7は送信時にメール通知が届く仕組みですが、問い合わせが増えてくると、メールだけでの管理はだんだんキツくなってきます。

  • 📩 メールの見落とし — 他のメールに埋もれて対応漏れが発生
  • 👥 チームでの共有が困難 — 誰が対応中か、完了したかが分かりにくい
  • 📊 データの集計・分析ができない — 問い合わせの傾向を把握しづらい

スプレッドシートで管理するメリット

そこでスプレッドシートに自動で溜まる仕組みを作ると、この辺りの悩みがだいぶ楽になります。

  • 一覧で管理 — 全ての問い合わせがスプレッドシート上に時系列で並ぶ
  • チームで共有 — 複数人がリアルタイムで確認・ステータス更新可能
  • 集計・フィルタ — 期間別やサービス別の問い合わせ傾向を簡単に把握
  • プラグイン不要 — 追加プラグインなしで実装可能なため、セキュリティリスクを最小化

これはCRM(顧客管理)の第一歩

こういう「問い合わせを溜めて管理する仕組み」、ビジネスではCRM(Customer Relationship Management:顧客関係管理) と呼ばれています。代表的なツールはこんな感じです。

ツール特徴おすすめの規模
SalesforceCRMの最大手。高機能だがコストも高い中〜大企業
HubSpot無料プランあり。マーケティング連携が強い小〜中規模
Zoho CRMコスパに優れ、無料〜安価で機能が豊富小〜中規模
kintoneサイボウズ製。日本企業に人気が高い小〜中規模
Googleスプレッドシート無料。カスタマイズ自由で導入の敷居が低いスタートアップ・小規模

ただ、いきなりこれらを導入するのはハードルが高いかなと思います。まずはスプレッドシートで「問い合わせを一箇所にまとめる」ところから始めるのが現実的です。

対応ステータスの列を足せば進捗管理もできますし、フィルタで傾向を見ることもできます。小さなCRMとしては十分です。問い合わせが増えてきたら、そのときに本格的なツールへ移行すればOKです。

CF7×GAS連携の全体のしくみ

まず全体像を掴んでおきましょう。処理の流れはこうなっています。

sequenceDiagram
    participant User as ユーザー(ブラウザ)
    participant WP as WordPress(CF7)
    participant GAS as Google Apps Script
    participant Sheet as Googleスプレッドシート

    User->>WP: フォーム送信
    WP->>WP: メール送信処理
    WP-)GAS: Webhook POST(JSON)※非同期
    WP-->>User: 送信完了メッセージ表示
    GAS->>GAS: シークレットキー検証
    GAS->>Sheet: 行を追加

ポイントは3つです。

#処理説明
1フォーム送信 → メール送信CF7の標準機能でメール通知は従来通り動作
2メール送信成功 → Webhook送信メール送信が成功した場合のみ、GASへJSONデータをPOST
3GAS → スプレッドシート記録データを検証し、スプレッドシートに1行追加

Webhookはメール送信が成功したときだけ実行されるので、送信失敗やエラーの問い合わせがスプレッドシートに混ざることはありません。

手順1:Googleスプレッドシートを準備する

まずはお問い合わせデータを保存する受け皿のスプレッドシートを作ります。

  1. Google スプレッドシートを開き、新しいスプレッドシートを作成
  2. シート名は任意でOKです(例:「お問い合わせ管理」)
  3. 1行目にヘッダーを設定します
A列B列C列D列E列F列
問い合わせ日時氏名メールアドレス電話番号対象サービス問い合わせ内容

ヘッダーはGASスクリプト側で自動作成される設定にもできますが、あらかじめ手動で設定しておくと列の順番を把握しやすくなります。

手順2:Google Apps Script(GAS)でWebhookを作成する

Google Apps Scriptの基本的な使い方や、Googleスプレッドシートとの連携については[Google公式ドキュメント](https://developers.google.com/apps-script)も参考になります。

次に、WordPressからのデータを受け取るエンドポイント(Webhook)をGASで作成します。

GASエディタを開く

  1. 先ほど作成したスプレッドシートを開く
  2. メニュー 「拡張機能」→「Apps Script」 をクリック
  3. GASエディタが開きます

スクリプトを作成する

デフォルトの `myFunction` を削除し、以下のコードに置き換えます。

function doPost(e) {
  var data = JSON.parse(e.postData.contents);

  // シークレットキー検証
  var SECRET = 'ここにシークレットキーを設定';
  if (!data.secret || data.secret !== SECRET) {
    return ContentService.createTextOutput('Unauthorized');
  }

  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  // ヘッダ行がなければ自動作成
  if (sheet.getLastRow() === 0) {
    sheet.appendRow([
      '問い合わせ日時', '氏名', 'メールアドレス',
      '電話番号', '対象サービス', '問い合わせ内容'
    ]);
  }

  sheet.appendRow([
    data.timestamp,
    data.name,
    data.email,
    data.tel,
    data.target_service,
    data.message
  ]);

  return ContentService.createTextOutput('OK');
}

シークレットキーを生成する

不正なリクエストを防ぐため、WordPress側とGAS側で共有するシークレットキーを設定します。

ターミナルで以下のコマンドを実行して、ランダムな文字列を生成しましょう。

openssl rand -hex 32

生成された64文字の文字列を、スクリプト内の ‘ここにシークレットキーを設定’ の部分に貼り付けます。このキーは次の手順でWordPress側にも設定するので、必ずメモしておいてください。

シークレットキーは絶対に外部に公開しないでください。GitHubなどのリポジトリにハードコードしてpushしてしまうと、第三者にスプレッドシートへ不正にデータを書き込まれる可能性があります。

GASをWebアプリとしてデプロイする

  • 1.GASエディタ右上の 「デプロイ」→「新しいデプロイ」 をクリック
  • 2.種類の選択で 「ウェブアプリ」 を選択
  • 3.以下の設定にします
設定項目
説明CF7問い合わせ連携(任意)
次のユーザーとして実行自分
アクセスできるユーザー全員
  • 4.「デプロイ」 をクリック
  • 5.表示されるウェブアプリのURLをコピーします(次の手順で使用)

「アクセスできるユーザー」を「全員」にするのは、WordPressサーバーからのリクエストを受け付けるためです。セキュリティはシークレットキーで担保しています。

手順3:WordPress側でWebhook送信コードを追加する

WordPress側では、CF7のメール送信完了時にGASへデータをPOSTする処理を追加します。

functions.phpにコードを追加

テーマの functions.php に以下のコードを追加します。

コード内の $data[‘your-name’] などのフィールド名は、あなたのCF7フォームで設定しているフィールド名と一致させる必要があります。CF7のフォーム編集画面を開いて、下のような [text* your-name] の部分を確認してください。

[text* your-name]         → $data['your-name']
[email* your-email]       → $data['your-email']
[tel your-tel]            → $data['your-tel']
[checkbox target-service] → $data['target-service']
[textarea your-message]   → $data['your-message']

フィールド名が違うとデータが取れずに空欄になるので、ここは丁寧に確認してください。

/**
 * CF7メール送信成功時にGASスプレッドシートへデータを送信
 */
add_action('wpcf7_mail_sent', 'send_cf7_to_spreadsheet');

function send_cf7_to_spreadsheet($contact_form) {
    // GAS WebアプリのURL
    $gas_url = 'https://script.google.com/macros/s/ここにデプロイURLを設定/exec';

    // シークレットキー(GAS側と同じ値)
    $secret = 'ここにシークレットキーを設定';

    // フォームの送信データを取得
    $submission = WPCF7_Submission::get_instance();
    if (!$submission) {
        return;
    }
    $data = $submission->get_posted_data();

    // ペイロードを構築
    $payload = array(
        'secret'         => $secret,
        'timestamp'      => current_time('Y-m-d H:i:s'),
        'name'           => isset($data['your-name']) ? $data['your-name'] : '',
        'email'          => isset($data['your-email']) ? $data['your-email'] : '',
        'tel'            => isset($data['your-tel']) ? $data['your-tel'] : '',
        'target_service' => isset($data['target-service']) 
                            ? (is_array($data['target-service']) 
                                ? implode(', ', $data['target-service']) 
                                : $data['target-service']) 
                            : '',
        'message'        => isset($data['your-message']) ? $data['your-message'] : '',
    );

    // GASへJSON POST(非同期)
    wp_remote_post($gas_url, array(
        'body'     => wp_json_encode($payload),
        'headers'  => array('Content-Type' => 'application/json'),
        'timeout'  => 10,
        'blocking' => false,
    ));
}

コードの解説

いくつかハマりやすいポイントがあるので補足しておきます。

wpcf7_mail_sent フック

CF7にはいくつかフックがありますが、ここでは wpcf7_mail_sent を使います。

フック名発火タイミング採用判断
wpcf7_mail_sentメール送信成功後✅ 採用
wpcf7_before_send_mailメール送信❌ 不採用

wpcf7_before_send_mail を使うと、メール送信に失敗した問い合わせもスプレッドシートに記録されてしまいます。「メール送信が成功した = 正常な問い合わせ」という前提で、wpcf7_mail_sent を選択しています。

wp_remote_postblocking => false

'blocking' => false,

blockingfalse にすると、GASのレスポンスを待たずに次の処理に進みます。つまりWebhookのPOSTだけ投げて、ユーザーにはすぐ送信完了メッセージが返ります。GAS側の処理が遅くてもユーザーの待ち時間に影響しません。

ただし、GAS側でエラーが起きてもPHP側では検知できないので、書き込みが失敗していないかはGASの実行ログで確認してください。

フィールド名のカスタマイズ

上記コードの $data[‘your-name’] $data[‘your-email’] は、CF7のフォーム設定で定義したフィールド名です。ご自身のフォームのフィールド名に合わせて変更してください。

CF7のフォーム編集画面で確認できるフィールド名(例: [text* your-name]your-name 部分)と一致させる必要があります。

手順4:動作確認とテスト

設定が完了したら、実際にテスト送信して動作を確認しましょう。

テスト手順

  1. WordPressサイトのお問い合わせページを開く
  2. テストデータを入力してフォームを送信
  3. メール通知が届くことを確認
  4. Googleスプレッドシートにデータが追加されていることを確認

curlでGASの動作だけ先にテストする

WordPress側の実装をする前に、GAS単体で動くか確認しておくと安心です。ターミナルから以下のコマンドを叩いてみてください。

curl -L -X POST \
  'https://script.google.com/macros/s/ここにデプロイURL/exec' \
  -H 'Content-Type: application/json' \
  -d '{
    "secret": "ここにシークレットキー",
    "timestamp": "2026-02-18 12:00:00",
    "name": "テスト太郎",
    "email": "[email protected]",
    "tel": "03-0000-0000",
    "target_service": "テスト",
    "message": "curlからのテスト送信です"
  }'

OK と返ってきて、スプレッドシートに行が追加されれば成功です。Unauthorized が返ってきたらシークレットキーが一致していません。

-L オプションはGASの302リダイレクトを追跡するために必要です。ただし、curlはリダイレクト時にPOSTからGETに切り替えてしまうため、405(Method Not Allowed)が返ってくることがあります。その場合は –post302 オプションを追加してください

curl -L --post302 -X POST \
  'https://script.google.com/macros/s/ここにデプロイURL/exec' \
  -H 'Content-Type: application/json' \
  -d '{"secret":"キー","timestamp":"2026-02-18 12:00:00","name":"テスト","email":"[email protected]","tel":"","target_service":"テスト","message":"テスト"}'

なおGASの doPost はリダイレクト前に実行されるため、405が返ってきてもスプレッドシートへの書き込みは成功していることがあります。レスポンスよりもスプレッドシートを確認してみてください。

うまくいかないときのチェックポイント

症状確認すること
スプレッドシートにデータが追加されないGASのデプロイURLが正しいか確認。URLの末尾が /exec になっているか
GASで「Unauthorized」が返るWordPress側とGAS側のシークレットキーが完全に一致しているか
curlで403やアクセス拒否が返るGASのデプロイ設定で「アクセスできるユーザー」が「全員」になっているか。「自分のみ」だと外部からアクセスできません
メールは届くがスプレッドシートに反映されないGASの「実行数」(エディタの左メニュー)でエラーログを確認
GASの実行ログにエラーがないwp_remote_post のレスポンスを確認。サーバー側のファイアウォール設定を確認

GASのスクリプトを修正した場合は、必ず「新しいデプロイ」を作成してください。既存のデプロイを「再デプロイ」しただけでは、コードの変更が反映されないことがあります。新しいデプロイでURLが変わった場合は、functions.php のURLも忘れずに更新しましょう。

セキュリティ対策のポイント

Webhookを使ったデータ連携では、セキュリティ面も重要です。当社でもWordPressの保守・セキュリティ対策を数多く支援してきた経験から、今回の実装で考慮すべきポイントをまとめます。

シークレットキー認証

GASのWebアプリURLは「アクセスできるユーザー:全員」で公開されていますが、シークレットキーを知らないリクエストはすべて拒否する仕組みを入れています。

// GAS側での検証
if (!data.secret || data.secret !== SECRET) {
    return ContentService.createTextOutput('Unauthorized');
}

万が一URLが漏れても、キーを知らなければデータは書き込めません。

reCAPTCHAによるスパム対策

CF7側でreCAPTCHA v3を導入しておくと、ボットによるスパム送信を防止できます。reCAPTCHAは「Contact Form 7」の「インテグレーション」設定から簡単に有効化できます。

HTTPS通信

WordPress側からGASへの通信は https:// なので、TLS(SSL)で暗号化されています。通信の盗聴を気にする必要はありません。

以下の3点が揃っていれば、基本的なセキュリティは確保されています。

  • シークレットキーによる認証 ✅
  • reCAPTCHAによるスパム対策 ✅
  • HTTPS通信による暗号化 ✅

個人情報の取り扱いに関する注意

お問い合わせフォームのデータには個人情報が含まれるので、スプレッドシートで管理する場合は以下も意識しておきたいところです。

  • 🔒 スプレッドシートの共有設定 — 「リンクを知っている全員」ではなく、必要な担当者のみに閲覧権限を付与する
  • 📝 プライバシーポリシーへの記載 — 「取得した個人情報はGoogleのサービスを利用して管理します」といった旨をプライバシーポリシーに明記する
  • 🗓️ データの保持期間 — 対応完了後のデータをいつまで保持するかルールを決め、不要になったデータは定期的に削除する
  • 🏢 Google Workspaceの利用推奨 — ビジネス用途では、個人向けGoogleアカウントではなくGoogle Workspaceの利用が望ましい。Workspaceにはデータ処理契約(DPA)が含まれており、企業の個人情報保護方針に沿った運用がしやすくなる

個人情報保護法では、個人データの安全管理措置が義務付けられています。スプレッドシートの共有範囲やアクセスログの管理など、自社のプライバシーポリシーと整合した運用ルールを必ず策定しましょう。

ここからお手製CRMに育てる

ここまでのスプレッドシート連携で、コンタクトフォームからの問い合わせは自動で保存されるようになりました。ここからちょっと列を足すだけで、お手製のCRMっぽく使えるようになります。

たとえばこんな列を追加してみてください。

G列H列I列J列
対応者ステータス対応日メモ

ステータスはプルダウン(データの入力規則)で「未対応 / 対応中 / 完了」などを選べるようにしておくと便利です。さらに条件付き書式で「未対応 = 赤」「完了 = 緑」のように色分けすれば、対応漏れもひと目で分かります。

やっていることはシンプルですが、「誰が・いつ・どの問い合わせに対応したか」が一覧で見えるだけで、チームの動きはかなり変わります。

まとめ

やることをおさらいしておきます。

  1. Googleスプレッドシートを作って、ヘッダーを設定
  2. GASスクリプトを書いて、Webhookとしてデプロイ
  3. functions.phpwpcf7_mail_sent フックでWebhook送信コードを追加
  4. テスト送信して動作確認

プラグインを入れずに済むので、サイトが重くなったりセキュリティリスクが増えたりする心配もありません。

一度仕組みを作ってしまえば、あとはスプレッドシート上で「対応済み」列を追加したり、条件付き書式で色分けしたりと、自分たちのやり方に合わせて育てていけます。

「自分でやるのは難しそう」「もう少し凝った連携を組みたい」という方は、お気軽にご相談ください。当社ではWordPressのカスタマイズから業務フローの自動化まで、エンジニア目線でお手伝いしています。