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

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

2026-10-25 게시 · https://ikiform.com/ko/guides/send-form-to-email/without-php

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

## 이 경우가 다른 점

대부분의 PHP 문의 폼은 몇 년 전 튜토리얼에서 복사한 똑같은 스무 줄입니다. `$_POST`를 읽고, 문자열을 만들고, `mail()`을 호출하고, 리디렉션합니다. 전형적인 예는 이렇습니다.

`contact.php`:

```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()을 쓰는 폼과 폼 백엔드를 쓰는 같은 폼

1. contact.php를 쓰면 폼이 호스팅으로 POST하고, mail()은 방문자가 보냈다고 주장하는 메시지를 보냅니다. 수신 서버는 도메인과 맞지 않는 발신자를 보고 스팸으로 분류하거나 버립니다.
2. 폼 백엔드를 쓰면 폼이 같은 필드를 Ikiform으로 POST합니다. Ikiform은 자체 도메인에서 이메일을 보내고 방문자의 주소를 Reply-To에 넣습니다. Reply-To는 원래 그런 용도입니다.

전달률을 해결하는 것은 더 나은 스크립트가 아닙니다. 발송이 허용된 도메인에서 보내는 것입니다.

## 폼을 PHP에서 옮기기

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

`변경 전`:

```html
<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>
```

`변경 후`:

```html
<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 가이드](https://ikiform.com/ko/docs/guides/wordpress.md)에서 설명합니다.

## 동작 확인하기

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`에 든 여러 주소.** 스크립트의 쉼표 목록은 대시보드에서 각각의 수신자가 됩니다. 외부 주소는 무언가를 받기 전에 링크로 확인합니다. [여러 수신자](https://ikiform.com/ko/guides/send-form-to-email/multiple-recipients.md)를 참고하세요.

## 문제가 생기면

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

## 질문

### 전환하는 동안 예전 폼이 계속 동작하나요?

네. 폼의 action을 바꾸기 전까지 예전 스크립트는 계속 동작합니다. 먼저 페이지 사본에서 새 엔드포인트를 테스트한 뒤 전환하고 스크립트를 삭제하면 됩니다.

### PHP 없이 HTML 폼을 이메일로 보낼 수 있나요?

네. 폼의 action을 PHP 스크립트 대신 폼 백엔드로 지정하세요. 백엔드가 POST를 받아 이메일을 보내므로, 사이트는 어떤 정적 호스팅에서든 일반 HTML로 둘 수 있습니다.

### PHP mail()로 보낸 이메일은 왜 스팸함에 들어가나요?

스크립트는 보통 From 헤더를 방문자의 주소로 설정하지만, 메일은 호스팅 서버에서 나갑니다. 그래서 방문자 도메인의 SPF와 DMARC 검사에 실패하고, Gmail과 Outlook은 이를 위조로 취급합니다. 폼 백엔드는 자체 도메인에서 보내고 방문자는 대신 Reply-To에 넣습니다.

### 필드 이름을 바꿔야 하나요?

아니요. Ikiform은 POST한 이름을 그대로 저장합니다. 답장이 방문자에게 가도록 이메일 필드 이름은 email, email_address, your_email, reply_to, contact_email 중 하나로 유지하거나 _replyto 필드를 추가하세요.

### SMTP를 쓰는 PHPMailer가 더 나은 선택인가요?

도메인에 SPF와 DKIM을 설정하고 제공업체를 통해 보내면 전달률 문제는 해결됩니다. 그래도 PHP 호스팅, 검증, 스팸 필터링, 메시지를 보관할 곳은 여전히 필요합니다. 이미 PHP 코드를 유지보수하고 있다면 좋은 선택입니다.

## 가이드 더 보기

- [폼을 이메일로 보내기](https://ikiform.com/ko/guides/send-form-to-email.md): 메일 서버 없이 모든 폼 제출을 받은편지함으로 받으세요. mailto:와 PHP mail()이 실패하는 이유와, 스팸을 거르고 바로 답장할 수 있는 설정을 다룹니다.
- [Gmail로](https://ikiform.com/ko/guides/send-form-to-email/gmail.md): mailto: 링크, 앱 비밀번호, Apps Script 없이 Gmail에서 폼 제출을 받고, 라벨을 붙이고, 스팸함을 피하고, Gmail에서 답장하세요.
- [받은편지함에서 답장하기](https://ikiform.com/ko/guides/send-form-to-email/reply-to.md): 폼 알림에서 답장을 누르면 폼을 작성한 사람에게 가도록 하세요. 어떤 필드 이름이 동작하는지, _replyto는 언제 쓰는지, 답장이 엉뚱한 곳으로 가는 이유를 다룹니다.
- [여러 수신자](https://ikiform.com/ko/guides/send-form-to-email/multiple-recipients.md): 폼이 직접 수신자를 고르게 하지 않고도, 폼 하나를 팀 전체에 이메일로 보내거나 주제별로 메시지를 적절한 사람에게 보내세요.
- [EmailJS 대안](https://ikiform.com/ko/guides/send-form-to-email/emailjs-alternative.md): 문의 폼을 EmailJS에서 옮기세요. 브라우저 측 이메일 키가 위험한 이유, 코드에서 바뀌는 점, 자동 응답처럼 포기하는 기능을 다룹니다.
- [Next.js](https://ikiform.com/ko/guides/send-form-to-email/nextjs.md): Server Action으로 Next.js 폼을 이메일로 보내는 두 가지 방법: Resend나 Nodemailer로 직접 보내기와 폼 백엔드로 전달하기를 솔직하게 비교합니다.
