簡體   English   中英

SMTP 發送郵件不適用於 office365

[英]SMTP send mail is not working for office365

這里有一個特殊的問題。 目的是通過 SMTP 為 office365 發送郵件。

我一直能夠從我的本地筆記本電腦發送郵件。

但是當部署在我們的服務器上(在防火牆后面)時,它並沒有成功。 注意: smtp.office365.com 587 端口可在服務器上訪問並確認。 以下是它在我的本地計算機上成功運行的屬性。

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

檢查服務器是否與您的本地計算機具有相同的證書集。

來自服務器的 220 響應並不意味着 TLS 會話已經建立,它只是意味着客戶端可以開始協商它:

在收到對 STARTTLS 命令的 220 響應后,客戶端必須在給出任何其他 SMTP 命令之前開始 TLS 協商。 如果在發出 STARTTLS 命令后,客戶端發現某些故障阻止它實際啟動 TLS 握手,那么它應該中止連接。 (來自 RFC 3207)

此時,缺少證書是最有可能的問題。

檢查服務器上的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

嘗試將其添加到您的屬性中,它應該可以解決問題。

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

問題是防火牆中的一項特殊規則。

刪除防火牆中的規則解決了這個問題。 無需更改特定代碼即可使其工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM