If you searched for "php mail function", "send email php", or "php send email", this guide explains exactly what mail() can do, where it fails, and when to use a better option.

Quick answer: what does mail() do in PHP?

mail() asks the server mail transport to send a message. On Unix-like systems this is usually sendmail/Postfix. On Windows, PHP uses SMTP settings in php.ini.

mail() is useful for simple cases, but it lacks modern SMTP ergonomics, robust error insight, and built-in retry controls.

Basic mail() usage

<?php
$to = 'recipient@example.com';
$subject = 'Test Mail';
$message = 'Hello, this is a test email.';
$headers = "From: no-reply@example.com\r\n";

if (mail($to, $subject, $message, $headers)) {
    echo "Email sent successfully";
} else {
    echo "Email send failed";
}

Sending HTML with mail()

For HTML email, set MIME headers correctly:

<?php
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/html; charset=UTF-8\r\n";
$headers .= "From: no-reply@example.com\r\n";

$html = "<h1>Welcome</h1><p>Your account is ready.</p>";
mail('recipient@example.com', 'Welcome', $html, $headers);

If headers are malformed, clients may render raw HTML or reject the message.

PHP mail setup requirements

Linux/macOS

Verify sendmail_path in php.ini:

sendmail_path = "/usr/sbin/sendmail -t -i"

Windows

Configure SMTP host and port in php.ini:

[mail function]
SMTP = smtp.example.com
smtp_port = 587
sendmail_from = no-reply@example.com

After changes, restart PHP-FPM/Apache/IIS to apply configuration.

Common PHP mail errors and fixes

mail() returns false

  • local MTA is missing or unreachable
  • process permissions block mail binary execution
  • malformed headers break message construction

Message accepted but never delivered

  • SPF/DKIM/DMARC missing or invalid
  • sender reputation or policy rejection
  • recipient-side spam filtering

SMTP auth failures

When using authenticated SMTP relays, verify port/TLS/auth mode. See SMTP authentication troubleshooting.

When to use PHPMailer or Symfony Mailer instead

Use a dedicated library when you need:

  • authenticated SMTP with clear transport options
  • richer attachments and templates
  • better exception handling and debugging
  • OAuth/provider API integrations

If your application is production-critical, library-based SMTP/API patterns are usually safer than raw mail().

Testing PHP email flows end to end

Unit tests around mail() are not enough. Also validate:

  • real inbox arrival
  • content and headers
  • links/OTP extraction
  • latency and retry behavior

MailSlurp provides disposable inboxes and wait-for-email APIs for automated testing. Related resources:

Production PHP mail reliability checklist

Whether you keep mail() or migrate to SMTP libraries, use this model:

  1. Validate output templates and recipients in an email sandbox.
  2. Add deterministic regression checks with email integration testing.
  3. Track send, bounce, and failure events through email webhooks.
  4. Route retry and fallback behavior with email automation routing.
  5. Run recurring deliverability tests to catch policy and reputation drift.

This prevents silent failures that often happen with PHP email code in production.

FAQ

Is PHP mail() deprecated?

No, but it is minimal and often insufficient for modern production workflows.

Can I send attachments with mail()?

Yes, but MIME multipart formatting is manual and error-prone. Libraries are easier and safer.

Why does mail() work locally but fail in production?

Production environments enforce stricter transport, auth, and domain policy requirements.

Final take

mail() still works for basic sending, but production systems usually need stronger SMTP/API controls, clearer observability, and deterministic testing.