Le courrier envoyé par une application échoue d'ordinaire en silence. La fonction renvoie true, le message est remis à un processus local, et rien ne vous dit qu'il a été refusé une heure plus tard. Le remède : envoyer en SMTP authentifié, où un échec est une erreur que vous voyez.

N'utilisez pas mail()

  • Elle indique si le message a été remis, pas s'il a été délivré.
  • Elle envoie sous l'identité du serveur web, si bien que SPF et DKIM échouent en général.
  • Elle n'a ni authentification, ni nouvelle tentative, ni journal lisible.

Utilisez SMTP

use PHPMailer\PHPMailer\PHPMailer;

$m = new PHPMailer(true);
$m->isSMTP();
$m->Host       = 'mail.yourdomain.com';
$m->SMTPAuth   = true;
$m->Username   = 'noreply@yourdomain.com';
$m->Password   = getenv('SMTP_PASS');
$m->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
$m->Port       = 465;

$m->setFrom('noreply@yourdomain.com', 'Your Shop');
$m->addReplyTo('support@yourdomain.com');
$m->addAddress($customerEmail);
$m->Subject = 'Your order';
$m->Body    = $text;
$m->send();
Ne mettez jamais le mot de passe dans le code. Lisez-le depuis l'environnement, et gardez le fichier d'environnement hors de la racine web et hors de git.

Le From doit être votre propre domaine

Mettre l'adresse du client dans le From pour que les réponses fonctionnent est l'erreur classique : vous envoyez alors en tant que gmail.com, ce qui échoue net à leur SPF et à leur DMARC. Envoyez sous votre domaine et mettez Reply-To sur la leur.

Envoyez en arrière-plan

Envoyer pendant la requête fait attendre le visiteur derrière un serveur distant et transforme une panne de courrier en paiement cassé. Mettez en file et envoyez depuis un worker.

Et journalisez le résultat

$m->SMTPDebug = 2;   // development only
// production: record the message ID and the accept/reject per recipient
Pour tout ce qui est transactionnel - reçus, réinitialisations de mot de passe - passez par un service d'envoi dédié. La délivrabilité est tout leur métier, et cela sépare vos reçus de vos infolettres : voyez courrier transactionnel et infolettres.