NTF-001
Send mail that actually arrives from a shared host
PHP's mail() from shared hosting lands in spam. Authenticated SMTP, a real From address on your own domain, and the three DNS records that decide delivery.
Mail sent with mail() from shared hosting is unauthenticated, comes from an IP shared with hundreds of other sites, and usually has a From address the domain never authorised. It gets filed as spam or dropped silently, and the only symptom is users saying the verification email never came.
Authenticated SMTP through a real mail account fixes the sending half. The receiving half is DNS: SPF says which servers may send for your domain, DKIM signs the message, DMARC tells receivers what to do when either fails.
Without those records, no amount of correct code will get you into an inbox.
function send_mail(string $to, string $subject, string $textBody, string $htmlBody = ''): bool
{
$host = setting('smtp_host');
$port = setting_int('smtp_port', 587);
$user = setting('smtp_user');
$pass = setting('smtp_pass');
$from = setting('mail_from'); // MUST be on your own domain
$name = setting('site_name');
if ($host === '' || $from === '') {
return false;
}
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = $host;
$mail->Port = $port;
$mail->SMTPAuth = true;
$mail->Username = $user;
$mail->Password = $pass;
$mail->SMTPSecure = $port === 465 ? 'ssl' : 'tls';
$mail->CharSet = 'UTF-8';
$mail->Timeout = 15;
$mail->setFrom($from, $name);
$mail->addReplyTo($from, $name);
$mail->addAddress($to);
$mail->Subject = $subject;
if ($htmlBody !== '') {
$mail->isHTML(true);
$mail->Body = $htmlBody;
$mail->AltBody = $textBody; // never send HTML with no text part
} else {
$mail->Body = $textBody;
}
return $mail->send();
} catch (Throwable $e) {
error_log('mail failed: ' . $e->getMessage());
return false;
}
}
Using it
The three DNS records, in the order they matter:
v=spf1 include:your-mail-provider.com ~all
DKIM: the selector and public key your provider gives you
v=DMARC1; p=none; rua=mailto:you@yourdomain
Start DMARC at p=none and read the reports for a fortnight before tightening it.
Send from your own domain. A From address at a free mail provider fails DMARC at the receiver whatever you do.
What bites people
Never put the user's address in From, even for a contact form. It fails SPF at the receiver and gets your domain marked as a forger. Put it in Reply-To.
HTML with no plain text alternative is a strong spam signal on its own.
Queue mail rather than sending during the request. An SMTP timeout should not be what a user sees after signing up.