Java邮件发送到Exchange服务器时出现“不支持登录方法”错误

26

我正在尝试实现一个Java Mail servlet,第一步是连接到IMAP服务器。

我能够在默认的IMAP端口143上telnet到服务器,telnet显示:OK The Microsoft Exchange IMAP4 service is ready.

现在我正在尝试使用Java Mail API连接到服务器,如下所示:

Properties props = new Properties();
session = Session.getDefaultInstance(props, null);
store = session.getStore("imap");
store.connect("host","user","password");

我能够使用现有的Outlook Webapp并使用相同的凭据连接到同一台服务器,就像我试图在java中传递的那样。

但是,使用session.setDebug(true)运行此代码会产生以下输出:

DEBUG: setDebug: JavaMail version 1.4.5
DEBUG: getProvider() returning javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Sun Microsystems, Inc]
DEBUG: mail.imap.fetchsize: 16384
DEBUG: mail.imap.statuscachetimeout: 1000
DEBUG: mail.imap.appendbuffersize: -1
DEBUG: mail.imap.minidletime: 10
DEBUG: trying to connect to host "myHost", port 143, isSSL false
* OK The Microsoft Exchange IMAP4 service is ready.
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 LOGINDISABLED STARTTLS UIDPLUS CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG: protocolConnect login, host=myHost, user=myUser, password=<non-null>
javax.mail.MessagingException: No login methods supported!;

编辑:

我按照建议添加了prop.setProperty("mail.imap.starttls.enable", "true")

然而,我开始收到这个调试输出:

DEBUG: setDebug: JavaMail version 1.4.5
DEBUG: getProvider() returning javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Sun Microsystems, Inc]
DEBUG: mail.imap.fetchsize: 16384
DEBUG: mail.imap.statuscachetimeout: 1000
DEBUG: mail.imap.appendbuffersize: -1
DEBUG: mail.imap.minidletime: 10
DEBUG: enable STARTTLS
DEBUG: trying to connect to host "myHost", port 143, isSSL false
* OK The Microsoft Exchange IMAP4 service is ready.
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 LOGINDISABLED STARTTLS UIDPLUS CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG: protocolConnect login, host=myHost, user=myUser, password=<non-null>
A1 STARTTLS
A1 OK Begin TLS negotiation now.
DEBUG IMAP: STARTTLS Exception: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

假设这是一个证书问题,我按照这些说明添加了邮件服务器到我的cacerts文件。其中包含的测试程序完全正常地运行了,我可以使用SSL URL连接,但当运行java邮件类时仍然会得到相同的异常。

我还尝试使用 "imaps" 更改为:session.getStore("imaps") (而不是 "imap"),甚至无法得到“Microsoft Exchange Server 现在已准备就绪”的消息。我认为是因为它在指定 "imaps" 时尝试连接端口993。但使用telnet连接端口993并没有显示与电子邮件服务器的连接。

所以接下来我尝试强制程序在端口143上使用SSL,就像这样:

// Use SSL
prop.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
prop.setProperty("mail.imap.socketFactory.fallback", "false");

// Use port 143
prop.setProperty("mail.imap.port", "143");
prop.setProperty("mail.imap.socketFactory.port", "143");

我只是为了接收这个异常,所以我不认为它想要与SSL有任何关系:

DEBUG: mail.imap.fetchsize: 16384
DEBUG: mail.imap.statuscachetimeout: 1000
DEBUG: mail.imap.appendbuffersize: -1
DEBUG: mail.imap.minidletime: 10
DEBUG: trying to connect to host "myHost", port 143, isSSL false
Not able to process the mail reading.
javax.mail.MessagingException: Unrecognized SSL message, plaintext connection?;

上面的TLS异常(DEBUG IMAP: STARTTLS Exception: javax.net.ssl.SSLHandshakeException:)可能是因为Exchange服务器上未启用TLS引起的吗?

我没有直接访问邮件服务器的权限,但我可能可以让有权限的人帮我查看。

解决方案:

HulkingUnicorn在他的回答下面的评论指出了这个答案,那正是我需要的处理方式。显然,MS Exchange Server存在这个问题。除了将该答案中列出的类添加到我的包中外,我只需按照以下方式实现我的邮件连接即可:

Properties prop = new Properties();
prop.setProperty("mail.imap.starttls.enable", "true");
prop.setProperty("ssl.SocketFactory.provider", "my.package.name.ExchangeSSLSocketFactory");
prop.setProperty("mail.imap.socketFactory.class", "my.package.name.ExchangeSSLSocketFactory");
session = Session.getDefaultInstance(prop, null);
session.setDebug(true);
store = session.getStore("imap");
store.connect("myHost","myUser","myPassword");
2个回答

22

这部分内容:* CAPABILITY IMAP4 IMAP4rev1 LOGINDISABLED 意味着您无法登录,在 此主题 中,原帖作者通过将其 Javamail 更新到 1.4.4 解决了该问题(尽管您的调试输出表明您已经拥有它)。建议尝试使用 1.4.5 版本

实际上,在创建会话之前添加以下行:您的电子邮件服务器支持它,并且默认情况下已禁用:props.put("mail.imap.starttls.enable", "true");

此答案 解决了该问题。


1
如果您使用“imaps”,则必须将所有属性中的“s”添加到其中,例如prop.setProperty(“mail.imaps.port”,“143”);但是似乎不太可能服务器使用该端口号进行imaps。 - HulkingUnicorn
@Geronimo,你试过Javamail 1.4.5吗? - HulkingUnicorn
升级完成了,但还没有运气。我在想我需要使用SSL连接,因为我通常通过https的Outlook Webapp连接到这个服务器来发送电子邮件。但现在我认为Outlook Webapp需要SSL,但是交换服务器本身运行明文。这个推断是否有缺陷?我得出这个想法是因为我可以通过端口143上的telnet连接到交换服务器,但是当我尝试在默认的安全imap端口(993)上进行telnet时,无法连接到交换服务器。此外,根据我上面的编辑,当我尝试在143上强制使用SSL时,它说它是明文。 - egerardus
1
@Geronimo,您与Web应用程序的连接并不一定反映其与电子邮件服务器的连接。 您可以尝试使用mail.imap.auth.<login/plain/ntlm>.disable属性来控制Javamail将尝试使用哪些身份验证方法。 还有这个问题,其中一个评论建议使用DOMAIN\username而不是username@,以及在答案中使用自定义SSLSocketFactory。 - HulkingUnicorn
在这里找到了一个回答(https://community.oracle.com/thread/2292149),它帮助我解决了问题,而不需要使用类:`prop.setProperty("mail.imap.ssl.trust", "*");` - sbiz
显示剩余2条评论

6
您可以使用javamail 1.4.5 API中的com.sun.mail.util.MailSSLSocketFactory
示例:
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
props.put("mail.imap.starttls.enable", "true");
props.put("mail.imap.ssl.socketFactory", sf);

无需使用自定义的SSLSocketFactory。


太棒了!你救了我的一天。 - user5320306
这对我也解决了问题!我正在使用SSL和IMAPS(以及端口993)。如果您这样做,您需要将imap更改为imaps。 - smmelzer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接