静的サイトのお問い合わせフォーム

静的サイトのお問い合わせフォーム2 分で読めます

GitHub Pages のサイトにお問い合わせフォームを追加する

GitHub Pages ではサーバーコードが動かず、フォームの POST は 405 Not Allowed になります。フォームバックエンドに送信し、プロジェクトサイトのリダイレクトを正しく設定しましょう。

Preet SutharIkiform 創業者

GitHub Pages は静的ファイルしか配信しないので、自分のサイトに送信するフォームは 405 Not Allowed になり、メッセージは失われます。フォームの action を Ikiform のエンドポイントにし、username.github.io と独自ドメインを Allowed domains に追加して、プロジェクトサイトのパスを含むサンクスページにリダイレクトします。リポジトリも Pages の設定も変わらず、公開リポジトリにシークレットが入ることもありません。

GitHub Pages ならではの違い

GitHub Pages が公開するのは、リポジトリか Actions のワークフローがビルドしたものだけです。Jekyll を使うならビルド時に動き、その結果はファイルになります。リクエストを処理する仕組みがないので、何をコミットしても PHP の mail()、Node のスクリプト、Python の CGI フォームは動きません。

失敗はターミナルで確認できます。Pages のサイトのどのページに POST しても、次の結果になります:

ターミナル
curl -i -X POST -d "message=hello" https://ada.github.io/notebook/contact.html
応答
HTTP/2 405
server: Varnish
content-length: 131

<html>
<head><title>405 Not Allowed</title></head>

Pages には他の静的ホストと違う点がさらに 4 つあり、どれもお問い合わせフォームに関わります:

Pages の特徴フォームへの影響
プロジェクトサイトは username.github.io/repo/ のようにパスの下に置かれる/thanks.html というサンクスページの URL は、プロジェクトではなくユーザーサイトを指す。どの URL にも /repo/ の部分が必要
カスタムのレスポンスヘッダーを設定できないContent-Security-Policy は、ページ内の <meta> タグでしか指定できない
リポジトリは公開されていることが多い中身はすべて公開される。フォーム ID なら問題ないが、シークレット API キーやメールのパスワードは絶対に置かない
GitHub は、パスワードやクレジットカード番号の送信など機密性の高い取引に Pages サイトを使うべきではないとしているお問い合わせフォームはお問い合わせ専用にする。カード情報やアカウントのパスワードを集めない
GitHub Pages が実行するものと、お問い合わせフォームの送信先GitHub Pages が実行するもの訪問者の送信が届く先git pushPages のブランチへビルドJekyll か Actionsのワークフロー静的ファイルusername.github.io/repo上contact.htmlPages が配信Ikiform保存してメール通知repo/thanks.htmlPages が配信405 Not Allowed何も保存されないデプロイPOST303action="/contact"GitHub Pages が実行するものと、お問い合わせフォームの送信先GitHub Pages が実行するもの訪問者の送信が届く先git pushPages のブランチへビルドJekyll か Actionsのワークフロー静的ファイルusername.github.io/repo上contact.htmlPages が配信Ikiform保存してメール通知repo/thanks.htmlPages が配信405 NotAllowed何も保存されないデプロイPOST303action="/contact"
  1. Pages の公開元のブランチに push します。
  2. Jekyll か Actions のワークフローがサイトを 1 回ビルドします。
  3. Pages はその結果を、github.io か独自ドメインで静的ファイルとして配信します。
  4. 訪問者がお問い合わせフォームを送信します。action が自分のサイトを指していると、Pages は 405 Not Allowed を返します。
  5. action を Ikiform のエンドポイントにすれば、Ikiform がメッセージを保存してメールで通知します。
  6. Ikiform はブラウザーをサンクスページにリダイレクトし、Pages はそれを他のファイルと同じように配信します。
コードが GitHub で実行されるのは push ごとに 1 回だけです。訪問者が送信を押したときに動くあなたのコードはないので、送信は github.io の外へ出す必要があります。

フォーム

手書きのサイトなら、index.html の隣に contact.html を追加します。この例は ada.github.io/notebook のプロジェクトサイト用なので、リダイレクト先に /notebook/ が含まれます:

contact.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"
    />
    <title>Contact</title>
  </head>
  <body>
    <h1>Get in touch</h1>
    <form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
      <label for="name">Name</label>
      <input id="name" name="name" autocomplete="name" required />

      <label for="email">Email</label>
      <input id="email" name="email" type="email" autocomplete="email" required />

      <label for="about">What is it about?</label>
      <select id="about" name="about">
        <option value="question">A question about the project</option>
        <option value="hire">Work together</option>
        <option value="other">Something else</option>
      </select>

      <label for="message">Message</label>
      <textarea id="message" name="message" rows="6" minlength="10" required></textarea>

      <input type="hidden" name="page" value="docs-home" />
      <input type="hidden" name="_redirect" value="https://ada.github.io/notebook/thanks.html" />
      <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
      <button type="submit">Send</button>
    </form>
  </body>
