Si vos formulaires envoient “Message envoyé” mais que rien n’arrive en boîte, vous êtes souvent face à un WordPress qui expédie via mail() — et un hébergeur qui filtre, rate-limit, ou signe mal les messages. Sur WordPress 6.9.4, la voie la plus fiable reste SMTP… et vous pouvez le faire proprement sans plugin, avec un MU-plugin minimal, versionnable et auditable.

Ce qu’on va construire

Vous allez mettre en place une configuration SMTP complète pour l’envoi d’emails WordPress, sans installer de plugin. Le résultat final :

  • WordPress envoie via votre serveur SMTP (ou un relais type Mailgun/SendGrid/SMTP pro) au lieu de mail().
  • Les identités d’expéditeur (From) sont cohérentes et ne se font pas réécrire par un thème ou un builder.
  • Vous avez des logs de diagnostic exploitables (sans exposer le mot de passe SMTP).
  • Vous disposez d’une page d’admin “Test SMTP” pour valider en 30 secondes après chaque changement.

C’est destiné aux sites vitrines, blogs, WooCommerce, sites avec formulaires (Contact Form 7, Gravity Forms, WPForms…), et aux environnements où vous voulez éviter l’effet “plugin de plus” (ou les plugins de snippets qui cassent au moindre update).

À la fin, vous saurez où accrocher le code (hook phpmailer_init), comment sécuriser les secrets, et comment diagnostiquer les erreurs SMTP réelles (TLS, auth, ports, DNS).

Résumé rapide

  • On configure PHPMailer via le hook phpmailer_init (WordPress 6.9.4) pour basculer en SMTP.
  • On met le code dans un MU-plugin (wp-content/mu-plugins/) pour qu’il soit toujours chargé.
  • On stocke les secrets dans wp-config.php (ou variables d’environnement), jamais en dur dans un dépôt Git.
  • On force From / From Name et on protège contre les réécritures courantes.
  • On ajoute des logs + une page de test admin avec nonce pour valider et dépanner vite.

Quand utiliser cette solution

  • Vous voulez une configuration SMTP auditable (un fichier PHP clair) et versionnable (Git), sans interface plugin.
  • Vous gérez plusieurs environnements (local / staging / prod) et vous voulez switcher via variables d’environnement.
  • Vous avez déjà eu des conflits entre plugins “SMTP” et des plugins de formulaires (j’ai souvent vu deux configurations SMTP se battre, avec des timeouts aléatoires).
  • Vous voulez maîtriser les détails (TLS/SSL, ports, timeouts, debug) sans dépendre d’un plugin qui change d’UI.

Quand ne PAS utiliser cette solution

  • Vous n’avez pas accès aux fichiers (FTP/SFTP/SSH) ou vous ne pouvez pas éditer wp-config.php.
  • Votre organisation exige une rotation automatique des secrets via un gestionnaire (Vault/Secrets Manager) et vous n’avez pas la chaîne de déploiement adaptée.
  • Vous avez besoin d’une fonctionnalité avancée “marketing” (tracking, templates, webhooks, logs UI, retries) : un plugin ou un SDK du fournisseur sera plus adapté.
  • Vous ne pouvez pas assurer la maintenance : un snippet SMTP oublié peut casser les envois après un changement de mot de passe, et personne ne regarde les logs.

Avant de commencer (prérequis)

Versions et environnement

  • WordPress : 6.9.4 (avril 2026) ou plus récent.
  • PHP : 8.1+ (idéalement 8.2/8.3 si votre hébergeur le permet).
  • Accès : capacité à créer un fichier dans wp-content/mu-plugins/ et à modifier wp-config.php.

Sauvegarde et test

  • Faites une sauvegarde (fichiers + base) et testez d’abord sur un staging si possible. Un mauvais SMTP peut bloquer l’envoi de mails critiques (reset password, commandes WooCommerce).
  • Préparez une boîte email de test externe (Gmail, Outlook, Proton) et une adresse sur votre domaine.

Sécurité (à prendre au sérieux)

  • Ne mettez jamais le mot de passe SMTP en dur dans un thème, un plugin normal, ou un snippet copié/collé dans l’admin. Ça finit dans des exports, des backups, ou des captures d’écran.
  • Utilisez un compte SMTP dédié (ou une clé API SMTP) avec des permissions minimales.
  • Si vous activez le debug SMTP, faites-le temporairement et logguez côté serveur, pas à l’écran.

Références officielles utiles (vous allez les recroiser)


Étape 1 : Choisir votre fournisseur SMTP et récupérer les bons paramètres

