Sending email
A registration confirmation, a password reset, a message from a contact form — hardly any site does without email. PHP has the built-in mail() function, but real projects send email through a mail server over the SMTP protocol.
The examples send mail and do not run here — run them on your machine.
The mail function
<?php
// send.php
$sent = mail(
'anna@example.com',
'Order received',
'Thank you! Your order #42 is being processed.',
['From' => 'shop@example.com']
);
echo $sent ? 'Sent' : 'Error';The arguments: recipient, subject, text, headers. The function returns true when the email is accepted for delivery — which does not yet mean it arrived.
Why mail is not enough
mail() hands the email to the server's mail program. A home computer usually has none, and emails from a hosting account often land in spam without extra setup. So email is sent through a mail service's SMTP server — with a login and a password, as a mail client does.
PHPMailer
The most widespread library for this is PHPMailer:
composer require phpmailer/phpmailer<?php
// send.php
require 'vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->Port = 587;
$mail->SMTPAuth = true;
$mail->Username = getenv('MAIL_USER');
$mail->Password = getenv('MAIL_PASSWORD');
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->CharSet = 'UTF-8';
$mail->setFrom('shop@example.com', 'Shop');
$mail->addAddress('anna@example.com', 'Anna');
$mail->Subject = 'Order received';
$mail->Body = 'Thank you! Your order #42 is being processed.';
$mail->send();The true argument in the constructor turns exceptions on: on failure send() throws an error with a description.
An HTML email
<?php
// send-html.php
$mail->isHTML(true);
$mail->Subject = 'Order received';
$mail->Body = '<h1>Thank you!</h1><p>Your order <b>#42</b> is being processed.</p>';
$mail->AltBody = 'Thank you! Your order #42 is being processed.';AltBody is the text version for mail clients that do not show HTML.
Attachments
<?php
// send-invoice.php
$mail->addAttachment(__DIR__ . '/invoices/42.pdf', 'Invoice.pdf');Handling errors
<?php
// send-safe.php
use PHPMailer\PHPMailer\Exception;
try {
$mail->send();
echo 'The email was sent';
} catch (Exception $e) {
error_log('Mail: ' . $mail->ErrorInfo);
echo 'Could not send the email. Please try again later.';
}Details go to the log, and the visitor sees a general phrase.
Checking during development
To avoid sending real emails during development, use the Mailpit program: it accepts emails over SMTP and shows them in the browser. In the settings it is enough to set Host = 'localhost' and Port = 1025.
Common mistake
Form data must not be put into headers unchecked. If a visitor types a line break and Bcc: … into the email field, your site sends spam in your name. Validate the address with filter_var() and do not put the visitor's address into From — Reply-To exists for replies:
<?php
// contact.php
$email = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL);
if ($email === false) {
exit('Invalid email address');
}
$mail->setFrom('site@example.com', 'Site');
$mail->addReplyTo($email);