[英]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 版本並將其與本地計算機的版本進行比較。
這是一個與環境相關的問題,因為相同的代碼在不同的機器上表現不同。 沒有全貌,我無法肯定地回答。 但我希望為進一步調查提供一些見解。 我的分析如下:
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 版本所必需的方式。
嘗試將其添加到您的屬性中,它應該可以解決問題。
props.getProperties().put("mail.smtp.ssl.trust", "smtp.office365.com");
問題是防火牆中的一項特殊規則。
刪除防火牆中的規則解決了這個問題。 無需更改特定代碼即可使其工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.