Envoi d’emails en php depuis une boite office365

Bonjour,

Des fois, un problème qui est censé être simple, devient un casse tête chronophage, en plus je DOIS le faire car c’est pour un client, donc pas de remise au lendemain (du moins pas sans se battre jusqu’à épuisement le jour même).

Voici les données de départ :

  • Un nom de domaine relié à un hébergement
  • Une boite e-mail chez office365

Le but est simple : pouvoir envoyer des e-mails depuis php grâce à office365. Et si on a choisi de payer une boite e-mail c’est pour avoir notre nom de domaine dessus.

C’est simple et en théorie facile. Il faut d’abord enregistrer les champs MX auprès de notre registrar pour avoir le nom de domaine qui colle à notre boite mail, c’est facile, ça marche un peu, on règle les DNS et ça roule.

Deuxième étape, on vérifie le smtp et pop/imap. C’est tout aussi facile. On prend icedove (oui, j’ai une Debian, si vous vous souvenez) et on configure les paramètres qu’office365 nous a donné. Après des dizaines d’années de configuration sur outlook express, thunderbird, et autres smartphones du s60 à android, le test se fait en deux coups de cuiller à pot.

Troisième étape, tester manuellement (avec openssl) sur le serveur en ssh. Ca fonctionne bien.

Quatrième étape, on fait un test en php avec la fonction mail(). Bien entendu, il faut une connexion StartTls avec authentification qui n’est pas prise en charge par mail().

Cinquième étape, installer et configurer un MTA qui pourra ne rien demander à mail() et envoyer le courrier quand même. On regarde du côté de sendmail, ç’est très compliqué. Postfix, c’est moins compliqué mais ça reste compliqué quand même. Le problème n’est pas de faire marcher cette solution, c’est de la sécuriser afin de ne pas devenir un zombie pour spammers.

Cinquième étape bis, chercher une alternative à mail(). Une solution vite trouvée : phpmailer. C’est facile et ça marche sur la machine de test (mon ordinateur) et un compte hotmail fait pour l’occasion. J’ajuste les paramètres pour le compte office365 et comme prévu, ça fonctionne toujours sur ma machine.

Sixième étape, on envoie la page de test sur le serveur. Ca ne marche pas ! Le syndrome « Ca marche sur ma machine » a encore été diagnostiqué. Je passe une journée entière à déboguer le code source de phpmailer afin de savoir où se situe le problème. C’est la fonction stream_socket_client qui fait un timeout, il y a donc un firewall qui empêche la connexion. Je règle le timeout de connexion à 10s pour que php donne une erreur de connexion plutôt qu’un timeout de la page (entre 2 timeouts, choisir le moindre). Une nouvelle journée passée à parler anglais (à la louche) pour se faire comprendre du staff de chez Microsoft (très professionnel d’ailleurs). Ils veulent m’aider grâce à un logiciel de partage d’écran, qui est compatible Windows et Mac… J’ai aussi un problème avec l’adsl en ce moment, j’utilise donc la 3G de mon téléphone, et donc pas d’internet quand je parle… Décidément, cette journée n’est pas la plus « jouasse ». Après quelque coups de fil et des mails échangés, on arrive à la conclusion que ç’est pas chez eux que ça coince.

Septième étape, on récapitule parce que ça commence à ressembler à du vaudou cette histoire.

  • Ca marche sur ma machine
  • Le même code ne marche pas sur le serveur
  • Le même code marche sur le serveur quand c’est hotmail qui est configuré
  • Le firewall est désactivé pour pas nous prendre la tête
  • Ca ne bloque pas du côté d’office365
  • Openssl nous permet d’envoyer les mails sur le serveur manuellement
  • Sendmail n’est pas à blamer car phpmailer le court-circuite

Les hypothèses qui restent :

  • phpmailer à une bogue qui fait que hotmail fonctionne et pas office365
  • Le serveur malgré le firewall désactivé fait une distinction entre office365 et hotmail

La deuxième hypothèse me parait plus plausible, je décide de faire un telnet tout bête, et ça ne passe pas, contrairement à openssl qui se connecte.
Un indice qui ne m’as pas échappé est que telnet coince devant une ipv6, je test derechef sur hotmail, ça passe, et bingo, une ipv4.
J’ai donc une piste sérieuse, je désactive l’ipv6 sur le serveur et telnet marche de partout sur toutes les adresses.

Enfin, je lance le script de test php et… Encore un timeout. Je consulte les logs, je constate qu’il y a un fait étrange dans phpmailer : La variable timeout est utilisée dans stream_socket_client(), ce qui est normal, mais aussi dans stream_set_timeout(), ce qui est bizarre pour moi. J’aurais aimé choisir une valeur différente pour chacun.
Et si j’ai remarqué cela c’est que le timeout n’est plus à la connexion mais lors de l’authentification. Le serveur met environ 12 secondes pour confirmer l’existence du compte, oui, j’ai mis 10s et ça me retombre dessus.
Je fais un calcul simple, la page php timeout à 30s, l’authentification met 15s, il reste donc 15s pour la connexion vers la boite mail.
Je met donc 15s pour timeout sans patcher phpmailer (afin de prendre 2 valeurs différentes, si vous suivez toujours).

Je croise les doigts et lance le test et… Ca marche \o/. On fais quelques tests supplémentaires pour voir si c’est tout le temps vrai, et oui.

J’ai quelques questions qui me viennent à l’esprit :

  • Pourquoi le test manuel est très rapide (connexion et authentification en 3s, le reste est quasi instantané) et phpmailer si lent.
  • Pourquoi ipv6 ne marche pas alors que le firewall est désactivé. J’ai une réponse qui vient de google, Digital Ocean, qui est notre hébergeur, désactive ipv6 sur les ports smtp, donc même si le firewall du serveur laisse passer ces ports, celui de l’hébergeur bloque quand même.

Je n’ai plus de temps pour résoudre ces questions. Et je me contente donc de cette petite victoire.