PHP Mail
Today, we will discuss the mail() function in PHP. This function is used to send email messages from a PHP script.
PHP's built-in mail() function sends email straight from a script — no extra library required. It is the quickest way to fire off a notification, a "contact us" message, or a password-reset link. This chapter explains the function's signature, walks through plain-text and HTML examples, and covers the security and deliverability pitfalls that trip people up in production.
What the mail() Function Does
mail() hands a message to the server's local mail transfer agent (MTA) — the program (such as Sendmail, Postfix, or Exim) that actually relays mail to the outside world. PHP does not talk to remote SMTP servers itself; it only queues the message locally. If the host has no working MTA, mail() returns false and nothing is sent.
The function returns a boolean: true if the message was accepted for delivery (not the same as delivered), and false on failure.
Syntax
mail(
string $to,
string $subject,
string $message,
array|string $additional_headers = [],
string $additional_params = ""
): bool| Parameter | Required | Description |
|---|---|---|
$to | Yes | Recipient address(es). Separate multiple addresses with a comma. |
$subject | Yes | Subject line. Must not contain newlines. |
$message | Yes | The email body. Lines should be separated by \r\n and no longer than 70 characters. |
$additional_headers | No | Extra headers such as From, Reply-To, or Content-Type. As of PHP 7.2 this can be an associative array. |
$additional_params | No | Extra command-line flags passed to the MTA (for example, the envelope sender via -f). |
Sending a Plain-Text Email
This is the most common case: a simple text message with a few headers.
<?php
$to = '[email protected]';
$subject = 'Test email';
$message = 'This is a test email from PHP.';
// Additional headers
$headers = 'From: [email protected]' . "\r\n";
$headers .= 'Reply-To: [email protected]' . "\r\n";
$headers .= 'X-Mailer: PHP/' . phpversion();
if (mail($to, $subject, $message, $headers)) {
echo 'Email sent successfully.';
} else {
echo 'Failed to send email.';
}
?>We set the recipient, subject, and body, then build a headers string. The From header identifies the sender, Reply-To controls where replies go, and X-Mailer is informational. Headers are joined with \r\n (carriage return + line feed), which is the line ending the email protocol requires.
Sending an HTML Email
To send formatted HTML, add Content-type: text/html to the headers. Without it, the recipient sees raw tags instead of rendered markup.
<?php
$to = '[email protected]';
$subject = 'HTML email';
$message = '
<html>
<body>
<h1>Hello!</h1>
<p>This message is <strong>formatted with HTML</strong>.</p>
</body>
</html>';
// To send HTML mail, the Content-type header must be set
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=UTF-8' . "\r\n";
$headers .= 'From: [email protected]' . "\r\n";
mail($to, $subject, $message, $headers);
?>Sending to Multiple Recipients
Pass a comma-separated list in $to, or use Cc/Bcc headers:
<?php
$to = '[email protected], [email protected]';
$subject = 'Team update';
$message = 'Meeting moved to 3 PM.';
$headers = 'From: [email protected]' . "\r\n";
$headers .= 'Bcc: [email protected]' . "\r\n";
mail($to, $subject, $message, $headers);
?>Guard Against Header Injection
If any part of a header — especially From or Reply-To — comes from user input (such as a contact form), an attacker can inject extra newlines to add their own headers and turn your script into a spam relay. Never put raw user input into headers. Validate and sanitize first:
<?php
// $_POST['email'] comes from an untrusted form
$email = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL);
if ($email === false) {
exit('Invalid email address.');
}
// Strip any line breaks that could be used to inject headers
$email = str_replace(["\r", "\n"], '', $email);
$headers = 'From: ' . $email . "\r\n";
mail('[email protected]', 'Contact form', 'New message', $headers);
?>See filter_var() and the PHP Filter chapter for more on validating input, and PHP Form Validation for handling form data safely.
Deliverability and Production Notes
Note: The
mail()function relies on the server's local MTA. On many modern hosting environments it fails silently or lands in spam without proper configuration. For real applications, prefer an established library such as PHPMailer or Symfony Mailer, which support SMTP authentication, attachments, encoding, and queueing. Whichever route you choose, give your domain valid SPF, DKIM, and DMARC records so mailbox providers trust your messages.
A returned true only means the MTA accepted the message — it is not a delivery confirmation. To track actual delivery, bounces, and opens, use a transactional email service.
Common Use Cases
- Contact forms — collect a message and email it to the site owner (combine with PHP Form Handling).
- Notifications — order confirmations, alerts, password resets.
- Reports — scheduled scripts that email a summary.
Conclusion
PHP's mail() function offers a quick, dependency-free way to send email from a script: supply the recipient, subject, and body, then add headers for the sender, reply address, or HTML content. Keep its limitations in mind — it depends on a configured MTA, returns acceptance rather than delivery, and must never receive unsanitized user input in its headers. For anything beyond simple, low-volume mail, reach for a dedicated library. To keep building, explore PHP Functions and PHP Strings.