フォームをメールに送る2 分で読めます
PHP なしで HTML フォームをメールに送る
mail() を呼ぶ contact.php スクリプトを、ホストされたエンドポイントに送信するフォームに置き換えます。フィールド名、サンクスページ、返信はそのままです。
フォームの action を PHP スクリプトからフォームバックエンドの URL に変え、フィールド名はそのままにして、スクリプトを削除します。バックエンドは mail() がしていたことに加え、それが苦手だったスパム除外、保存、迷惑メールにならない送信も行います。PHP がまったく動かない静的ホストでも動きます。
ここが違う
PHP のお問い合わせフォームのほとんどは、何年も前にチュートリアルからコピーされた同じ 20 行ほどのコードです。$_POST を読んで文字列を組み立て、mail() を呼んでリダイレクトします。典型的な例です:
<?php
$name = $_POST["name"];
$email = $_POST["email"];
$phone = $_POST["phone"];
$message = $_POST["message"];
$to = "hello@example.com";
$subject = "Website enquiry from $name";
$body = "Name: $name\nEmail: $email\nPhone: $phone\n\n$message";
$headers = "From: $email\r\nReply-To: $email";
if (mail($to, $subject, $body, $headers)) {
header("Location: /thanks.html");
} else {
echo "Sorry, something went wrong.";
}一見無害で、書かれた当時は動いていました。しかし今は 4 つの点で壊れていて、明らかなのは最初の 1 つだけです:
| 問題 | 原因 |
|---|---|
| ホストに PHP がない | GitHub Pages、Netlify、Vercel、Cloudflare Pages、S3 はファイルを配信するだけで、PHP は実行しません。フォームは実行されないファイルに送信され、404 か 405 が返ります。 |
| メールが迷惑メールになる、または消える | mail() はメッセージをサーバー内のメールプログラムに渡します。From: ヘッダーは訪問者のアドレスを名乗りますが、メールはホストのサーバーから送られるので、訪問者のドメインの SPF と DMARC のチェックに通りません。Gmail や Outlook はそれを振り分けるか拒否し、多くの場合は何も通知しません。 |
| ヘッダーインジェクション | $email は確認されないままヘッダーに入ります。改行を含む値を送るボットは独自の Bcc: 行を追加し、あなたのフォームを使ってスパムを送れるので、ホストの IP がブロックリストに載ってしまいます。 |
| 何も残らない | メールが失われると、メッセージも失われます。記録もスパムフィルターもなく、先月の問い合わせを見返す手段もありません。 |
それぞれ直すこともできます。すべての値を検証し、PHPMailer などのライブラリで SMTP プロバイダー経由で送り、自分のドメインに SPF と DKIM を設定し、ハニーポットとレート制限を追加し、データベースに記録します。すでに PHP を運用しているなら妥当な作業です。そうしたくないなら、その仕事をフォームバックエンドに任せましょう。
- contact.php では、フォームはホストに送信し、mail() は訪問者から来たと名乗るメッセージを送ります。受信側のサーバーは送信者がドメインと一致しないと判断し、迷惑メールに振り分けるか破棄します。
- フォームバックエンドでは、フォームは同じフィールドを Ikiform に送信します。Ikiform は自身のドメインからメールを送り、訪問者のアドレスを Reply-To に入れます。Reply-To は本来そのためのものです。
フォームを PHP から移す
フィールド名は今のまま変えないでください。変えるのは action と、2 つの hidden 入力欄の追加だけです:
<form action="/contact.php" method="post">
<input name="name" required />
<input name="email" type="email" required />
<input name="phone" type="tel" />
<textarea name="message" required></textarea>
<button>Send</button>
</form><form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
<input name="name" required />
<input name="email" type="email" required />
<input name="phone" type="tel" />
<textarea name="message" required></textarea>
<input type="hidden" name="_redirect" value="https://example.com/thanks.html" />
<input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
<button>Send</button>
</form>次に、スクリプトがしていたことを、今どこで行うかに対応づけます:
| contact.php での処理 | 現在 |
|---|---|
$to = "hello@example.com" | フォームの Notifications 設定にある受信者 |
header("Location: /thanks.html") | hidden 入力欄の _redirect、またはフォーム設定の Redirect after submit |
Reply-To: $email | フィールド名が email なので自動 |
$subject = "Website enquiry from $name" | New submission: <form name> で固定。文言を残したいなら、フォーム名を「Website enquiry」にします |
echo "Sorry, something went wrong." | 通常の送信なら Ikiform のエラーページ、fetch なら自分のメッセージ |
| 自分では書いていなかったチェック | _gotcha ハニーポット、スパムスコア、レート制限、フィールドのバリデーション |
- 自分のドメインを Allowed domains(許可ドメイン)に追加します。
_redirectは、それらのドメインにあるhttps:の URL でしか機能しません。 - 新しいフォームが動いたら、サーバーから
contact.phpを削除します。放置されたスクリプトは、URL を覚えているボットにとって開いたままのメールリレーです。 - 静的ホストに移った場合、古い
/contact.phpの URL はもう存在しません。そこに直接送信するボットは404を受け取りますが、それで問題ありません。
動作を確認する
- フォームの Allowed domains に自分のサイトのドメインと、開発中は
localhostを追加します。空にしておくと、どこからの送信でも受け付けます。 - 公開中のページでフォームを送信します。以前の
thanks.htmlに移動します。 - ダッシュボードで Submissions を開きます。送ったすべてのフィールドを含む新しい送信データがあります。
- メールを開きます。訪問者のアドレスではなく Ikiform から届き、迷惑メールにも入っていません。送信元を連絡先に追加しておけば、以降のメールも迷惑メールに入りません。
- Reply(返信)を押します。To 欄に訪問者のアドレスが入っています。
- ハニーポットを埋めて
_gotcha=botで送信します。成功の応答は返りますが、送信データはスパムとして保存され、メールも Webhook も送られません。
ハマりどころ
- 角かっこ付きの古いフィールド名。 PHP のフォームでは
contact[email]のような名前がよく使われます。Ikiform はそのまま保存しますが、返信先はemailという名前のフィールドか、それに近いいくつかの名前からしか取りません。フィールド名を変えるか、_replytoを追加してください。 - 件名に名前を入れられません。 スクリプトの件名には訪問者の名前が入っていました。通知メールの件名は固定で、
_subjectは Webhook と API に渡されるだけで、メールは変わりません。 - 文字コード。
mail()のスクリプトは charset を設定していないことが多く、アクセント記号がよく文字化けしていました。Ikiform のメールは UTF-8 なので、どの文字体系の名前も崩れずに届きます。 $toに複数のアドレス。 スクリプトのカンマ区切りのリストは、ダッシュボードではそれぞれ別の受信者になります。外部のアドレスは、何かを受け取る前にリンクで確認します。複数の受信者 を参照してください。
うまくいかないとき
| 問題 | 対処法 |
|---|---|
| ブラウザーが自分のページではなく Ikiform のサンクスページに移動する | _redirect は、ドメインが Allowed domains にあり、かつ https: の URL でないと無視されます。ドメインを追加するか、代わりにフォーム設定で Redirect after submit を設定してください。 |
403 origin_not_allowed が返るか、すべての送信がスパムになる | ページのドメインがフォームの Allowed domains にありません。追加し、ローカルでのテスト用に localhost も追加してください。登録したドメインのサブドメインは許可されます。 |
| フォームがまだ PHP ファイルに送信している | キャッシュされたページや、フッターのインクルードなどフォームの 2 つ目のコピーに、古い action が残っています。サイト全体で contact.php を検索してください。 |
| 送信データはダッシュボードにあるのに、メールも Webhook も届かない | スパムとして保存されています。スパムでは何も送られません。Spam フィルターで開いて理由を確認し、スパムではないとマークすればメールと Webhook が送られます。 |
よくある質問
はい。フォームの action を変えるまで古いスクリプトは動き続けるので、まずページのコピーで新しいエンドポイントをテストし、それから切り替えてスクリプトを削除できます。
はい。フォームの action を PHP スクリプトではなくフォームバックエンドに向けます。バックエンドが送信を受け取ってメールで知らせるので、サイトはどの静的ホスト上のプレーンな HTML でも構いません。
スクリプトはたいてい From ヘッダーを訪問者のアドレスにしますが、メールはあなたのホストのサーバーから送られます。そのため訪問者のドメインの SPF と DMARC のチェックに失敗し、Gmail や Outlook は偽装とみなします。フォームバックエンドは自分のドメインから送信し、代わりに訪問者を Reply-To に入れます。
いいえ。Ikiform は送信されたどんな名前でも保存します。返信が訪問者に届くよう、メールのフィールド名は email、email_address、your_email、reply_to、contact_email のいずれかにするか、_replyto フィールドを追加してください。
SPF と DKIM を設定した自分のドメインでプロバイダー経由で送れば、到達率の問題は解決します。それでも PHP のホスト、バリデーション、スパムフィルター、メッセージの保管場所は必要です。すでに PHP のコードを保守しているなら良い選択です。
手順で詰まったときや、あなたの状況に合うガイドがほしいときはメールでどうぞ: hello@ikiform.com