Skip to content
FormSubmit

HTML

PHP email form: the problems with mail() and a contact form without PHP

How a PHP email form works, why mail() causes spam-folder, security and hosting problems, and how to run a contact form without PHP instead.

6 min readUpdated Oct 8, 2026

A PHP email form posts to a .php script that calls mail() to send the message, but that approach often lands in spam, is easy to get wrong securely, and doesn't run on static hosts. To build a contact form without PHP, set the form's action to a hosted form endpoint such as https://formsubmit.app/f/YOUR_FORM_ID. The form backend receives the submission, filters spam and emails it to you from a properly authenticated sending domain. If you already have a PHP form, you can switch by changing one attribute and keeping all your field names.

This guide shows a typical PHP email form honestly, explains where it breaks, and then walks through the no-PHP alternative and a migration.

How a typical PHP email form works

Most "email form HTML PHP" tutorials have two files: an HTML form and a script that sends it.

contact.html
<form action="send.php" method="POST">
  <label for="name">Name</label>
  <input id="name" type="text" name="name" required>

  <label for="email">Email</label>
  <input id="email" type="email" name="email" required>

  <label for="message">Message</label>
  <textarea id="message" name="message" required></textarea>

  <button type="submit">Send</button>
</form>
send.php
<?php
// A typical copy-paste handler. Shown for illustration, not as a recommendation.
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
    http_response_code(405);
    exit;
}

$name    = trim($_POST["name"] ?? "");
$email   = trim($_POST["email"] ?? "");
$message = trim($_POST["message"] ?? "");

if ($name === "" || !filter_var($email, FILTER_VALIDATE_EMAIL) || $message === "") {
    http_response_code(400);
    exit("Please fill in all fields.");
}

$to      = "you@example.com";
$subject = "New message from your website";
$body    = "Name: $name\nEmail: $email\n\n$message";
$headers = "From: website@example.com\r\nReply-To: $email";

if (mail($to, $subject, $body, $headers)) {
    header("Location: /thanks.html", true, 303);
} else {
    http_response_code(500);
    echo "Sorry, your message could not be sent.";
}

This is a reasonably careful version. It checks the method, validates the email before using it in a header, and sends from your own address rather than the visitor's. Plenty of scripts in the wild skip all three. Even so, it has problems that the code can't fix.

The problems with PHP mail()

Deliverability: emails land in spam or vanish

mail() hands the message to the server's local mail program, which sends it from your host's shared server. Unless your domain's SPF record allows that server, and the message is signed with DKIM for your domain, Gmail and Outlook have little reason to trust it. Many scripts make it worse by setting From: to the visitor's address, which looks exactly like spoofing and can fail DMARC checks outright.

The result is the classic "my contact form doesn't send email" problem. The script reports success, but the message is filtered, delayed or silently dropped. Fixing it means editing DNS records, configuring SMTP through a library such as PHPMailer, and often paying for a transactional email provider. Contact form emails going to spam covers this in depth.

Header injection

The fourth argument to mail() is raw email headers. If any user input reaches it without validation, an attacker can submit a value containing line breaks and add their own Bcc: header, turning your form into a spam relay for other people's mail. Validating with filter_var as above helps, but it's easy to forget when you add a field later.

Spam submissions

A bare PHP script has no spam protection. Bots find it within days. Adding a honeypot, rate limiting, duplicate detection, content scoring and a captcha is all code you have to write, test and keep current.

Hosts that disable or limit mail()

Many hosts disable mail(), rate-limit it, or require you to use their SMTP server with authentication. And static hosts such as GitHub Pages, Netlify, Vercel and Cloudflare Pages don't run PHP at all, so send.php is downloaded or returns a 404 instead of executing.

Maintenance and no record

You own the PHP version upgrades, the security patches and the debugging. There's also no record of submissions. If an email is lost, the message is gone, because nothing stored it.

A contact form without PHP

A form backend replaces send.php. The browser posts the form straight to it, and it handles validation, spam filtering, storage and email. With FormSubmit:

Create a form

Sign up with Google or email and click New form. You get an endpoint like https://formsubmit.app/f/k3m9p2qabx.

Use it as your form's action

contact.html
<form action="https://formsubmit.app/f/YOUR_FORM_ID" method="POST">
  <div>
    <label for="fs-name">Name</label>
    <input id="fs-name" type="text" name="name" placeholder="Jane Doe" required>
  </div>
  <div>
    <label for="fs-email">Email</label>
    <input id="fs-email" type="email" name="email" placeholder="jane@example.com" required>
  </div>
  <div>
    <label for="fs-message">Message</label>
    <textarea id="fs-message" name="message" rows="5" placeholder="How can we help?" required></textarea>
  </div>
  <!-- Honeypot: leave this hidden field empty to catch bots -->
  <input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="display:none">
  <!-- Optional: where to send people after submitting -->
  <!-- <input type="hidden" name="_redirect" value="https://yoursite.com/thanks"> -->
  <button type="submit">Send</button>
</form>

Test it

Submit the form. You're redirected to a thank-you page, the submission appears in your dashboard, and the notification email arrives with Reply-To set to the visitor.

Compared with the PHP version:

PHP mail() scriptFormSubmit
Server code to writeYesNone
Works on static hostsNoYes
Sent fromYour host's shared serverFormSubmit's own sending address, with the visitor in Reply-To
Spam protectionWhatever you buildHoneypot, timing check, content scoring, rate limits, optional captcha
Header injection riskYours to preventNo headers built from your HTML
Stored copy of each submissionNoYes, in your dashboard
File uploadsExtra code and storageenctype="multipart/form-data" and a file input
CostHostingFree for 1 form and 50 submissions a month

Migrate an existing PHP email form

You don't need to rebuild your form. Most PHP email forms can switch in a few minutes.

Keep your field names

FormSubmit stores whatever field names your form sends, so name, email, phone and message all keep working. Names become readable labels in the email, so company_size appears as "Company size". If your email field has an unusual name, rename it email (or add a _replyto field) so replies go to the visitor.

Change the action

html
<!-- Before -->
<form action="send.php" method="POST">

<!-- After -->
<form action="https://formsubmit.app/f/YOUR_FORM_ID" method="POST">

Keep method="POST". If the form has a file input, keep enctype="multipart/form-data" too.

Move your PHP settings into hidden fields or the dashboard

In your PHP scriptWith FormSubmit
$to = "you@example.com"Your account email by default. Add more under Notifications → Recipients.
$subject = "..."A hidden _subject field, or a subject template such as New message from {{name}} in email settings
Reply-To: $emailAutomatic, from a field named email or _replyto
header("Location: /thanks.html")A hidden _redirect field with the full URL, or a redirect URL in form settings
Required-field checksKeep the required attributes in your HTML
hidden-fields.html
<input type="hidden" name="_subject" value="New message from your website">
<input type="hidden" name="_redirect" value="https://example.com/thanks.html">
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="display:none">

See control fields and redirects for the details.

Test, then remove the PHP file

Send a test submission, check your inbox and dashboard, and then delete send.php from your server. Leaving an old mail script online invites abuse.

If you'd like to stay on the page and show an inline thank-you message instead of redirecting, see submit a form with JavaScript.

When PHP still makes sense

If you already run a PHP application, such as a custom CMS, with authenticated SMTP and proper SPF and DKIM, and you need to write submissions into your own database, keeping the handler in PHP is reasonable. Use a maintained library like PHPMailer with SMTP rather than bare mail(). For WordPress, see WordPress contact form without a plugin.

For most brochure sites, portfolios and landing pages, though, a PHP email form is a lot of moving parts for a job a form backend does in one line.

Next steps

Frequently asked questions

Can an HTML form send email without PHP?

Not by itself. HTML only sends data to a URL. Without PHP or another server language, point the form's action at a hosted form backend such as FormSubmit, which stores the submission and emails it to you.

Why do my PHP mail() emails go to spam?

mail() usually sends from your web host's shared server without SPF, DKIM or DMARC alignment for your domain. Setting the visitor's address as From makes it look like spoofing. Receiving providers filter or reject that mail.

Is PHP mail() secure?

It can be, but only if you validate every value and never put unchecked input into headers. Many copy-paste scripts insert the visitor's email into the From header, which allows header injection.

Do I have to rename my form fields to switch?

No. Keep the field names you already use. FormSubmit stores whatever names your form sends and turns them into readable labels in the email.

Does it work on hosts without PHP, like GitHub Pages or Netlify?

Yes. The browser posts directly to FormSubmit, so the page can be plain HTML on any static host.

Keep reading

Your form backend is 60 seconds away

Sign up with Google or email, create a form, paste the endpoint. Free forever for small sites — no credit card.