web-dev-qa-db-fra.com

L'envoi de courrier SMTP ne fonctionne pas pour office365

Voici un problème particulier. L'intention est d'envoyer un courrier via SMTP pour office365.

J'ai pu envoyer régulièrement du courrier à partir de mon ordinateur portable local.

Mais lorsqu'il est déployé sur notre serveur (derrière un pare-feu), il ne réussit pas. Remarque: Le port 587 pour smtp.office365.com est accessible et confirmé sur le serveur. Voici les propriétés via lesquelles il fonctionne avec succès depuis mon ordinateur local.

Properties props = new Properties();
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.connectiontimeout", MAIL_TIMEOUT);
props.put("mail.smtp.timeout", MAIL_TIMEOUT);
props.put("mail.debug", true);
this.session = Session.getInstance(props);
session.setDebug(true);

Transport transport  = session.getTransport();
transport.connect("smtp.office365.com", 587, email, pass);

Mais échoue sur le serveur. Voici les journaux de débogage du serveur:

DEBUG: setDebug: JavaMail version 1.6.2
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.Sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth false
DEBUG SMTP: trying to connect to Host "smtp.office365.com", port 587, isSSL false
220 PN1PR0101CA0017.Outlook.office365.com Microsoft ESMTP MAIL Service ready at Fri, 28 Jun 2019 06:39:41 +0000
DEBUG SMTP: connected to Host "smtp.office365.com", port: 587
EHLO appqa
250-PN1PR0101CA0017.Outlook.office365.com Hello [182.73.191.100]
250-SIZE 157286400
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-STARTTLS
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250 SMTPUTF8
DEBUG SMTP: Found extension "SIZE", arg "157286400"
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "DSN", arg ""
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "BINARYMIME", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Found extension "SMTPUTF8", arg ""
STARTTLS
220 2.0.0 SMTP server ready
Exception in thread "main" javax.mail.MessagingException: Could not convert socket to TLS;
  nested exception is:
Java.net.SocketTimeoutException: Read timed out
at com.Sun.mail.smtp.SMTPTransport.startTLS(SMTPTransport.Java:2155)
at com.Sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.Java:752)
at javax.mail.Service.connect(Service.Java:366)
at com.company.app.MailReader.getTransport(MailReader.Java:269)
at io.vavr.control.Try.of(Try.Java:75)
at com.company.app.MailReader.<init>(MailReader.Java:59)
at com.company.services.MailService.getNewMailReader(MailService.Java:82)
at com.company.services.MailService.start(MailService.Java:46)
at com.company.Main.main(Main.Java:34)
Caused by: Java.net.SocketTimeoutException: Read timed out
at Java.net.SocketInputStream.socketRead0(Native Method)
at Java.net.SocketInputStream.socketRead(SocketInputStream.Java:116)
at Java.net.SocketInputStream.read(SocketInputStream.Java:171)
at Java.net.SocketInputStream.read(SocketInputStream.Java:141)
at Sun.security.ssl.InputRecord.readFully(InputRecord.Java:465)
at Sun.security.ssl.InputRecord.readV3Record(InputRecord.Java:593)
at Sun.security.ssl.InputRecord.read(InputRecord.Java:529)
at Sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.Java:975)
at Sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.Java:1367)
at Sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.Java:1395)
at Sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.Java:1379)
at com.Sun.mail.util.SocketFetcher.configureSSLSocket(SocketFetcher.Java:626)
at com.Sun.mail.util.SocketFetcher.startTLS(SocketFetcher.Java:553)
at com.Sun.mail.smtp.SMTPTransport.startTLS(SMTPTransport.Java:2150)
... 8 more
11
Jatin

Le problème était une règle particulière dans le pare-feu.

La suppression de la règle dans le pare-feu a résolu ce problème. Aucun changement de code spécifique n'était nécessaire pour le faire fonctionner.

0
Jatin

Vérifiez si le serveur possède le même ensemble de certificats que votre ordinateur local.

La réponse 220 du serveur ne signifie pas que la session TLS est déjà établie, cela signifie simplement que le client peut commencer à la négocier:

