W3docs

mail()

Today, we will discuss the mail() function in PHP. This function is used to send email messages from a PHP script.

The mail() function sends email messages directly from a PHP script. It is the simplest built-in way to send mail, and this guide covers its syntax and parameters, how headers work, sending HTML and multi-recipient messages, the security pitfalls to avoid, and when you should reach for a dedicated library instead.

What is the mail() Function?

The mail() function is a built-in PHP function that hands an email off to the system's mail transfer agent (MTA) — typically sendmail on Linux — or to the SMTP server configured in php.ini. Because it depends on that local configuration, mail() frequently returns false (or silently fails to deliver) on a development machine that has no MTA installed. It does not open an SMTP connection itself, so it cannot authenticate against an external provider like Gmail.

A true return value only means the message was accepted for delivery by the MTA — it is not a guarantee the email reached the recipient's inbox.

Syntax

mail(
    string $to,
    string $subject,
    string $message,
    array|string $additional_headers = [],
    string $additional_params = ""
): bool
ParameterRequiredDescription
$toYesRecipient address(es). Multiple addresses are comma-separated, e.g. "[email protected], [email protected]".
$subjectYesThe subject line. Must not contain newlines.
$messageYesThe body. Each line should be separated by \r\n and be no longer than 70 characters.
$additional_headersNoExtra headers such as From, Cc, Bcc, Content-Type. A string (CRLF-separated) or, since PHP 7.2, an associative array.
$additional_paramsNoExtra flags passed to the MTA's command line (e.g. -f to set the envelope sender).

How to Use the mail() Function

Here is a complete, plain-text example that builds headers and checks the return value:

<?php
$to      = '[email protected]';
$subject = 'Test email';
$message = 'This is a test email from PHP';

// Additional headers
$headers = 'From: [email protected]' . "\r\n"
         . 'Reply-To: [email protected]' . "\r\n"
         . 'X-Mailer: PHP/' . phpversion();

// Send the email and check the result
if (mail($to, $subject, $message, $headers)) {
    echo "Email sent successfully.";
} else {
    echo "Email delivery failed.";
}
?>

We define the recipient, subject, and message, then construct the headers. Since mail() returns a boolean, it's best practice to check the return value rather than assume success. The From header matters: without it, many mail servers reject the message or mark it as spam.

Sending an HTML Email

To send HTML instead of plain text, add Content-Type: text/html to the headers. Without it, the client displays the raw tags as text.

<?php
$to      = '[email protected]';
$subject = 'HTML email test';
$message = '<h1>Hello</h1><p>This message is <b>HTML</b>.</p>';

$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);
?>

Multiple Recipients, Cc and Bcc

Put several addresses in $to (comma-separated) for the visible "To" line, and use Cc/Bcc headers for copies:

<?php
$to      = '[email protected], [email protected]';
$subject = 'Team update';
$message = 'See attached agenda.';

$headers  = "From: [email protected]\r\n";
$headers .= "Cc: [email protected]\r\n";
$headers .= "Bcc: [email protected]\r\n";

mail($to, $subject, $message, $headers);
?>

Recipients in Bcc are hidden from everyone else, while Cc addresses are visible to all recipients.

Security: Avoiding Header Injection

If any part of the recipient, subject, or headers comes from user input — for example a contact form — an attacker can inject extra newlines to add their own Cc/Bcc headers and hijack your server into sending spam. Always validate addresses and strip line breaks before passing them to mail():

<?php
$email = $_POST['email'] ?? '';

// Reject anything that is not a valid email address
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    exit('Invalid email address.');
}

// Strip CR/LF so the value can't inject new headers
$email = str_replace(["\r", "\n"], '', $email);
?>

Use filter_var() with FILTER_VALIDATE_EMAIL to validate, and see PHP Form Validation and Form URL/E-mail handling for safe form processing patterns.

Limitations and When to Use a Library

mail() is fine for simple, low-volume messages, but it has real limits:

  • It cannot authenticate against an external SMTP server (no username/password, TLS handshake).
  • It offers no native support for attachments — you must hand-build MIME parts.
  • Error reporting is minimal: a false return tells you little about why delivery failed.

For production, transactional email, or anything with attachments, use a dedicated library such as PHPMailer or Symfony Mailer. They handle SMTP authentication, encoding, attachments, and far better error reporting.

Conclusion

The mail() function provides a quick way to send email straight from PHP and is well suited to simple notifications when a working MTA is available. Remember that its success depends on server configuration, that you must guard against header injection with user-supplied data, and that production systems are usually better served by PHPMailer or Symfony Mailer. For related reading, explore PHP Functions and the header() function.

Practice

Practice
What is correct about the PHP mail() function according to the content of the provided URL?
What is correct about the PHP mail() function according to the content of the provided URL?
Was this page helpful?