Le code ne sert à rien si les paramètres SMTP sont bancals. Les erreurs que je vois le plus :

  • Port/TLS incohérents (ex : port 587 mais “SSL” au lieu de “TLS”).
  • Identifiant = email complet vs login court (ça dépend du fournisseur).
  • Nom d’hôte incorrect (ex : smtp.mail.domain.tld au lieu de smtp.domain.tld).

Paramètres typiques

Paramètre Valeur typique Notes
Host smtp.votre-fournisseur.tld Doit résoudre en DNS depuis le serveur
Port 587 STARTTLS (le plus courant)
Encryption tls STARTTLS sur 587
Port (alternative) 465 SMTPS (TLS implicite)
Auth Oui Souvent requis
Username compte SMTP / clé Parfois une clé API
Password mot de passe / secret À stocker hors dépôt

Vérification rapide côté serveur (optionnel mais utile)

Si vous avez accès SSH, testez la connectivité réseau (ça évite de coder pour découvrir ensuite que le port est bloqué par l’hébergeur).

# Test DNS
getent hosts smtp.votre-fournisseur.tld

# Test TCP (587)
nc -vz smtp.votre-fournisseur.tld 587

# Test TLS (STARTTLS sur 587)
openssl s_client -starttls smtp -connect smtp.votre-fournisseur.tld:587 -servername smtp.votre-fournisseur.tld

Résultat attendu : une connexion qui s’établit, et un certificat présenté sans erreur critique. Si nc échoue, votre hébergeur bloque peut-être le sortant SMTP.


Étape 2 : Créer un MU-plugin SMTP (propre, versionnable, sans dépendance)

Un MU-plugin est chargé automatiquement, sans activation dans l’admin. C’est parfait pour une config “infrastructure” comme SMTP. C’est aussi un bon moyen d’éviter l’erreur classique : coller le code dans functions.php puis changer de thème et tout perdre.

Où créer le fichier

  1. Ouvrez wp-content/.
  2. Si le dossier mu-plugins n’existe pas, créez-le : wp-content/mu-plugins/.
  3. Créez le fichier : wp-content/mu-plugins/bpcab-smtp.php.

Collez ce squelette (sans secrets pour l’instant)

<?php
/**
 * Plugin Name: BPCAB SMTP (MU)
 * Description: Configuration SMTP sans plugin via PHPMailer pour WordPress 6.9.4+.
 * Author: Votre Nom
 * Version: 1.0.0
 *
 * Ce fichier est un MU-plugin : placez-le dans wp-content/mu-plugins/.
 */

defined('ABSPATH') || exit;

/**
 * Retourne une valeur de configuration SMTP depuis :
 * 1) une constante (wp-config.php)
 * 2) une variable d'environnement
 *
 * Note : on ne met PAS de valeurs par défaut sensibles ici.
 */
function bpcab_smtp_get_config(string $key, $default = null) {
	$const = 'BPCAB_SMTP_' . strtoupper($key);

	if (defined($const)) {
		return constant($const);
	}

	$env = getenv($const);
	if ($env !== false && $env !== '') {
		return $env;
	}

	return $default;
}

/**
 * Active/désactive SMTP. Pratique pour un rollback rapide.
 */
function bpcab_smtp_is_enabled(): bool {
	return (bool) bpcab_smtp_get_config('enabled', false);
}

Résultat attendu après cette étape : rien ne change encore, mais votre site ne doit pas planter. Si vous avez un écran blanc, vous avez probablement :

  • Copié le fichier au mauvais endroit (ex : wp-content/plugins au lieu de mu-plugins), ou
  • Introduit une erreur de syntaxe (parenthèse/point-virgule).

Étape 3 : Injecter les identifiants de façon sûre (wp-config.php et variables d’environnement)

Le piège classique : mettre $password = 'monmdp'; dans le MU-plugin, committer, puis le mot de passe se retrouve dans le dépôt, un zip envoyé à un client, ou un backup partagé. Je l’ai vu trop souvent.

Méthode A (simple) : constantes dans wp-config.php

Éditez wp-config.php et ajoutez au-dessus de la ligne “That’s all, stop editing!” :

/** SMTP - Configuration (ne pas committer si votre wp-config est versionné) */
define('BPCAB_SMTP_ENABLED', true);
define('BPCAB_SMTP_HOST', 'smtp.votre-fournisseur.tld');
define('BPCAB_SMTP_PORT', 587);            // 587 (STARTTLS) ou 465 (SMTPS)
define('BPCAB_SMTP_ENCRYPTION', 'tls');    // 'tls', 'ssl' ou '' (déconseillé)
define('BPCAB_SMTP_USERNAME', 'votre-identifiant');
define('BPCAB_SMTP_PASSWORD', 'votre-secret-long-et-unique');