</html>
  • <meta> の Content-Security-Policy は任意です。すでにあるなら残し、form-action と connect-src に https://ikiform.com が含まれていることを確認してください。Pages は代わりにヘッダーを送れません。
  • about のセレクトボックスで、メッセージを開く前に問い合わせの理由がわかります。選択肢は、実際に届く問い合わせの内容に合わせて変えてください。
  • hidden の page 入力欄は、フォームが置かれていたページを記録します。同じフォームを複数のドキュメントページに置くときに便利です。
  • フィールド名は email のままにしてください。通知メールはこれを reply-to アドレスとして使います。

同じ HTML を複数のパスにデプロイする場合や、最終的なパスがわからない場合は、ページ自身のアドレスからブラウザーでリダイレクト先を組み立てます。フォームの後にこれを置きます:

contact.html
<script>
  document.querySelectorAll('input[name="_redirect"]').forEach((input) => {
    input.value = new URL("thanks.html", document.baseURI).href;
  });
</script>

Jekyll を使っていますか?それなら URL をハードコードする必要はありません。Jekyll ガイドに、absolute_url で URL を組み立てる include があり、プロジェクトサイトでは baseurl を付けてくれます。Astro、Vite、Hugo を Actions のワークフローでビルドしているなら、フォームのアセットが読み込まれるようにフレームワークのベースパスを /repo/ に設定し、フォーム自体は Hugo や各フレームワークのガイドに従ってください。

github.io での許可ドメイン

自分のユーザー名で ada.github.io を追加します。プロジェクトサイトは同じホストを共有するので、これでユーザーサイトとすべてのプロジェクトサイトをカバーできます。独自ドメインを使っているならそれも追加します。example.com は www.example.com もカバーします。

github.io だけを追加してはいけません。他人のサイトにあるあなたのフォームのコピーも含め、すべての Pages サイトが一致してしまいます。許可ドメインを設定していれば https://ada.github.io/notebook/thanks.html への _redirect に従いますが、設定していなければ Ikiform はそれを無視し、自身がホストするサンクスページを表示します。

リポジトリの Pages 設定で Enforce HTTPS をオンにします。Ikiform が従うのは https: で始まる _redirect の値だけで、証明書がまだない独自ドメインは http: でページを配信します。

mailto: リンクを置き換える

多くの Pages サイトは、フッターの mailto: リンクから始まります。これをフォームに置き換えれば、新たなスクレイパーにページからアドレスを読み取られなくなり、メールアプリを設定していない訪問者も連絡できるようになります。削除する前に知っておくべきことが 2 つあります:

  • アドレスはリポジトリの履歴や、古いページのフォークやアーカイブに残ります。フォームが役立つのはこれからの分で、何年も公開されていたアドレスが非公開に戻るわけではありません。
  • 返信は自分の受信トレイから行います。通知メールは送信者を reply-to アドレスに設定するので、Reply を押せば、mailto: リンクと同じことを逆側から行えます。

Ikiform は訪問者にメールを送らないので、いつごろ返事が届くかをサンクスページに書いておきましょう。メールで返しきれないほどメッセージが届くなら、Webhook で 1 件ずつ Slack や Discord に送ることもできます。

動作を確認する

これは公開中の github.io のアドレスで実行してください。Pages にはプレビューのデプロイがないので、まずローカルサーバーでテストします。

  1. Allowed domains に localhost と username.github.io、独自ドメインがあればそれも追加します。
  2. contact.html と thanks.html をコミットし、リポジトリの Actions タブで Pages のデプロイが終わるのを待ってから、公開中のページを開きます。
  3. フォームを送信します。アドレスバーにプロジェクトのパスが入った、自分の thanks.html に移動するはずです。
  4. ダッシュボードで Submissions を開きます。送ったすべてのフィールドを含む新しい送信データがあります。
  5. 通知の受信者それぞれの受信トレイを確認します。各自にフィールド入りのメールが届き、フォームに email フィールドがあれば Reply の宛先は送信者になります。
  6. 何も届かない場合は、ダッシュボードのステータスフィルターを Spam に切り替えてください。スパムにも本物の送信と同じ成功の応答が返ります。

ハマりどころ

問題対処
送信を押すと 405 Not Allowed になるデプロイされたフォームがまだ自分のサイトに送信しています。github.io でページのソースを表示して action を確認してください。古いキャッシュのビルドが数分間残っていることもあります。
自分のページではなく Ikiform のサンクスページが表示される_redirect の値にリポジトリのパスがない、http: になっている、またはフォームに許可ドメインがありません。username.github.io を追加し、完全な https: の URL を使ってください。
403 origin_not_allowed が返るか、すべての送信がスパムになるページのドメインがフォームの Allowed domains にありません。ドメインと、ローカルのテスト用に localhost を追加してください。登録済みドメインのサブドメインは許可されます。
ローカルでは送信できるのに、github.io ではコンソールに CSP エラーが出るレイアウトの <meta> の Content-Security-Policy で、form-action か connect-src に https://ikiform.com がありません。

よくある質問

手順で詰まったときや、あなたの状況に合うガイドがほしいときはメールでどうぞ: hello@ikiform.com