폼을 이메일로 보내기

폼을 이메일로 보내기4분 분량

PHP 없이 HTML 폼을 이메일로 보내기

mail()을 호출하는 contact.php 스크립트를 호스팅 엔드포인트로 POST하는 폼으로 바꾸세요. 필드 이름, 감사 페이지, 답장은 그대로 유지됩니다.

Preet SutharIkiform 창업자

폼의 action을 PHP 스크립트에서 폼 백엔드의 URL로 바꾸고, 필드 이름은 그대로 두고, 스크립트는 삭제하세요. 백엔드가 mail()이 하던 일에 더해, 그동안 제대로 못 하던 일까지 처리합니다. 스팸 필터링, 저장, 그리고 스팸함에 들어가지 않는 메일입니다. PHP를 전혀 실행할 수 없는 정적 호스팅에서도 동작합니다.

이 경우가 다른 점

대부분의 PHP 문의 폼은 몇 년 전 튜토리얼에서 복사한 똑같은 스무 줄입니다. $_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.";
}

무해해 보이고, 작성 당시에는 동작했습니다. 하지만 지금은 네 가지 방식으로 망가지며, 눈에 띄는 것은 첫 번째뿐입니다.

문제원인
호스팅에 PHP가 없음GitHub Pages, Netlify, Vercel, Cloudflare Pages, S3는 파일을 제공할 뿐 PHP를 실행하지 않습니다. 폼은 절대 실행되지 않는 파일로 POST하고, 404나 405를 받습니다.
메일이 스팸함에 들어가거나 사라짐mail()은 메시지를 서버의 로컬 메일 프로그램에 넘깁니다. From: 헤더는 방문자의 주소라고 주장하지만 메일은 호스팅 서버에서 나가므로, 방문자 도메인의 SPF와 DMARC 검사에 실패합니다. Gmail과 Outlook은 이를 걸러 내거나 거부하며, 아무 알림 없이 그러는 경우가 많습니다.
헤더 인젝션$email이 검사 없이 헤더에 들어갑니다. 줄바꿈이 포함된 값을 POST하는 봇은 자기 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를 쓰면 폼이 호스팅으로 POST하고, mail()은 방문자가 보냈다고 주장하는 메시지를 보냅니다. 수신 서버는 도메인과 맞지 않는 발신자를 보고 스팸으로 분류하거나 버립니다.
  2. 폼 백엔드를 쓰면 폼이 같은 필드를 Ikiform으로 POST합니다. Ikiform은 자체 도메인에서 이메일을 보내고 방문자의 주소를 Reply-To에 넣습니다. Reply-To는 원래 그런 용도입니다.
전달률을 해결하는 것은 더 나은 스크립트가 아닙니다. 발송이 허용된 도메인에서 보내는 것입니다.

폼을 PHP에서 옮기기

필드 이름은 그대로 두세요. 바뀌는 것은 action과 숨김 입력 두 개뿐입니다.

변경 전
<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")숨김 입력 _redirect, 또는 폼 설정의 Redirect after submit
Reply-To: $email필드 이름이 email이므로 자동
$subject = "Website enquiry from $name"New submission: <form name>으로 고정. 비슷한 문구를 유지하려면 폼 이름을 "Website enquiry"로 지으세요
echo "Sorry, something went wrong."일반 POST에는 Ikiform의 오류 페이지, fetch를 쓰면 직접 만든 메시지
직접 작성한 적 없는 검사_gotcha 허니팟, 스팸 점수, 레이트 리밋, 필드 검증
  • Allowed domains에 도메인을 추가하세요. _redirect는 그 도메인 중 하나에 있는 https: URL일 때만 동작합니다.
  • 새 폼이 동작하면 서버에서 contact.php를 삭제하세요. 잊고 남겨 둔 스크립트는 URL을 기억하는 봇에게 여전히 열린 메일 릴레이입니다.
  • 정적 호스팅으로 옮겼다면 예전 /contact.php URL은 더 이상 존재하지 않습니다. 그 URL로 바로 POST하는 봇은 404를 받으며, 그걸로 괜찮습니다.
폼이 스크립트가 아니라 WordPress 플러그인이었다면 같은 방식이 적용됩니다. 블록 테마에서 폼을 어디에 넣는지는 WordPress 가이드에서 설명합니다.

동작 확인하기

  1. 폼의 Allowed domains에 사이트 도메인을 추가하고, 개발하는 동안에는 localhost도 추가하세요. 비워 두면 어디서 온 POST든 받습니다.
  2. 실제 페이지에서 폼을 제출하세요. 예전 thanks.html로 이동합니다.
  3. 대시보드에서 Submissions를 여세요. 보낸 모든 필드가 담긴 새 제출이 있습니다.
  4. 이메일을 여세요. 방문자 주소가 아니라 Ikiform에서 왔고, 스팸함에 있지 않습니다. 이후 메일도 그렇도록 발신자를 연락처에 추가하세요.
  5. Reply를 누르세요. To 줄에 방문자의 주소가 있습니다.
  6. 허니팟을 채워서 _gotcha=bot으로 POST하세요. 성공 응답은 받지만 제출은 스팸으로 저장되고 이메일도 웹훅도 보내지 않습니다.

주의할 점

  • 대괄호가 들어간 예전 폼 이름. PHP 폼은 contact[email] 같은 이름을 자주 씁니다. Ikiform은 이름을 그대로 저장하지만, 회신 주소는 email이나 그와 비슷한 몇 가지 이름의 필드에서만 가져옵니다. 필드 이름을 바꾸거나 _replyto를 추가하세요.
  • 제목에 이름을 넣을 수 없습니다. 스크립트의 제목에는 방문자 이름이 들어 있었습니다. 알림 제목은 고정이며, _subject는 이메일을 바꾸지 않고 웹훅과 API로 전달됩니다.
  • 문자 인코딩. mail() 스크립트는 문자 집합을 지정하지 않아 악센트 문자가 자주 깨졌습니다. Ikiform의 이메일은 UTF-8이므로 어떤 문자로 쓴 이름이든 그대로 도착합니다.
  • $to에 든 여러 주소. 스크립트의 쉼표 목록은 대시보드에서 각각의 수신자가 됩니다. 외부 주소는 무언가를 받기 전에 링크로 확인합니다. 여러 수신자를 참고하세요.

문제가 생기면

문제해결 방법
브라우저가 여러분의 감사 페이지 대신 Ikiform의 감사 페이지로 이동함_redirect는 도메인이 Allowed domains에 있고 https: URL일 때만 따릅니다. 도메인을 추가하거나, 대신 폼 설정에서 Redirect after submit을 지정하세요.
403 origin_not_allowed가 나거나 모든 POST가 스팸으로 감페이지의 도메인이 폼의 Allowed domains에 없습니다. 도메인을 추가하고, 로컬 테스트용으로 localhost도 추가하세요. 등록한 도메인의 하위 도메인도 허용됩니다.
폼이 아직 PHP 파일로 POST함캐시된 페이지나 푸터 인클루드 같은 폼의 두 번째 사본에 예전 action이 남아 있습니다. 사이트에서 contact.php를 검색하세요.
대시보드에는 제출이 있는데 이메일도 웹훅도 오지 않음스팸으로 저장된 것입니다. 스팸은 아무것도 보내지 않습니다. Spam 필터에서 열어 이유를 확인하고, 스팸이 아님으로 표시하면 이메일과 웹훅이 발송됩니다.

질문

막히는 단계가 있거나 내 상황에 맞는 가이드가 필요하다면 이메일을 보내세요: hello@ikiform.com.