フォームをメールに送る

フォームをメールに送る2 分で読めます

PHP なしで HTML フォームをメールに送る

mail() を呼ぶ contact.php スクリプトを、ホストされたエンドポイントに送信するフォームに置き換えます。フィールド名、サンクスページ、返信はそのままです。

Preet SutharIkiform 創業者

フォームの action を PHP スクリプトからフォームバックエンドの URL に変え、フィールド名はそのままにして、スクリプトを削除します。バックエンドは mail() がしていたことに加え、それが苦手だったスパム除外、保存、迷惑メールにならない送信も行います。PHP がまったく動かない静的ホストでも動きます。

ここが違う

PHP のお問い合わせフォームのほとんどは、何年も前にチュートリアルからコピーされた同じ 20 行ほどのコードです。$_POST を読んで文字列を組み立て、mail() を呼んでリダイレクトします。典型的な例です:

contact.php
<?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 を運用しているなら妥当な作業です。そうしたくないなら、その仕事をフォームバックエンドに任せましょう。

PHP の mail() を使う場合とフォームバックエンドを使う場合の同じフォームcontact.php の場合フォームバックエンドの場合あなたのフォームaction="/contact.php"mail()From: 訪問者、送信はホスト迷惑メールフォルダーSPF と DMARC で失敗あなたのフォーム同じフィールド、新しい actionIkiformスパム除外、保存受信トレイReply-To: 訪問者送信ローカルのメール送信メールPHP の mail() を使う場合とフォームバックエンドを使う場合の同じフォームcontact.php の場合フォームバックエンドの場合あなたのフォームaction="/contact.php"mail()From: 訪問者、送信はホスト迷惑メールフォルダーSPF と DMARC で失敗あなたのフォーム同じフィールド、新しい actionIkiformスパム除外、保存受信トレイReply-To: 訪問者送信ローカルのメール送信メール
  1. contact.php では、フォームはホストに送信し、mail() は訪問者から来たと名乗るメッセージを送ります。受信側のサーバーは送信者がドメインと一致しないと判断し、迷惑メールに振り分けるか破棄します。
  2. フォームバックエンドでは、フォームは同じフィールドを 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 を受け取りますが、それで問題ありません。
フォームがスクリプトではなく WordPress のプラグインだった場合も、考え方は同じです。ブロックテーマのどこにフォームを置くかは WordPress のガイドにあります。

動作を確認する

  1. フォームの Allowed domains に自分のサイトのドメインと、開発中は localhost を追加します。空にしておくと、どこからの送信でも受け付けます。
  2. 公開中のページでフォームを送信します。以前の thanks.html に移動します。
  3. ダッシュボードで Submissions を開きます。送ったすべてのフィールドを含む新しい送信データがあります。
  4. メールを開きます。訪問者のアドレスではなく Ikiform から届き、迷惑メールにも入っていません。送信元を連絡先に追加しておけば、以降のメールも迷惑メールに入りません。
  5. Reply(返信)を押します。To 欄に訪問者のアドレスが入っています。
  6. ハニーポットを埋めて _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 が送られます。

よくある質問

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