Fix Postmark SMTP TLS
Contexte
On n'arrivait pas a se connecter au serveur SMTP de Postmark (smtp.postmarkapp.com:587). L'erreur dans les logs :
2026-02-01T17:26:29+01:00 CRIT (2): Unable to connect via TLS
La connexion TCP passait, mais ca plantait au moment de la negociation TLS (STARTTLS). Je pensais que ca venait d'OpenSSL, mais en fait c'est un bug PHP.
Ce que j'ai trouve
Le probleme vient de library/Zend/Mail/Protocol/Smtp.php ligne 206 :
stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)
Sur notre version de PHP (7.0.33), la constante STREAM_CRYPTO_METHOD_TLS_CLIENT vaut 9, ce qui correspond a TLS 1.0 uniquement. Or Postmark a desactive TLS 1.0 le 1er fevrier 2020 sur ses serveurs SMTP. Seuls TLS 1.1 et TLS 1.2 sont acceptes.
En verifiant les valeurs des constantes sur PHP 7.0.33 (OpenSSL 1.1.0j) :
| Constante | Valeur | Version TLS |
|---|---|---|
STREAM_CRYPTO_METHOD_TLS_CLIENT | 9 | TLS 1.0 uniquement |
STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT | 9 | TLS 1.0 |
STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | 17 | TLS 1.1 |
STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | 33 | TLS 1.2 |
STREAM_CRYPTO_METHOD_TLS_CLIENT et TLSv1_0_CLIENT ont la meme valeur. C'est le coeur du probleme.
Pourquoi la doc PHP est trompeuse
La doc PHP actuelle dit que STREAM_CRYPTO_METHOD_TLS_CLIENT signifie "Any TLS version". C'est vrai, mais seulement a partir de PHP 7.2+ ou la constante vaut 57 (= 9|17|33).
C'est en fait un bug connu, le Bug #73388 : "STREAM_CRYPTO_METHOD_TLS_CLIENT restricted to TLS1.0 only". En PHP 5.6.7, pour des raisons de retro-compatibilite, la constante a ete ramenee a la valeur de TLSv1_0 uniquement. Cette regression est restee en place jusqu'a PHP 7.1.x et a ete corrigee en 7.2 via le RFC improved-tls-constants.
| Versions PHP | Valeur | Signification reelle |
|---|---|---|
| 5.6.0 – 5.6.6 | 57 | TLS 1.0 + 1.1 + 1.2 |
| 5.6.7 – 7.1.x | 9 | TLS 1.0 uniquement (regression) |
| 7.2+ | 57 | TLS 1.0 + 1.1 + 1.2 (corrige) |
Script de test
Un script de test est disponible dans tests/smtp-tls-test.php. Il envoie un email via Zend Framework pour verifier que le correctif fonctionne.
Configuration
Ajouter les identifiants Postmark dans .env :
POSTMARK_SMTP_USERNAME=ton-username
POSTMARK_SMTP_PASSWORD=ton-password
Lancer le test
docker compose up -d php
docker compose exec php php tests/smtp-tls-test.php
Resultat attendu
PHP 7.0.33 / OpenSSL 1.1.0j
Envoi vers martin@file-service.eu via Zend_Mail...
OK - Email envoye
Tests manuels
Tests isoles realises le 4 fevrier 2026 avec l'image Docker php:7.0-cli (PHP 7.0.33, OpenSSL 1.1.0j), connexion directe vers smtp.postmarkapp.com:587.
Avant correctif — TLS 1.0 (echec)
TCP OK
Banner: 220 p-pm-outboundg01c-aws-euwest1c.smtpservice.postmarkapp.com ESMTP
STARTTLS: 220 2.0.0 Ready to start TLS
Crypto method: STREAM_CRYPTO_METHOD_TLS_CLIENT (constante=9)
Resultat: false
Erreur PHP: stream_socket_enable_crypto(): SSL: Connection reset by peer
stream_socket_enable_crypto() retourne false. Postmark coupe la connexion (Connection reset by peer) parce que TLS 1.0 est refuse depuis le 1er fevrier 2020.
Apres correctif — TLS 1.2 (succes)
TCP OK
Banner: 220 p-pm-outboundg01c-aws-euwest1c.smtpservice.postmarkapp.com ESMTP
STARTTLS: 220 2.0.0 Ready to start TLS
Crypto method: STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT (constante=33)
Resultat: true
EHLO post-TLS: OK (session SMTP chiffree active)
AUTH LOGIN: 334 VXNlcm5hbWU6
stream_socket_enable_crypto() retourne true. La session SMTP chiffree fonctionne, le serveur repond 334 (pret pour l'authentification).
Correctif a appliquer
Une seule ligne a changer dans library/Zend/Mail/Protocol/Smtp.php, ligne 206.
Avant :
if (!stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
Apres :
if (!stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT)) {
Notes
STREAM_CRYPTO_METHOD_TLSv1_2_CLIENTexiste depuis PHP 5.6.0, donc pas de souci de compatibilite avec notre PHP 7.0.- Ca n'impacte que les connexions SMTP avec
ssl = "tls"(STARTTLS, port 587). Les connexions sans TLS (MailDev en dev, port 1025) et les connexions SSL implicites (port 465) ne sont pas concernees. - TLS 1.0 et 1.1 sont de toute facon deprecies depuis le RFC 8996 (mars 2021). Tous les fournisseurs SMTP modernes (Postmark, Mailgun, SendGrid, etc.) exigent TLS 1.2 minimum.
- Rien a changer cote conteneur Docker, c'est purement un fix dans le code PHP.
References
- PHP Bug #73388 — STREAM_CRYPTO_METHOD_TLS_CLIENT restricted to TLS1.0 only
- PHP Bug #69195 — STREAM_CRYPTO_METHOD_SSLv23_CLIENT no longer includes TLS
- Gist: Inconsistent stream crypto values across PHP versions (5.6.7 – 7.1.22)
- PHP RFC: improved-tls-defaults
- PHPMailer — TLS 1.2 Compatibility Issue #542
- RFC 8996 — Deprecating TLS 1.0 and TLS 1.1 (mars 2021)
- Postmark — Security upgrades to SMTP sending (1er fevrier 2020)