SMTP发送邮件不适用于office365

时间:2019-06-28 06:50:19

标签: java office365 javamail

这是一个特殊的问题。目的是通过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

4 个答案:

答案 0 :(得分:2)

检查服务器是否具有与本地计算机相同的证书集。

来自服务器的220响应并不意味着TLS会话已经建立,仅意味着客户端可以开始协商它:

  

在收到对STARTTLS命令的220响应之后,客户端必须在提供任何其他SMTP命令之前开始TLS协商。如果在发出STARTTLS命令后,客户端发现某个故障阻止了它实际启动TLS握手,则它应该中止连接。   (来自RFC 3207)

这时,最可能的问题是缺少证书。

答案 1 :(得分:1)

在服务器上检查您的 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 < / strong>超时,表示客户端(您的服务器)期望服务器(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

答案 2 :(得分:0)

尝试将其添加到属性中,它应该可以解决问题。

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

答案 3 :(得分:0)

问题是防火墙中的一条特殊规则。

删除防火墙中的规则可解决此问题。无需进行特定的代码更改即可使其工作。