Après avoir reçu une réponse 220 à une commande STARTTLS, le client DOIT démarrer la négociation TLS avant de donner toute autre commande SMTP. Si, après avoir émis la commande STARTTLS, le client découvre qu'un échec l'empêche de démarrer réellement une négociation TLS, il DEVRAIT abandonner la connexion. (à partir de la RFC 3207)

À ce stade, un certificat manquant est le problème le plus probable.

2
tquadrat

Vérifiez votre version JRE sur le serveur et comparez-le à la version de votre ordinateur local.

Il s'agit d'un problème lié à l'environnement car le même code se comporte différemment sur différentes machines. Sans l'image complète, je ne peux pas répondre avec certitude. Mais j'espère fournir un aperçu pour une enquête plus approfondie. Mon analyse suit:

  • Tout d'abord, je ne pense pas que ce soit un problème de certificat SSL, l'erreur de cause première est claire:
Caused by: Java.net.SocketTimeoutException: Read timed out
at Java.net.SocketInputStream.socketRead0(Native Method)
at Java.net.SocketInputStream.socketRead(SocketInputStream.Java:116)
...
at Sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.Java:1367)
...

cela signifie que le socket a été établi, mais la phase de prise de contact de conversion du socket en TLS a échoué. Si le certificat n'est pas valide, il sera signalé après la prise de contact, regardons le code de la classe SocketFetcher.Java:

    /*
     * Force the handshake to be done now so that we can report any
     * errors (e.g., certificate errors) to the caller of the startTLS
     * method.
     */
    sslsocket.startHandshake();

    /*
     * Check server identity and trust.
     */
    boolean idCheck = PropUtil.getBooleanProperty(props,
                prefix + ".ssl.checkserveridentity", false);
    if (idCheck)
        checkServerIdentity(Host, sslsocket);
    if (sf instanceof MailSSLSocketFactory) {
        MailSSLSocketFactory msf = (MailSSLSocketFactory)sf;
        if (!msf.isServerTrusted(Host, sslsocket)) {
        throw cleanupAndThrow(sslsocket,
            new IOException("Server is not trusted: " + Host));
        }
    }
    }

le socket a rencontré le délai d'expiration sur cette ligne: sslsocket.startHandshake(), qui est avant la validation du certificat.

  • Deuxièmement, vous avez déjà mentionné que les pare-feu sont désactivés, et nous pouvons voir que le socket précédent est correctement établi, tout comme la commande telnet, donc je ne pense pas que ce soit un problème de pare-feu non plus.

  • Cela semble être un problème de protocole, principalement parce que cela s'est produit pendant la phase de prise de contact, sinon nous devrions voir une erreur différente et plus explicite, comme une erreur de certificat, un délai de connexion, etc. Ceci est un délai d'attente socketRead, qui indique que le client (votre serveur) attend des informations du serveur (office365), mais le serveur ne répond pas, c'est comme s'ils ne parlaient pas ensemble.

  • Le code compilé n'est pas le problème ici, mais une partie de ce processus est liée à l'environnement: la classe SSLSocketImpl.class Provient du JRE et non de la compilation. Et c'est le code exact (décompilé) où le protocole est implémenté:

private void performInitialHandshake() throws IOException {
        Object var1 = this.handshakeLock;
        synchronized(this.handshakeLock) {
            if (this.getConnectionState() == 1) {
                this.kickstartHandshake();
                if (this.inrec == null) {
                    this.inrec = new InputRecord();
                    this.inrec.setHandshakeHash(this.input.r.getHandshakeHash());
                    this.inrec.setHelloVersion(this.input.r.getHelloVersion());
                    this.inrec.enableFormatChecks();
                }

                this.readRecord(this.inrec, false);
                this.inrec = null;
            }

        }
    }

Le code ci-dessus provient de JRE_1.8.0_181, votre code ou le code de votre serveur peut être différent. C'est ainsi qu'il est nécessaire de vérifier la version JRE de votre serveur.

  • En utilisant le même code que vous avez fourni au début, j'ai pu me connecter correctement à office365
1
iyunbo

Essayez d'ajouter cela à vos propriétés, et cela devrait faire l'affaire.

props.getProperties().put("mail.smtp.ssl.trust", "smtp.office365.com");
0
Joe