Sending a contact form email from a PHP website sounds simple, but in real life it often turns into “why is nothing arriving in my inbox?”. In this guide we walk through a clean, working example of the PHP mail() function so you can send email from a form with less guessing. If you do web development or run small PHP sites, this will help you get basic email notifications working with more stability and fewer surprises.
Think of mail() as PHP’s built‑in shortcut to your server’s mail system.
When you call it, PHP hands your message to the server’s mail program (like sendmail or an SMTP service). If that part is configured correctly, the email goes out.
The basic syntax looks like this:
php
mail(
string $to,
string $subject,
string $message,
string $additional_headers = "",
string $additional_params = ""
);
In this tutorial we will:
Create a simple HTML form
Write the PHP code that reads the form data
Build an HTML email body
Send the email with mail() and handle errors
Nothing fancy. Just enough to get a real message into your inbox.
You can run this example on any PHP hosting or VPS:
PHP must be installed and running (Apache, Nginx, etc.)
The server must be able to send mail (local mail server or external SMTP)
Your “From” address should match your domain for better deliverability
On some cheap or overloaded hosting, outgoing mail can be painfully unreliable. If you want more control over deliverability and performance for your PHP mail scripts, a dedicated server is usually a better option.
With that in place, let’s build the form.
Create a file called index.php and start with a basic HTML form.
php
Send Mail Using PHP
' . htmlspecialchars($_SESSION['msg']) . '
'; unset($_SESSION['msg']); } ?>
Your Email:
<label>
Subject:
<input type="text" name="subject" required>
</label>
<br><br>
<label>
Message:
<textarea name="message" rows="5" required></textarea>
</label>
<br><br>
<button type="submit" name="send" value="1">Send Email</button>
What this does:
Shows a form with three fields: email, subject, and message
Posts the data back to the same index.php file
Leaves a spot at the top to output a status message
So far, clicking “Send Email” does nothing on the server side. Next we add the PHP logic.
Now we write the PHP code at the top of index.php to grab the form data and send the email.
Place this block at the very top of the file, before <!DOCTYPE html>:
php
<?php
session_start();
if (isset($_POST['send'])) {
// 1. Read and validate input
$email = isset($_POST['email']) ? trim($_POST['email']) : '';
$subject = isset($_POST['subject']) ? trim($_POST['subject']) : '';
$message = isset($_POST['message']) ? trim($_POST['message']) : '';
$to = filter_var($email, FILTER_VALIDATE_EMAIL);
if (!$to) {
$_SESSION['msg'] = 'Please enter a valid email address.';
} elseif ($subject === '' || $message === '') {
$_SESSION['msg'] = 'Subject and message cannot be empty.';
} else {
// 2. Build an HTML email body
$mailBody = '
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo From Website</title>
</head>
<body>
<table cellpadding="4" cellspacing="0">
<tr>
<td><strong>Subject</strong></td>
<td>:</td>
<td>' . htmlspecialchars($subject) . '</td>
</tr>
<tr>
<td><strong>Message</strong></td>
<td>:</td>
<td>' . nl2br(htmlspecialchars($message)) . '</td>
</tr>
</table>
</body>
</html>';
// 3. Set From and headers
$fromName = 'My PHP Site';
$fromEmail = 'no-reply@yourdomain.com'; // use your real domain
$fromAddr = $fromName . ' <' . $fromEmail . '>';
$headers = 'From: ' . $fromAddr . "\r\n";
$headers .= 'Reply-To: ' . $fromAddr . "\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
// 4. Send the mail
if (mail($to, 'PHP mail() demo from website', $mailBody, $headers)) {
$_SESSION['msg'] = 'Your information has been sent successfully.';
} else {
$_SESSION['msg'] = 'Mail could not be sent. Check server mail configuration.';
}
}
// Refresh to avoid resubmission on reload
header('Location: ' . $_SERVER['REQUEST_URI']);
exit;
}
?>
What’s happening here, in plain terms:
We check if the form was submitted (isset($_POST['send']))
We validate the email address and make sure subject and message are not empty
We build a small HTML email using the submitted data
We set a proper From address and headers so mail clients treat it as HTML
We call mail() and store a success or error message in the session
Reload the page after pressing “Send” and you should see one of the messages at the top.
Headers are where most beginners get stuck. If headers are wrong, the email might:
Show up as plain text with HTML tags visible
Go straight to spam
Get rejected by the server
The important lines in our example:
php
$headers = 'From: ' . $fromAddr . "\r\n";
$headers .= 'Reply-To: ' . $fromAddr . "\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
From and Reply-To should be a real address on your own domain in production
MIME-Version tells the mail client what type of content follows
Content-Type: text/html tells the client to render HTML instead of raw text
If you ever see your HTML tags inside the email, you almost always forgot the Content-Type header.
You run the script, it claims “sent”, but your inbox is empty. Classic web development moment.
Try these:
Check the spam/junk folder (especially for test subjects like “test”)
Use a subject line that looks more like a real message
Try sending to a different provider (e.g., Gmail vs your work email)
On Linux, check the mail log (/var/log/mail.log or similar) if you have access
Ask your hosting provider whether PHP mail is allowed or rate-limited
On some shared hosting, mail() is disabled or heavily restricted. In that case you might switch to SMTP libraries like PHPMailer or Symfony Mailer for more control and better tracking.
With a stable hosting environment, though, the plain PHP mail() function is often enough for simple forms and notifications.
For small sites, contact forms, and simple notifications, yes, the PHP mail function can be enough. For larger apps, bulk email, or anything where deliverability really matters, you will usually use an SMTP service or a proper email library instead.
mail() returning true only means PHP handed the mail to the server. It does not guarantee delivery. Check spam, mail logs, and be sure your From address uses your own domain on a properly configured server.
No. If you just want plain text, you can send the $message without HTML tags and set the header to:
php
$headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
HTML is nice for formatting, but not required.
Yes, but:
On Windows, you often need to configure an SMTP server in php.ini
On Linux/Mac, you need a local mail transfer agent or a relay
Many developers find it easier to test mail on a real server or VPS where mail is already configured
You have a working index.php file that shows a form, reads the data, builds an HTML email, and sends it using the PHP mail() function. This is often all you need for simple web development tasks like contact forms and notification emails.
When you move from “it works on my laptop” to “real users rely on these emails,” the hosting environment suddenly matters a lot. If you want reliable delivery and full control over PHP mail configuration, 👉 why GTHost is suitable for hosting simple PHP mail() contact forms is that their instant dedicated servers give you stable resources and predictable mail behavior without complex setup. That way your PHP email scripts stay simple, and the infrastructure does the heavy lifting in the background.