/** Identité d'envoi */
define('BPCAB_SMTP_FROM_EMAIL', '[email protected]');
define('BPCAB_SMTP_FROM_NAME', 'Votre Site');

/** Options de robustesse */
define('BPCAB_SMTP_TIMEOUT', 10);          // en secondes
define('BPCAB_SMTP_DEBUG', false);         // true temporairement, pour diagnostiquer

Méthode B (pro) : variables d’environnement

Sur un hébergement géré (ou via Docker), préférez des variables d’environnement. Votre MU-plugin les lit déjà via getenv(). Exemples :

export BPCAB_SMTP_ENABLED=1
export BPCAB_SMTP_HOST="smtp.votre-fournisseur.tld"
export BPCAB_SMTP_PORT="587"
export BPCAB_SMTP_ENCRYPTION="tls"
export BPCAB_SMTP_USERNAME="votre-identifiant"
export BPCAB_SMTP_PASSWORD="votre-secret"
export BPCAB_SMTP_FROM_EMAIL="[email protected]"
export BPCAB_SMTP_FROM_NAME="Votre Site"
export BPCAB_SMTP_TIMEOUT="10"
export BPCAB_SMTP_DEBUG="0"

Résultat attendu : vous avez désormais des valeurs de config disponibles, mais SMTP n’est pas encore branché à PHPMailer.


Étape 4 : Verrouiller From/Reply-To et éviter les réécritures

Avant même de configurer SMTP, je force l’identité d’envoi. Sinon, vous allez dépanner un “SMTP marche, mais l’expéditeur change” causé par :

  • un plugin de formulaire qui impose son From,
  • un builder qui injecte un Reply-To étrange,
  • un thème qui filtre wp_mail_from.

Ajoutez à la fin de votre fichier bpcab-smtp.php :

/**
 * Force l'email "From" pour éviter les réécritures incohérentes.
 * Attention : certains SMTP refusent un From hors domaine autorisé.
 */
add_filter('wp_mail_from', function ($from_email) {
	$configured = bpcab_smtp_get_config('from_email', '');
	if (!empty($configured) && is_string($configured)) {
		return $configured;
	}
	return $from_email;
}, 9999);

/**
 * Force le nom "From".
 */
add_filter('wp_mail_from_name', function ($from_name) {
	$configured = bpcab_smtp_get_config('from_name', '');
	if (!empty($configured) && is_string($configured)) {
		return $configured;
	}
	return $from_name;
}, 9999);

Pourquoi la priorité 9999 ? Parce que beaucoup de plugins se branchent plus tôt. Ici, je préfère “gagner” à la fin. Si vous avez un besoin spécifique (ex : WooCommerce doit mettre un From différent), vous ajusterez ensuite en ciblant uniquement certains emails.

Résultat attendu : les emails envoyés via wp_mail() auront un From stable (même avant SMTP).


Étape 5 : Ajouter des logs exploitables (sans fuiter de secrets)

Quand SMTP échoue, l’erreur utile est rarement visible dans l’admin. Elle est dans le retour de PHPMailer. Je loggue deux choses :

  • les erreurs (avec message),
  • le contexte minimal (host/port/encryption), sans username/password.

Ajoutez ce code :

/**
 * Petit logger : écrit dans error_log.
 * Si WP_DEBUG_LOG est activé, ça ira dans wp-content/debug.log.
 */
