폼을 이메일로 보내기4분 분량
PHP 없이 HTML 폼을 이메일로 보내기
mail()을 호출하는 contact.php 스크립트를 호스팅 엔드포인트로 POST하는 폼으로 바꾸세요. 필드 이름, 감사 페이지, 답장은 그대로 유지됩니다.
폼의 action을 PHP 스크립트에서 폼 백엔드의 URL로 바꾸고, 필드 이름은 그대로 두고, 스크립트는 삭제하세요. 백엔드가 mail()이 하던 일에 더해, 그동안 제대로 못 하던 일까지 처리합니다. 스팸 필터링, 저장, 그리고 스팸함에 들어가지 않는 메일입니다. PHP를 전혀 실행할 수 없는 정적 호스팅에서도 동작합니다.
이 경우가 다른 점
대부분의 PHP 문의 폼은 몇 년 전 튜토리얼에서 복사한 똑같은 스무 줄입니다. $_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.";
}무해해 보이고, 작성 당시에는 동작했습니다. 하지만 지금은 네 가지 방식으로 망가지며, 눈에 띄는 것은 첫 번째뿐입니다.
| 문제 | 원인 |
|---|---|
| 호스팅에 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를 운영하고 있다면 해 볼 만한 작업입니다. 그렇지 않다면 이 일을 폼 백엔드로 넘기세요.
- contact.php를 쓰면 폼이 호스팅으로 POST하고, mail()은 방문자가 보냈다고 주장하는 메시지를 보냅니다. 수신 서버는 도메인과 맞지 않는 발신자를 보고 스팸으로 분류하거나 버립니다.
- 폼 백엔드를 쓰면 폼이 같은 필드를 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.phpURL은 더 이상 존재하지 않습니다. 그 URL로 바로 POST하는 봇은404를 받으며, 그걸로 괜찮습니다.
동작 확인하기
- 폼의 Allowed domains에 사이트 도메인을 추가하고, 개발하는 동안에는
localhost도 추가하세요. 비워 두면 어디서 온 POST든 받습니다. - 실제 페이지에서 폼을 제출하세요. 예전
thanks.html로 이동합니다. - 대시보드에서 Submissions를 여세요. 보낸 모든 필드가 담긴 새 제출이 있습니다.
- 이메일을 여세요. 방문자 주소가 아니라 Ikiform에서 왔고, 스팸함에 있지 않습니다. 이후 메일도 그렇도록 발신자를 연락처에 추가하세요.
- Reply를 누르세요. To 줄에 방문자의 주소가 있습니다.
- 허니팟을 채워서
_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 필터에서 열어 이유를 확인하고, 스팸이 아님으로 표시하면 이메일과 웹훅이 발송됩니다. |
질문
네. 폼의 action을 바꾸기 전까지 예전 스크립트는 계속 동작합니다. 먼저 페이지 사본에서 새 엔드포인트를 테스트한 뒤 전환하고 스크립트를 삭제하면 됩니다.
네. 폼의 action을 PHP 스크립트 대신 폼 백엔드로 지정하세요. 백엔드가 POST를 받아 이메일을 보내므로, 사이트는 어떤 정적 호스팅에서든 일반 HTML로 둘 수 있습니다.
스크립트는 보통 From 헤더를 방문자의 주소로 설정하지만, 메일은 호스팅 서버에서 나갑니다. 그래서 방문자 도메인의 SPF와 DMARC 검사에 실패하고, Gmail과 Outlook은 이를 위조로 취급합니다. 폼 백엔드는 자체 도메인에서 보내고 방문자는 대신 Reply-To에 넣습니다.
아니요. Ikiform은 POST한 이름을 그대로 저장합니다. 답장이 방문자에게 가도록 이메일 필드 이름은 email, email_address, your_email, reply_to, contact_email 중 하나로 유지하거나 _replyto 필드를 추가하세요.
도메인에 SPF와 DKIM을 설정하고 제공업체를 통해 보내면 전달률 문제는 해결됩니다. 그래도 PHP 호스팅, 검증, 스팸 필터링, 메시지를 보관할 곳은 여전히 필요합니다. 이미 PHP 코드를 유지보수하고 있다면 좋은 선택입니다.
막히는 단계가 있거나 내 상황에 맞는 가이드가 필요하다면 이메일을 보내세요: hello@ikiform.com.