SMTP отправка почты не работает для office365 - программирование
Подтвердить что ты не робот

SMTP отправка почты не работает для office365

Здесь есть особая проблема. Намерение состоит в том, чтобы отправить почту через SMTP для office365.

Я был в состоянии последовательно отправлять почту с моего локального ноутбука.

Но при развертывании на нашем сервере (за брандмауэром) это не удается. Примечание. Порт 587 для smtp.office365.com доступен и подтвержден на сервере. Вот свойства, с помощью которых он успешно работает с моего локального компьютера.

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);

Но не на сервере. Вот журналы отладки сервера:

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
4b9b3361

Ответ 1

Проверьте, имеет ли сервер тот же набор сертификатов, что и ваш локальный компьютер.

Ответ 220 от сервера не означает, что сеанс TLS уже установлен, это просто означает, что клиент может начать согласовывать его:

После получения ответа 220 на команду STARTTLS клиент ДОЛЖЕН начать согласование TLS, прежде чем давать какие-либо другие команды SMTP. Если после выполнения команды STARTTLS клиент обнаруживает, что какой-то сбой не позволяет ему фактически запустить рукопожатие TLS, то он ДОЛЖЕН прервать соединение. (из RFC 3207)

На данный момент, пропущенный сертификат является наиболее вероятной проблемой.

Ответ 2

Проверьте версию JRE на сервере и сравните ее с версией вашего локального компьютера.

Это проблема, связанная с окружающей средой, поскольку один и тот же код ведет себя по-разному на разных машинах. Без полной картины я не могу ответить с уверенностью. Но я надеюсь дать некоторую информацию для дальнейшего расследования. Мой анализ выглядит следующим образом:

  • Во-первых, я не думаю, что это проблема с сертификатом SSL, ошибка основной причины ясна:
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)
...

это означает, что сокет был установлен, но фаза согласования преобразования сокета в TLS не удалась. Если сертификат недействителен, о нем будет сообщено после рукопожатия, давайте посмотрим на код из класса 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));
        }
    }
    }

сокет обнаружил таймаут в этой строке: sslsocket.startHandshake(), который находится перед проверкой сертификата.

  • Во-вторых, вы уже упоминали, что брандмауэры отключены, и мы видим, что предыдущий сокет правильно установлен, так же как и команда telnet, поэтому я не думаю, что это проблема брандмауэра.

  • Это похоже на проблему протокола, главным образом потому, что это произошло на этапе установления связи, в противном случае мы должны увидеть другую и более явную ошибку, такую как ошибка сертификата, тайм-аут соединения и т.д. Это тайм-аут SocketRead, который указывает клиент (ваш сервер) ожидает некоторую информацию от сервера (office365), но сервер не отвечает, как будто они не разговаривают друг с другом.

  • Скомпилированный код здесь не является проблемой, но некоторая часть этого процесса связана со средой: класс SSLSocketImpl.class из JRE, а не из компиляции. И это точный код (декомпилированный), где реализован протокол:

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;
            }

        }
    }

Приведенный выше код взят из JRE_1.8.0_181, ваш код или код с вашего сервера могут отличаться. Таким образом, необходимо проверить версию JRE вашего сервера.

  • Используя тот же код, который вы указали в начале, я мог правильно подключиться к office365

Ответ 3

Попробуйте добавить это к своим свойствам, и это должно сработать.

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