Un « TLS error on port 465 » survient quand le client SMTP et le server ne négocient pas le chiffrement au même moment : le port 465 fonctionne « with implicit TLS », dès le premier octet, alors que beaucoup de logiciels attendent la bannière en clair puis STARTTLS. Thunderbird l'affiche en « Sending of the message failed », PHPMailer en « Could not connect to SMTP host ».
- Port 465
- TLS implicite : la négociation TLS précède tout échange SMTP (option « Use SSL/TLS » du client,
secure: true,SMTP_SSL). - Port 587
- connexion en clair, puis commande STARTTLS (option « Start TLS »,
secure: false) : un server qui ne la propose pas, ou un client qui ne la demande pas, fait échouer l'envoi. - Premier test
openssl s_clientsur le port 465 : une ligne 220 du serveur prouve que le chiffrement passe.
Que signifie « TLS error on port 465 » ?
Le message « TLS error on port 465 » indique que la poignée de main TLS (le TLS handshake) a échoué entre le logiciel d'envoi et le serveur de messagerie, avant même que la première commande SMTP soit lue. Sur ce port, le serveur n'envoie rien tant que le client n'a pas ouvert une session chiffrée : c'est le TLS implicite, « encrypted from the first byte » selon la formule des documentations anglophones.
La RFC 8314 de l'IETF, publiée en janvier 2018, recommande ce mode pour la soumission du courrier par les clients et rattache le port 465 à ce service, nommé submissions. Le port avait auparavant servi à SMTPS, puis l'IANA l'avait attribué à un autre usage : cette histoire explique pourquoi de vieux tutoriels le disent obsolète et conseillent uniquement le 587.
TLS signifie Transport Layer Security. La RFC 2246, qui l'a défini en 1999, lui fixe pour but premier « privacy and data integrity » entre deux applications. Quand la négociation échoue, aucune donnée ne transite : le client affiche une erreur de connexion, une erreur de protocole ou une erreur de certificat, selon l'étape où la négociation s'est arrêtée. Lire cette étape suffit presque toujours à trouver le correctif.
Ports 465, 587 et 25 : lequel choisir pour envoyer ?
Le choix du port SMTP dépend de l'usage : un logiciel ou un script qui envoie au nom d'un compte utilise la soumission (465 ou 587), tandis que le port 25 relie les serveurs de messagerie entre eux. Confondre les deux familles produit des erreurs qui ressemblent à un problème de TLS alors que le port est simplement fermé.
| Port | Mode de chiffrement | Usage | Réglage du client |
|---|---|---|---|
| 465 | TLS implicite, dès la connexion | soumission authentifiée (RFC 8314) | SSL/TLS, secure: true, SMTP_SSL |
| 587 | clair, puis STARTTLS | soumission authentifiée (submission port) | STARTTLS, secure: false, starttls() |
| 25 | STARTTLS opportuniste | échanges entre serveurs | à éviter pour un client, souvent bloqué en sortie |
Les deux ports de soumission sont sûrs quand le chiffrement est obligatoire. Le 465 supprime toute ambiguïté, puisqu'aucun octet ne circule en clair ; le 587 reste le plus documenté chez les fournisseurs. Microsoft 365 documente ainsi smtp.office365.com sur le port 587 (ou 25), pas sur le 465 : un client réglé en SSL/TLS sur 465 échoue alors sans que le réglage soit faux en soi. Gmail accepte les deux, smtp.gmail.com en SSL sur 465 ou en STARTTLS sur 587.
Reconnaître la cause au message affiché
Le message d'erreur SMTP renvoyé par la bibliothèque désigne l'étape qui a échoué, et chaque étape a sa cause. Voici les formes les plus courantes, en anglais tel que les logiciels les affichent, avec ce qu'elles révèlent :
| Message affiché | Logiciel | Cause probable |
|---|---|---|
SMTP Error: Could not connect to SMTP host. | PHPMailer | port filtré, mauvais hôte ou mode de chiffrement inversé ; le mode débogage dit lequel |
Greeting never received | Nodemailer | secure: false sur le port 465 : la bannière 220 n'arrive qu'après la négociation TLS |
wrong version number | OpenSSL (PHP, Node.js, Python) | l'inverse : TLS envoyé à un port qui répond en clair, typiquement secure: true ou SMTP_SSL sur 587 |
Connection unexpectedly closed | Python smtplib | smtplib.SMTP() ouvert sur 465 sans TLS ; le serveur coupe après le délai |
STARTTLS extension not supported by server | Python smtplib | starttls() appelé sur un port qui ne propose pas STARTTLS, souvent le 465 |
Unable to establish a secure link with the SMTP server using STARTTLS since it doesn't advertise that feature | Thunderbird | sécurité réglée sur STARTTLS alors que le port attend SSL/TLS ; le message conseille de contacter le « service provider » |
Your server does not support the connection encryption type you have specified | Outlook | type de connexion chiffrée inadapté au port choisi ; la suite du message renvoie vers « your mail server administrator or Internet service provider (ISP) » |
SMTP ERROR: Failed to connect to server: Connection timed out (110) | PHPMailer | aucune réponse : port bloqué par le firewall du réseau ou de l'hébergeur |
stream_socket_client(): SSL operation failed with code 1, Failed to enable crypto | PHP | négociation refusée : certificat invalide ou OpenSSL trop ancien pour la version TLS du serveur |
certificate verify failed, self signed certificate | tous | la session chiffrée s'établit, mais le certificat ne correspond pas au nom appelé ou n'est pas signé par une autorité reconnue |
Must issue a STARTTLS command first | serveur, port 587 | authentification tentée avant la demande de chiffrement |
Application-specific password required | Gmail | TLS correct, mais compte à double validation : il faut « sign in with app passwords » |
Un délai dépassé sans aucun message, enfin, oriente vers un pare-feu : ni le client ni le serveur ne parlent, la connexion TCP elle-même n'aboutit pas.
Tester la connexion avec openssl avant de toucher au code
L'outil openssl s_client reproduit la connexion d'un client SMTP sans aucune bibliothèque intermédiaire, ce qui sépare un problème de réseau ou de certificat d'un problème de configuration applicative. Trois commandes couvrent tous les cas, en remplaçant smtp.example.com par le nom réel du serveur :
openssl s_client -connect smtp.example.com:465 -servername smtp.example.com
openssl s_client -connect smtp.example.com:587 -starttls smtp -servername smtp.example.com
nc -vz smtp.example.com 465
Avec openssl, une réponse correcte affiche la chaîne de certificats, la ligne Verify return code: 0 (ok), puis la bannière 220 du serveur. Le nom passé à -servername active le SNI : sans lui, un serveur qui héberge plusieurs domaines peut présenter un certificat qui ne correspond pas. Si nc reste muet jusqu'au délai, le port est bloqué entre la machine et le serveur ; si openssl signale une erreur de protocole, la bibliothèque TLS locale ou le serveur refusent la version proposée ; si la vérification échoue, le certificat est en cause.
Sous Windows, PowerShell offre un équivalent de nc : Test-NetConnection smtp.example.com -Port 465 renvoie TcpTestSucceeded : True quand le port répond ; un résultat négatif désigne le pare-feu local (Windows Defender Firewall), celui de la box ou le filtrage du fournisseur d'accès.
Le test se lance depuis la machine qui envoie réellement, pas depuis un poste de travail : un serveur web mutualisé n'a ni le même réseau ni la même version d'OpenSSL qu'un ordinateur portable.
Les réglages corrects selon la bibliothèque d'envoi
Le réglage SMTP d'une bibliothèque se résume à associer le bon mode de chiffrement au bon port ; la plupart des erreurs viennent d'un libellé trompeur, « SSL » et « TLS » désignant en pratique le moment du chiffrement et non la version du protocole.
PHPMailer
PHPMailer distingue deux constantes : ENCRYPTION_SMTPS (valeur 'ssl') pour le port 465 et ENCRYPTION_STARTTLS (valeur 'tls') pour le 587.
$mail->Host = 'smtp.example.com';
$mail->Port = 465;
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; // implicit TLS
$mail->SMTPAuth = true;
Les extensions d'envoi des CMS proposent la même alternative sous les libellés SSL et TLS, ce qui entretient la confusion : SSL correspond au 465, TLS au 587. Un PHP trop ancien peut aussi échouer quelle que soit l'option ; vérifier d'abord que le site tourne sur une branche de PHP encore maintenue.
Nodemailer
Nodemailer active le TLS implicite par l'option secure, qui selon sa documentation signifie « the connection will use TLS when connecting to server ». La même page précise : « In most cases set this value to true if you are connecting to port 465 ». Concrètement : secure: true pour le port 465, secure: false pour 587 ou 25, le passage au chiffrement se faisant alors par STARTTLS si le serveur le propose.
const transporter = nodemailer.createTransport({
host: "smtp.example.com",
port: 465,
secure: true, // TLS from the first byte
auth: { user: "compte@example.com", pass: process.env.SMTP_PASS }
});
Python et smtplib
Le module smtplib de Python sépare les deux modes en deux classes : SMTP_SSL pour le port 465, SMTP suivi de starttls() pour le 587. La documentation réserve la première aux cas où « SSL is required from the beginning of the connection ».
import smtplib, ssl
ctx = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.example.com", 465, context=ctx) as server:
server.login(user, password)
server.send_message(msg)
Le contexte créé par create_default_context() vérifie le certificat et le nom d'hôte : c'est le comportement à conserver.
Logiciel de messagerie
Dans un client comme Thunderbird ou Outlook, l'option de sécurité de la connexion porte le même choix : « SSL/TLS » pour 465, « STARTTLS » pour 587. Dans Outlook en anglais, le réglage se trouve sous « More Settings », onglet « Advanced », ligne « Use the following type of encrypted connection » ; l'onglet « Outgoing Server » porte la case « My outgoing server (SMTP) requires authentication », à cocher, et « Require logon using Secure Password Authentication », à laisser vide sauf demande du fournisseur. Dans Thunderbird, « Help », puis « About Thunderbird », affiche la version installée : une version ancienne qui ne reçoit plus de mises à jour peut ne pas négocier TLS 1.2. Tant que le réglage reste faux, Thunderbird répète « An error occurred while sending mail » à chaque tentative. Un clic sur « Send/Receive All Folders » relance ensuite l'envoi des messages en attente. Le détail des champs, identifiant et méthode d'authentification compris, figure dans les paramètres SMTP de Thunderbird. Un serveur hMailServer se règle de la même façon côté serveur : chaque port TCP/IP reçoit sa propre sécurité de connexion, SSL/TLS sur 465, avec un certificat déclaré.
Hébergement mutualisé et fournisseur : quand le port est fermé
Un hébergement mutualisé bloque souvent les connexions sortantes vers un serveur SMTP extérieur, ou n'en autorise qu'une partie : le script obtient alors un délai dépassé qui ressemble à une erreur TLS. Le fournisseur d'hébergement propose en général un relais local, joignable sans chiffrement depuis le serveur web ou par un port dédié ; sa documentation ou son support indique lequel utiliser. Demander l'ouverture du port 465 reste l'autre option, quand l'offre le permet.
Sur un hébergement géré par cPanel, la page « Connect Devices » d'un compte de messagerie donne les bons réglages en deux colonnes : « Secure SSL/TLS Settings (Recommended) », avec le serveur sortant et le port 465, et « Non-SSL Settings (NOT Recommended) », à ignorer. La mention « Requires authentication for IMAP, POP3, and SMTP » rappelle que l'identifiant complet du compte est exigé : une erreur d'authentification qui suit une négociation TLS réussie vient alors de lui, pas du port.
Un compte Gmail ou Google Workspace protégé par la validation en deux étapes refuse le mot de passe habituel : il exige un mot de passe d'application (app password), généré dans les réglages de sécurité du compte. L'erreur affichée parle alors d'authentification, pas de TLS, mais elle arrive juste après la négociation et se confond facilement. Un envoi par script vers Gmail pose d'ailleurs d'autres difficultés, détaillées dans la page sur le mail envoyé par un script PHP et bloqué par Gmail.
Certificat, versions TLS et bibliothèques anciennes
Le certificat présenté par le serveur SMTP doit porter le nom exact que le client appelle. Se connecter à mail.mondomaine.fr quand le certificat couvre seulement le nom du serveur mutualisé de l'hébergeur fait échouer la vérification ; la bonne réponse consiste à appeler le nom inscrit dans le certificat, pas à désactiver le contrôle. Les options verify_peer => false en PHP ou rejectUnauthorized: false en Node.js masquent l'erreur et ouvrent la porte à une interception des identifiants.
La version du protocole compte aussi. La RFC 8996, publiée en mars 2021, retire TLS 1.0 et 1.1, et les serveurs actuels les refusent. Un vieux PHP lié à un OpenSSL ancien, une imprimante multifonction ou un appareil qui ne reçoit plus de mises à jour ne savent pas négocier TLS 1.2 ou 1.3 : l'erreur porte alors sur le protocole ou la version. Mettre à jour la bibliothèque règle le problème, par exemple en passant Node.js sur une version LTS (Long Term Support) encore suivie ; pour un appareil figé, un relais interne qui accepte l'appareil et réexpédie le courrier en TLS récent reste la seule voie.
Journaliser la conversation SMTP sans exposer d'identifiants
Le journal de la conversation SMTP montre exactement où la connexion s'arrête, mais il recopie aussi l'authentification encodée en base64, donc lisible par n'importe qui. Dans PHPMailer, SMTPDebug = SMTP::DEBUG_SERVER affiche les échanges ; dans Nodemailer, les options logger: true et debug: true ; en Python, server.set_debuglevel(1).
Trois précautions limitent le risque. Le journal s'écrit dans un fichier hors de la racine web, jamais dans la page affichée au visiteur. Le mode débogage se coupe dès la cause trouvée. Et le mot de passe, s'il est apparu dans un journal partagé ou collé sur un forum, se change. Côté serveur, le log de Postfix (/var/log/mail.log sur Debian) ou celui de hMailServer complète le diagnostic : une ligne comme lost connection after CONNECT confirme qu'un client a ouvert le port sans jamais entamer la négociation TLS, et Exim écrit en clair TLS error on connection from suivi de l'adresse du client.
Un serveur Postfix n'écoute sur le port 465 que si le service submissions est déclaré dans master.cf avec le mode « wrapper » qui active le TLS implicite :
submissions inet n - y - - smtpd
-o syslog_name=postfix/submissions
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
Sans la ligne smtpd_tls_wrappermode=yes, le port 465 répond en clair et tous les clients correctement réglés échouent sur une erreur de version.
Une fois la configuration stable, l'authentification du domaine évite que les messages chiffrés arrivent en indésirables : SPF, puis l'enregistrement DKIM à publier dans les DNS.
Passage au 587, sécurité du 465 et envoi bloqué depuis le serveur
Faut-il passer au port 587 quand le 465 échoue ?
Passer au 587 ne s'impose que si le fournisseur ne propose pas le 465, comme Microsoft 365. Sinon, l'échec sur 465 vient presque toujours d'un mode de chiffrement inversé, d'un port filtré ou d'un certificat mal nommé, et le changement de port ne fait que déplacer le problème.
Le port 465 est-il moins sûr que le 587 ?
Le port 465 n'est pas moins sûr : avec le TLS implicite, aucun octet ne circule en clair, alors que le 587 commence en clair et dépend de la commande STARTTLS. La RFC 8314 recommande d'ailleurs le TLS implicite pour la soumission.
Pourquoi l'envoi marche depuis mon poste mais pas depuis le serveur ?
Le serveur n'a ni le même réseau ni la même bibliothèque TLS que le poste : un hébergeur peut filtrer les ports sortants, et un OpenSSL ancien peut refuser TLS 1.2. Le test openssl lancé depuis le serveur lui-même tranche entre les deux.
Sources : RFC 8314 de l'IETF (janvier 2018), RFC 2246 (janvier 1999), RFC 8996 (mars 2021), documentation d'OpenSSL (s_client), de PHPMailer, de Nodemailer, du module smtplib de Python et de Microsoft 365 (paramètres SMTP).














