Pour les développeurs · v2.7 · GPLv2

Deux filtres, une ligne par email, aucun tiers.

Tout ce qui suit est vérifiable dans le code source. Cette page existe pour que le détail technique n’ait pas à se déduire d’une liste de fonctionnalités, et pour que vous puissiez décider en cinq minutes si tout cela a sa place dans votre stack.

WordPress 6.0 à 7.0PHP 7.4+PHPMailer 7.0.2MultisiteFichiers en lecture seule

Surface d’intégration

Où il s’accroche
à WordPress.

Le chemin d’envoi et le chemin de journalisation sont séparés. La journalisation est un observateur passif de wp_mail(), elle continue donc de fonctionner quel que soit le transport que vous finissez par utiliser, y compris aucun des nôtres.

HookPrioritéCe qui s’y passe
wp_mail_from
wp_mail_from_name
PHP_INT_MAXIdentité de l’expéditeur, appliquée en dernier pour qu’un thème ou une autre extension ne puisse pas gagner l’arbitrage en silence.
phpmailer_initPHP_INT_MAXConfiguration du transport : hôte, port, chiffrement, authentification, Return-Path.
pre_wp_mail10Court-circuite tout le chemin PHPMailer quand le mailer API SES est sélectionné, et construit le MIME brut à la place.
wp_mailPHP_INT_MAXCapture le destinataire, l’objet, les en-têtes et le nombre de pièces jointes en mémoire. Rien n’est encore écrit.
wp_mail_succeeded
wp_mail_failed
défaut, puis 20Le logger écrit la ligne, puis le moniteur met ses compteurs à jour. Une seule écriture, une fois le résultat connu.
custom_smtp_purge_logscron quotidienUn unique DELETE préparé pour tout ce qui dépasse votre fenêtre de rétention.
custom_smtp_alert_checkcron 15 minSeuils de volume uniquement, et seulement quand les alertes sont actives. Les séries d’échecs, elles, sont comptées en ligne.
after_password_reset
filtres de notification
plugins_loadedInterrupteurs facultatifs pour les emails de notification que WordPress envoie à l’administrateur : mot de passe changé, nouveau compte, résultat des mises à jour automatiques, commentaires. Rien n’est coupé par défaut.
custom_smtp_skip_logfiltreÀ vous. Renvoyez true pour exclure l’envoi courant du journal et des compteurs d’alerte.

Ce que ça coûte

Un INSERT.
Voilà l’empreinte.

Autant l’énoncer précisément, parce que la « journalisation des emails » est le genre de fonctionnalité qui se transforme discrètement en incident de performance deux ans plus tard.

  • Une ligne écrite par email, sur le hook de succès ou d’échec. L’étape de capture garde les données en mémoire, il n’y a donc ni valse insert-puis-update, ni ligne orpheline quand un envoi meurt à mi-chemin.
  • Aucune requête sur une page qui n’envoie rien, c’est-à-dire presque toutes. Le plugin déclare ses filtres puis s’efface.
  • Une table, trois index : date_sent, status, et un index de préfixe sur 100 caractères pour recipient. Ce sont les trois colonnes sur lesquelles l’écran de journal filtre réellement.
  • Le corps des messages n’est pas stocké par défaut. Quand vous activez la journalisation du contenu, chaque corps est plafonné à 500 Ko, pour qu’une newsletter emballée ne fasse pas gonfler la table.
  • La purge est un DELETE par jour, sur un hook WP-Cron, selon la rétention que vous fixez. Mettez-la à 7 sur une boutique chargée et la table reste petite en permanence.
  • Aucune requête HTTP sortante en dehors de votre fournisseur de messagerie, et de votre propre webhook si vous en avez configuré un. Pas de vérification de licence, pas de télémétrie, pas de ping de mise à jour en dehors du mécanisme WordPress.org que toutes les extensions utilisent.

Où vit l’état

Les réglages dans wp_options sous forme d’un tableau unique, les journaux dans une table dédiée, les compteurs d’alerte dans les options, les exports CSV diffusés vers le navigateur plutôt qu’écrits sur le disque. Rien n’est écrit dans le répertoire du plugin à l’exécution, un système de fichiers en lecture seule et DISALLOW_FILE_MODS passent donc tous les deux sans histoire.

Amazon SES · API · rôle IAM

Envoyer depuis AWS sans le moindre identifiant.

Sur ECS Fargate, EC2 ou App Runner, Custom SMTP envoie par l’API SESv2 en utilisant le rôle de la tâche ou de l’instance. Rien n’est collé dans wp-admin, rien n’est écrit en base, rien à faire tourner.

  • Zéro secret stocké. L’authentification vient de la chaîne de credentials par défaut d’AWS, le conteneur tient donc ses permissions de son rôle.
  • PHPMailer est entièrement contourné. Le mailer court-circuite pre_wp_mail et soumet du MIME brut, donc le HTML, les pièces jointes, les CC, les CCI, le Reply-To et les en-têtes personnalisés survivent tous. Les CCI restent cachés.
  • Les Configuration Sets sont pris en charge, pour le suivi des rebonds et des plaintes dans CloudWatch.
  • Aucune dépendance dure. Il utilise le SDK AWS quand l’image en embarque déjà un, et retombe sur un petit client signé intégré quand ce n’est pas le cas.

Environnement du conteneur

# mailer choisi pour tout le réseau, aucun réglage par site
CUSTOM_SMTP_MAILER_TYPE=ses_api
SES_REGION=eu-west-3
SES_FROM_EMAIL=no-reply@example.com
SES_CONFIG_SET=transactional

# n'importe quel réglage se force de la même façon
CUSTOM_SMTP_LOG_RETENTION=90
CUSTOM_SMTP_STORE_CONTENT=0

Tout ce qui vient de l’environnement apparaît en lecture seule dans wp-admin, avec un badge nommant la variable dont il provient. Un administrateur voit ainsi ce que la plateforme contrôle et cesse d’ouvrir des tickets sur des champs qui refusent de s’enregistrer. Les mêmes valeurs peuvent être définies en constantes PHP danswp-config.phpsi vous préférez garder la configuration dans le code plutôt que dans l’environnement.

Multisite

Réglages réseau,
surcharges par site.

Configurez le réseau une fois et chaque site en hérite. Un site peut surcharger ce que vous l’autorisez à surcharger, et ne peut pas toucher à ce que l’environnement a déjà figé.

La précédence va dans un sens, et un seul : les variables d’environnement et les constantes PHP l’emportent, puis viennent les réglages du réseau, puis les options propres à chaque site. C’est cet ordre qui rend un parc prévisible, parce qu’un administrateur client qui explore son tableau de bord ne peut pas défaire une décision de plateforme.

Le journal, lui, reste par site, ce qui est presque toujours ce que l’on veut : la personne qui le consulte cherche un message, sur un site, envoyé à une personne.

Posture de sécurité

Énoncée, pas sous-entendue.

Une extension qui détient des identifiants SMTP et une copie de votre courrier sortant se doit d’être explicite sur la façon dont elle traite les deux.

  • Les mots de passe sont chiffrés en AES-256-CBC, avec une clé tirée de vos salts WordPress. Aucune clé n’est livrée dans le plugin, ce qui veut dire aussi que les identifiants ne survivent pas à une restauration dans un site aux salts différents, et c’est voulu.
  • Chaque point d’entrée AJAX vérifie un nonce et une capacité avant de faire quoi que ce soit. Test de connexion, email de test, export, suppression, aperçu et renvoi sont tous protégés.
  • Chaque requête est préparée. Les saisies qui atteignent la recherche du journal passent par esc_like() et sont liées, jamais concaténées.
  • Les exports sont diffusés en flux, donc rien n’atterrit sur le système de fichiers et rien ne traîne dans un répertoire d’uploads pour être trouvé plus tard.
  • Le courrier d’alerte ne peut pas boucler. Le notificateur marque ses propres messages, qui ne sont donc ni journalisés ni comptés dans les seuils qui les ont déclenchés.
  • Le plugin n’évalue aucun code distant, ne charge aucune ressource distante, et ne va rien chercher chez un éditeur à l’exécution.

Signaler quelque chose

Les signalements de sécurité passent par la page du plugin sur WordPress.org plutôt que par un fil de forum public. La fiche du dépôt porte le contact à jour et le journal des versions complet, version par version.

L’étendre

Un filtre que vous
utiliserez vraiment.

Du trafic transactionnel à haut volume dont vous ne voulez pas dans le journal, ou une classe de messages que vous n’avez pas le droit de conserver, se ramènent au même hook.

Exclure un envoi du journal et des compteurs

// Garder le trafic de la file d'attente hors du journal.
add_filter( 'custom_smtp_skip_log', function ( $skip ) {
    if ( wp_doing_cron() && defined( 'MY_BULK_RUN' ) ) {
        return true;
    }
    return $skip;
} );

Abilities API

Le plugin déclare deux abilities pour l’Abilities API de WordPress, pour qu’un agent ou un outil d’orchestration puisse vérifier le chemin du courrier sans scraper wp-admin : custom-smtp/connection-health etcustom-smtp/send-test-email. Les deux respectent les mêmes contrôles de capacité que les écrans d’administration.

Tout est traduit

Domaine de texte custom-smtp, français et anglais livrés intégralement, y compris les messages d’erreur SMTP traduits, c’est-à-dire justement la partie qui reste d’habitude en anglais et qui compte le plus pour la personne qui la lit.

Compatibilité

Ce sur quoi il tourne.

Testé contre le WordPress courant, et écrit pour la version de PHP sur laquelle votre plus vieux client est encore.

PrérequisPris en chargeNotes
WordPress6.0 à 7.0Utilise la gestion Envelope-From et Return-Path de WP 6.9 quand elle est disponible.
PHP7.4 et plusPropriétés et types de retour typés, aucune syntaxe réservée à PHP 8.
PHPMailer7.0.2Configuré sur phpmailer_init, jamais remplacé ni embarqué.
MultisiteouiRéglages réseau avec surcharges par site.
Fichiers en lecture seuleouiRien n’est écrit en dehors de la base. Exports en flux.
Cache objetouiLes réglages sont lus une fois par requête et gardés en mémoire.
OpenSSLrequisUniquement pour chiffrer les mots de passe stockés au repos.

Lisez le code,
puis décidez.

C’est du GPLv2 sur le dépôt WordPress.org : le code est à un téléchargement d’ici, et il n’y a aucun compte entre vous et lui.

v2.7GPLv2Aucune dépendanceAucune télémétrie