function bpcab_smtp_log(string $message, array $context = []): void {
	$prefix = '[BPCAB SMTP] ';
	$line = $prefix . $message;

	if (!empty($context)) {
		// On évite d'exposer des secrets : pas de password, pas de body complet.
		unset($context['password'], $context['pass'], $context['smtp_password']);
		$line .= ' ' . wp_json_encode($context, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
	}

	error_log($line);
}

/**
 * Loggue les échecs de wp_mail.
 * Doc : wp_mail_failed reçoit un WP_Error.
 */
add_action('wp_mail_failed', function ($wp_error) {
	if (!($wp_error instanceof WP_Error)) {
		return;
	}

	bpcab_smtp_log('wp_mail_failed', [
		'error_code' => $wp_error->get_error_code(),
		'error_message' => $wp_error->get_error_message(),
		'error_data' => $wp_error->get_error_data(),
	]);
});

Résultat attendu : si un envoi échoue, vous verrez une entrée dans vos logs PHP (ou wp-content/debug.log si activé).


Étape 6 : Ajouter une page d’admin “Test SMTP” (avec nonce) pour valider

Je préfère un test “dans WordPress” plutôt qu’un test externe, parce que ça valide le chemin réel : wp_mail() → PHPMailer → SMTP. Et ça évite l’erreur fréquente : “SMTP marche en CLI, mais WordPress est derrière un cache/une config différente”.

Ajoutez une page dans Outils → Test SMTP

Collez à la fin du MU-plugin :

/**
 * Ajoute une page Outils > Test SMTP.
 */
add_action('admin_menu', function () {
	add_management_page(
		'Test SMTP',
		'Test SMTP',
		'manage_options',
		'bpcab-smtp-test',
		'bpcab_smtp_render_test_page'
	);
});

/**
 * Affiche la page de test.
 */
function bpcab_smtp_render_test_page(): void {
	if (!current_user_can('manage_options')) {
		wp_die('Accès refusé.');
	}

	$enabled = bpcab_smtp_is_enabled();

	// Traitement du formulaire.
	$result_html = '';
	if (isset($_POST['bpcab_smtp_action']) && $_POST['bpcab_smtp_action'] === 'send_test') {
		check_admin_referer('bpcab_smtp_send_test', 'bpcab_smtp_nonce');

		$to = isset($_POST['bpcab_smtp_to']) ? sanitize_email(wp_unslash($_POST['bpcab_smtp_to'])) : '';
		if (empty($to) || !is_email($to)) {
			$result_html = '<div class="notice notice-error"><p>Adresse email de test invalide.</p></div>';
		} else {
			$subject = sprintf('[%s] Test SMTP', wp_specialchars_decode(get_bloginfo('name'), ENT_QUOTES));
			$body = "Email de test envoyé par WordPress.nnDate: " . gmdate('c') . "nSite: " . home_url();

			$sent = wp_mail($to, $subject, $body);

			if ($sent) {
				$result_html = '<div class="notice notice-success"><p>Email envoyé. Vérifiez la boîte de réception (et les spams).</p></div>';
			} else {
				$result_html = '<div class="notice notice-error"><p>Échec d’envoi. Vérifiez vos logs (debug.log / logs PHP).</p></div>';
			}
		}
	}

	$host = (string) bpcab_smtp_get_config('host', '');
	$port = (string) bpcab_smtp_get_config('port', '');
	$enc  = (string) bpcab_smtp_get_config('encryption', '');

	echo '<div class="wrap">';
	echo '<h1>Test SMTP</h1>';

	echo $enabled
		? '<p><strong>SMTP activé</strong>.</p>'
		: '<p><strong>SMTP désactivé</strong> (BPCAB_SMTP_ENABLED).</p>';

	echo '<p>Configuration détectée :<br>';
	echo '<code>' . esc_html($host) . ':' . esc_html($port) . ' (' . esc_html($enc) . ')</code></p>';

	echo $result_html;

	echo '<form method="post">';
	wp_nonce_field('bpcab_smtp_send_test', 'bpcab_smtp_nonce');
	echo '<input type="hidden" name="bpcab_smtp_action" value="send_test">';

	echo '<table class="form-table" role="presentation"><tbody>';
	echo '<tr><th scope="row"><label for="bpcab_smtp_to">Envoyer à</label></th>';
	echo '<td><input name="bpcab_smtp_to" id="bpcab_smtp_to" type="email" class="regular-text" required placeholder="[email protected]"></td></tr>';
	echo '</tbody></table>';

	submit_button('Envoyer un email de test');
	echo '</form>';

	echo '</div>';
}

Résultat attendu : dans l’admin, vous voyez Outils → Test SMTP. Vous pouvez envoyer un email de test et obtenir un message succès/échec.


Le résultat complet

Il manque encore la pièce centrale : brancher PHPMailer en SMTP. Voici le MU-plugin complet, prêt à copier/coller, compatible WordPress 6.9.4+ et PHP 8.1+.

Créez/écrasez wp-content/mu-plugins/bpcab-smtp.php avec ceci :

<?php
/**
 * Plugin Name: BPCAB SMTP (MU)
 * Description: Configuration SMTP sans plugin via PHPMailer pour WordPress 6.9.4+.
 * Author: Votre Nom
 * Version: 1.0.0
 *
 * Installation :
 * - Placez ce fichier dans wp-content/mu-plugins/bpcab-smtp.php
 * - Ajoutez les constantes dans wp-config.php (ou variables d'environnement)
 */

defined('ABSPATH') || exit;

/**
 * Récupère une valeur de configuration SMTP depuis :
 * 1) une constante (wp-config.php)
 * 2) une variable d'environnement
 */
function bpcab_smtp_get_config(string $key, $default = null) {
	$const = 'BPCAB_SMTP_' . strtoupper($key);

	if (defined($const)) {
		return constant($const);
	}

	$env = getenv($const);
	if ($env !== false && $env !== '') {
		return $env;
	}

	return $default;
}

/**
 * Active/désactive SMTP.
 */
function bpcab_smtp_is_enabled(): bool {
	return (bool) bpcab_smtp_get_config('enabled', false);
}

/**
 * Logger minimal.
 */
function bpcab_smtp_log(string $message, array $context = []): void {
	$prefix = '[BPCAB SMTP] ';
	$line = $prefix . $message;

	if (!empty($context)) {
		unset($context['password'], $context['pass'], $context['smtp_password']);
		$line .= ' ' . wp_json_encode($context, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
	}

	error_log($line);
}

/**
 * Force l'email From.
 */
add_filter('wp_mail_from', function ($from_email) {
	$configured = bpcab_smtp_get_config('from_email', '');
	if (!empty($configured) && is_string($configured)) {
		return $configured;
	}
	return $from_email;
}, 9999);

/**
 * Force le nom From.
 */
add_filter('wp_mail_from_name', function ($from_name) {
	$configured = bpcab_smtp_get_config('from_name', '');
	if (!empty($configured) && is_string($configured)) {
		return $configured;
	}
	return $from_name;
}, 9999);

/**
 * Configure PHPMailer pour utiliser SMTP.
 * Hook officiel : phpmailer_init.
 */
add_action('phpmailer_init', function ($phpmailer) {
	if (!bpcab_smtp_is_enabled()) {
		return;
	}

	// Sécurité : on vérifie qu'on a bien un objet PHPMailer.
	if (!is_object($phpmailer) || !method_exists($phpmailer, 'isSMTP')) {
		bpcab_smtp_log('PHPMailer non disponible, impossible de configurer SMTP.');
		return;
	}

	$host = (string) bpcab_smtp_get_config('host', '');
	$port = (int) bpcab_smtp_get_config('port', 587);
	$enc  = (string) bpcab_smtp_get_config('encryption', 'tls');
	$user = (string) bpcab_smtp_get_config('username', '');
	$pass = (string) bpcab_smtp_get_config('password', '');
	$timeout = (int) bpcab_smtp_get_config('timeout', 10);
	$debug = (bool) bpcab_smtp_get_config('debug', false);

	if ($host === '') {
		bpcab_smtp_log('SMTP activé mais host vide. Vérifiez BPCAB_SMTP_HOST.');
		return;
	}

	// Bascule en SMTP.
	$phpmailer->isSMTP();
	$phpmailer->Host = $host;
	$phpmailer->Port = $port;

	// Auth si username fourni (certains relais internes n'en ont pas besoin).
	$phpmailer->SMTPAuth = ($user !== '');
	if ($phpmailer->SMTPAuth) {
		$phpmailer->Username = $user;
		$phpmailer->Password = $pass;
	}

	// Encryption : 'tls' (STARTTLS) ou 'ssl' (SMTPS). Vide = pas de chiffrement (déconseillé).
	$enc = strtolower(trim($enc));
	if (in_array($enc, ['tls', 'ssl'], true)) {
		$phpmailer->SMTPSecure = $enc;
	} else {
		$phpmailer->SMTPSecure = '';
	}

	$phpmailer->Timeout = $timeout;

	/**
	 * Debug SMTP :
	 * - À utiliser temporairement.
	 * - On loggue dans error_log, pas à l'écran.
	 */
	if ($debug) {
		$phpmailer->SMTPDebug = 2; // 1 = client, 2 = client+serveur
		$phpmailer->Debugoutput = function ($str, $level) use ($host, $port, $enc) {
			bpcab_smtp_log('SMTP debug', [
				'level' => $level,
				'message' => $str,
				'host' => $host,
				'port' => $port,
				'encryption' => $enc,
			]);
		};
	}

	/**
	 * TLS moderne : options par défaut raisonnables.
	 * Si vous avez des erreurs de certificat, ne "désactivez" pas la vérification en prod.
	 * Corrigez plutôt votre CA bundle / votre fournisseur.
	 */
	$phpmailer->SMTPOptions = [
		'ssl' => [
			'verify_peer' => true,
			'verify_peer_name' => true,
			'allow_self_signed' => false,
		],
	];

	// Log minimal de configuration (sans secrets).
	bpcab_smtp_log('SMTP configuré', [
		'host' => $host,
		'port' => $port,
		'encryption' => $enc,
		'auth' => $phpmailer->SMTPAuth ? 'yes' : 'no',
		'timeout' => $timeout,
	]);
}, 10);

/**
 * Loggue les échecs wp_mail.
 */
add_action('wp_mail_failed', function ($wp_error) {
	if (!($wp_error instanceof WP_Error)) {
		return;
	}

	bpcab_smtp_log('wp_mail_failed', [
		'error_code' => $wp_error->get_error_code(),
		'error_message' => $wp_error->get_error_message(),
		'error_data' => $wp_error->get_error_data(),
	]);
});

/**
 * Page admin : Outils > Test SMTP
 */
add_action('admin_menu', function () {
	add_management_page(
		'Test SMTP',
		'Test SMTP',
		'manage_options',
		'bpcab-smtp-test',
		'bpcab_smtp_render_test_page'
	);
});

function bpcab_smtp_render_test_page(): void {
	if (!current_user_can('manage_options')) {
		wp_die('Accès refusé.');
	}

	$enabled = bpcab_smtp_is_enabled();

	$result_html = '';
	if (isset($_POST['bpcab_smtp_action']) && $_POST['bpcab_smtp_action'] === 'send_test') {
		check_admin_referer('bpcab_smtp_send_test', 'bpcab_smtp_nonce');

		$to = isset($_POST['bpcab_smtp_to']) ? sanitize_email(wp_unslash($_POST['bpcab_smtp_to'])) : '';
		if (empty($to) || !is_email($to)) {
			$result_html = '<div class="notice notice-error"><p>Adresse email de test invalide.</p></div>';
		} else {
			$subject = sprintf('[%s] Test SMTP', wp_specialchars_decode(get_bloginfo('name'), ENT_QUOTES));
			$body = "Email de test envoyé par WordPress.nnDate: " . gmdate('c') . "nSite: " . home_url();

			$sent = wp_mail($to, $subject, $body);

			if ($sent) {
				$result_html = '<div class="notice notice-success"><p>Email envoyé. Vérifiez la boîte de réception (et les spams).</p></div>';
			} else {
				$result_html = '<div class="notice notice-error"><p>Échec d’envoi. Vérifiez vos logs (debug.log / logs PHP).</p></div>';
			}
		}
	}

	$host = (string) bpcab_smtp_get_config('host', '');
	$port = (string) bpcab_smtp_get_config('port', '');
	$enc  = (string) bpcab_smtp_get_config('encryption', '');

	echo '<div class="wrap">';
	echo '<h1>Test SMTP</h1>';

	echo $enabled
		? '<p><strong>SMTP activé</strong>.</p>'
		: '<p><strong>SMTP désactivé</strong> (BPCAB_SMTP_ENABLED).</p>';

	echo '<p>Configuration détectée :<br>';
	echo '<code>' . esc_html($host) . ':' . esc_html($port) . ' (' . esc_html($enc) . ')</code></p>';

	echo $result_html;

	echo '<form method="post">';
	wp_nonce_field('bpcab_smtp_send_test', 'bpcab_smtp_nonce');
	echo '<input type="hidden" name="bpcab_smtp_action" value="send_test">';

	echo '<table class="form-table" role="presentation"><tbody>';
	echo '<tr><th scope="row"><label for="bpcab_smtp_to">Envoyer à</label></th>';
	echo '<td><input name="bpcab_smtp_to" id="bpcab_smtp_to" type="email" class="regular-text" required placeholder="[email protected]"></td></tr>';
	echo '</tbody></table>';

	submit_button('Envoyer un email de test');
	echo '</form>';

	echo '</div>';
}

Personnalisation rapide

  • Timeout : si votre SMTP est lent, montez BPCAB_SMTP_TIMEOUT à 20.
  • Encryption : utilisez tls sur 587 dans 80% des cas. ssl sur 465 si votre fournisseur l’impose.
  • From : évitez gmail.com en From si vous envoyez via un SMTP de domaine. Beaucoup de relais appliquent des politiques DMARC strictes.

Adapter pour Divi 5 / Elementor / Avada

Bonne nouvelle : SMTP agit au niveau wp_mail(), donc il est global et compatible avec Divi 5, Elementor et Avada. Les ajustements concernent surtout l’identité d’envoi, car ces outils (ou leurs modules de formulaire) définissent parfois des entêtes spécifiques.

Divi 5 (module Formulaire de contact)

  • Divi peut définir un Reply-To basé sur l’email du visiteur. Gardez-le : c’est utile.
  • Évitez de mettre l’email du visiteur en From (ça casse SPF/DMARC). Votre filtre wp_mail_from empêche justement ce cas.

Si vous constatez que Divi force encore le From, c’est souvent via un filtre tardif. Dans ce cas, gardez votre priorité 9999 (déjà fait) et vérifiez qu’aucun plugin “snippets” ne réécrit derrière.

Elementor (Form widget / Elementor Pro Forms)

  • Elementor Pro peut envoyer via “PHP Mail” ou “SMTP” selon réglages. Si vous utilisez ce MU-plugin, gardez Elementor en mode “PHP Mail” pour éviter une double config.
  • Conservez Reply-To = email du visiteur, et From = votre domaine.

Avada (Fusion Builder / Avada Forms)

  • Avada a parfois des options d’emailing dans ses panneaux. Désactivez toute option SMTP interne si elle existe, pour éviter deux couches SMTP.
  • Si des emails partent mais tombent en spam, le souci est souvent DNS (SPF/DKIM/DMARC), pas WordPress.

Vérification finale

  1. Activez BPCAB_SMTP_ENABLED à true.
  2. Allez dans Outils → Test SMTP.
  3. Envoyez un email vers une adresse externe (Gmail/Outlook) et une adresse du même domaine.
  4. Vérifiez :
    • Réception en inbox (ou spam).
    • From = celui défini dans wp-config.php.
    • En cas d’échec : consultez wp-content/debug.log (si WP_DEBUG_LOG est activé) ou les logs PHP.

Pour un test plus “réaliste”, déclenchez un email natif :

  • Mot de passe oublié (sur un compte test).
  • WooCommerce : email de commande (en staging).

Si le résultat n’est pas celui attendu

Voici un tableau de diagnostic qui couvre la majorité des cas que je dépanne en production.

Symptôme Cause probable Vérification Solution
Échec immédiat, rien n’arrive Port SMTP bloqué par l’hébergeur nc -vz host 587 échoue Demandez l’ouverture du port sortant, ou utilisez le SMTP de l’hébergeur / un relais sur port autorisé
Erreur “Could not authenticate” Username/Password erronés, ou auth requise Logs wp_mail_failed / debug SMTP Regénérez un mot de passe/clé SMTP, vérifiez le format du login (email complet vs identifiant)
Erreur TLS/certificat CA bundle manquant, interception TLS, vieux serveur Logs + openssl s_client Corrigez la chaîne de certificats côté serveur, mettez à jour PHP/CA, ne désactivez pas verify_peer en prod
Email envoyé mais en spam SPF/DKIM/DMARC absents ou incohérents Analyse des headers reçus Configurez SPF/DKIM/DMARC côté DNS (chez votre fournisseur SMTP)
Tout marche, puis plus rien après un update Mot de passe changé / rotation de secret Historique des changements, logs Mettez une procédure de rotation + test (page Test SMTP)

Checklist de dépannage rapide

  • Vérifiez que le fichier est bien dans wp-content/mu-plugins/ (pas ailleurs).
  • Activez temporairement BPCAB_SMTP_DEBUG à true et relancez un test.
  • Vérifiez la version PHP (8.1+) et l’extension OpenSSL active.
  • Videz les caches si vous utilisez un cache objet persistant ou un plugin de cache (le SMTP lui-même n’est pas “caché”, mais j’ai déjà vu des environnements où une config wp-config.php n’était pas celle attendue sur un nœud).

Pièges et erreurs courantes

Erreur Cause Solution
Copier le code dans functions.php Changement de thème = SMTP perdu Utilisez un MU-plugin (ou un plugin custom)
Écran blanc après collage Erreur de syntaxe (point-virgule/parenthèse), PHP trop vieux Vérifiez les logs PHP, repassez en PHP 8.1+, corrigez la syntaxe
SMTP configuré mais From “bizarre” Un plugin filtre wp_mail_from après vous Gardez la priorité 9999, ou ciblez les emails via filtres spécifiques
Utiliser ssl sur port 587 Confusion SSL implicite vs STARTTLS Port 587 = tls, port 465 = ssl (sauf exception fournisseur)
Activer le debug en prod et l’oublier Logs volumineux, fuite d’infos Debug temporaire, puis BPCAB_SMTP_DEBUG=false
Suivre un vieux tutoriel qui modifie PHPMailer directement Code obsolète, casse aux updates Utilisez phpmailer_init (API stable WordPress)

Variante / alternative

Alternative “sans code” : plugin SMTP

Si vous préférez une UI et des tests intégrés, un plugin SMTP sérieux peut être plus simple à déléguer à un non-dev. Cherchez un plugin maintenu, compatible WordPress 6.9.4, qui :

  • supporte OAuth2 si vous passez par Gmail/Microsoft (évite les mots de passe applicatifs),
  • gère les logs proprement,
  • n’ajoute pas de tracking intrusif.

Je garde malgré tout le MU-plugin pour les sites “pro” : moins de surface, moins d’UI, moins de surprises.

Alternative “plus avancée” : provider API (HTTP) au lieu de SMTP

Pour des volumes importants, l’API HTTP du provider (SendGrid/Mailgun/etc.) est souvent plus robuste que SMTP (retries, statuts, webhooks). Là, vous sortez du cadre “sans plugin” sauf si vous développez un mini-plugin dédié.


Conseils sécurité, performance et maintenance

  • Secrets : si votre wp-config.php est versionné (rare mais ça arrive), n’y mettez pas le password. Utilisez des variables d’environnement.
  • Ne désactivez pas la vérification TLS en production. Si vous êtes tenté de mettre verify_peer=false, vous êtes en train de masquer un vrai problème (CA manquant, MITM, certificat expiré).
  • Observabilité : laissez wp_mail_failed loggué. Ça vous sauvera le jour où un reset password n’arrive plus.
  • Performance : SMTP ajoute une latence réseau. Pour les sites à fort trafic (ex : WooCommerce + gros volumes), externalisez l’envoi (queue) ou passez par API provider.
  • Maintenance : documentez où se trouve le MU-plugin. J’ai déjà repris des sites où personne ne savait qu’un MU-plugin forçait SMTP, et tout le monde accusait “WordPress”.

Pour aller plus loin

  • Ajouter une whitelist d’emails (ex : n’activer SMTP qu’en production, ou uniquement pour certains domaines de destinataires en staging).
  • Ajouter un filtre pour gérer des From différents selon le type d’email (WooCommerce vs formulaire), en inspectant $subject ou en injectant des headers via wp_mail.
  • Écrire les logs dans un fichier dédié (via Monolog) plutôt que error_log, si votre infra le permet.
  • Ajouter une alerte (Slack/email) si wp_mail_failed se produit N fois en 10 minutes.

Ressources


FAQ

Est-ce que cette méthode remplace complètement mail() ?

Oui, tant que vos emails passent par wp_mail(). WordPress utilise PHPMailer et le hook phpmailer_init vous permet de basculer en SMTP avant l’envoi.

Pourquoi un MU-plugin plutôt qu’un plugin classique ?

Parce que c’est une config “infrastructure” : toujours chargée, pas désactivable par erreur, et indépendante du thème. La doc MU-plugins est ici : developer.wordpress.org.

Puis-je utiliser Gmail SMTP ?

Techniquement oui, mais en 2026 c’est souvent pénible sans OAuth2 (mots de passe applicatifs, restrictions). Pour un site pro, un relais SMTP dédié (ou un provider email transactionnel) est plus stable.

Pourquoi forcer le From au lieu de laisser le plugin de formulaire le définir ?

Parce que mettre l’email du visiteur en From casse souvent SPF/DMARC et augmente le spam. Gardez plutôt l’email du visiteur en Reply-To.

Je reçois l’email mais il est en spam : le code est en cause ?

Rarement. Le plus souvent, c’est DNS : SPF/DKIM/DMARC, réputation IP, ou From non aligné avec le domaine. Le code SMTP garantit surtout la délivrabilité “transport”, pas la réputation.

Dois-je activer BPCAB_SMTP_DEBUG en permanence ?

Non. Activez-le uniquement pour diagnostiquer, puis désactivez. Les logs SMTP peuvent devenir volumineux et révéler des détails de votre infra.

Que faire si mon hébergeur bloque le port 587 ?

Utilisez le SMTP fourni par l’hébergeur (souvent autorisé en interne), demandez l’ouverture du port, ou passez par un provider qui supporte un port alternatif autorisé.

Est-ce compatible WooCommerce ?

Oui. WooCommerce envoie via wp_mail() (sauf customisation). Testez un email de commande en staging pour valider.

Est-ce que ça peut casser les emails système (reset password) ?

Oui si les identifiants SMTP sont faux ou si le serveur est indisponible. Gardez la page “Test SMTP” et une procédure de rollback : mettre BPCAB_SMTP_ENABLED à false temporairement.

Pourquoi ne pas désactiver la vérification TLS si j’ai une erreur de certificat ?

Parce que vous ouvrez la porte à une interception. Corrigez plutôt la cause : CA bundle côté serveur, certificat du provider, ou un proxy qui fait du TLS inspection.

Comment savoir si le MU-plugin est bien chargé ?

Dans l’admin, allez dans Extensions : les MU-plugins apparaissent dans un onglet/section dédiée selon l’UI. Sinon, créez volontairement un log bpcab_smtp_log('MU-plugin chargé'); et vérifiez vos logs.