JAVAMAIL:AUTH NTLM失败了

我尝试使用microsoft Exchange服务器在本地网络中发送带有java的电子邮件

有我的代码:

import java.io.UnsupportedEncodingException; import java.util.Properties; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; public class Main { public static void main(String[] args) { final String username = "username@MyDomain.com"; final String password = "password"; Properties props = new Properties(); props.put("mail.smtp.auth", "true"); props.put("mail.debug", "true"); props.put("mail.smtp.host", "exchange_host.MyDomain.com"); props.put("mail.smtp.port", "25"); props.put("mail.smtp.auth.mechanisms","NTLM"); props.put("mail.smtp.auth.ntlm.domain","MyDomain"); Session session = Session.getInstance(props,new MyAuthenticator(username,password)); try { Message message = new MimeMessage(session); message.setFrom(new InternetAddress("from_adress@MyDomain.com")); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("recipent_adresse")); message.setSubject("Testing Subject"); message.setText("Dear Mail Crawler," + "\n\n No spam to my email, please!"); Transport.send(message); System.out.println("Done"); } catch (MessagingException e) { throw new RuntimeException(e); } } } 

这是我的authentificator类:

 import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; public class MyAuthenticator extends Authenticator { String user; String pw; public MyAuthenticator (String username, String password) { super(); this.user = username; this.pw = password; } public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(user, pw); } } 

我使用NTLM机制,但我收到此错误:

 DEBUG: JavaMail version 1.4.7 DEBUG: successfully loaded resource: /META-INF/javamail.default.providers DEBUG: Tables of loaded providers DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]} DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]} DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle] DEBUG SMTP: useEhlo true, useAuth true DEBUG SMTP: useEhlo true, useAuth true DEBUG SMTP: trying to connect to host "echange_server.MyDomain.com", port 25, isSSL false 220 echange_server.MyDomain.com Microsoft ESMTP MAIL Service ready at Mon, 30 Sep 2013 09:01:08 +0100 DEBUG SMTP: connected to host "echange_server.MyDomain.com", port: 25 EHLO host.MyDomain.com 250-echange_server.MyDomain.com Hello [xx.xx.xx.xx] 250-SIZE 250-PIPELINING 250-DSN 250-ENHANCEDSTATUSCODES 250-STARTTLS 250-X-ANONYMOUSTLS 250-AUTH NTLM 250-X-EXPS GSSAPI NTLM 250-8BITMIME 250-BINARYMIME 250-CHUNKING 250-XEXCH50 250-XRDST 250 XSHADOW DEBUG SMTP: Found extension "SIZE", arg "" 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 "X-ANONYMOUSTLS", arg "" DEBUG SMTP: Found extension "AUTH", arg "NTLM" DEBUG SMTP: Found extension "X-EXPS", arg "GSSAPI NTLM" DEBUG SMTP: Found extension "8BITMIME", arg "" DEBUG SMTP: Found extension "BINARYMIME", arg "" DEBUG SMTP: Found extension "CHUNKING", arg "" DEBUG SMTP: Found extension "XEXCH50", arg "" DEBUG SMTP: Found extension "XRDST", arg "" DEBUG SMTP: Found extension "XSHADOW", arg "" DEBUG SMTP: Attempt to authenticate using mechanisms: NTLM DEBUG SMTP: AUTH NTLM failed Exception in thread "main" java.lang.RuntimeException: javax.mail.AuthenticationFailedException: 250-exchange_host.MyDomain.com Hello [xx.xx.xx.xx] at testPakcage.Main.main(Main.java:51) Caused by: javax.mail.AuthenticationFailedException: 250-exchange_host.MyDomain.com Hello [xx.xx.xx.xx] 

请帮助我,我过去几天搜索解决方案,但我一无所获

我有这个工作通过NTLM连接到我们的Exchange 2010服务器。

NTLM使用您的Windows登录名和密码进行身份validation,而不是您的电子邮件地址和密码。

我做了以下更改:

1)用户名应该是Windows登录名,而不是电子邮件地址。 NTLM使用您的Windows凭据进行身份validation。

2)mail.smtp.auth.ntlm.domain应该是你的Windows域 – 即斜线前面的部分,如果你通常以“MYDOMAIN \ id12345”作为用户名登录你的Windows机器。

更新的代码如下:

 public class Main { public static void main(String[] args) { // *** CHANGED *** final String username = "id12345"; // ID you log into Windows with final String password = "MyWindowsPassword"; Properties props = new Properties(); props.put("mail.smtp.auth", "true"); props.put("mail.debug", "true"); props.put("mail.smtp.host", "exchangeserver.mydomain.com"); props.put("mail.smtp.port", "25"); props.put("mail.smtp.auth.mechanisms","NTLM"); // *** CHANGED *** props.put("mail.smtp.auth.ntlm.domain","WINDOMAIN"); // Domain you log into Windows with Session session = Session.getInstance(props,new MyAuthenticator(username,password)); try { Message message = new MimeMessage(session); message.setFrom(new InternetAddress("john.smith@mydomain.com")); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("the.recipient@mydomain.com")); message.setSubject("Test email"); message.setText("TEST EMAIL"); Transport.send(message); System.out.println("Done"); } catch (MessagingException e) { e.printStackTrace(); } } public static class MyAuthenticator extends Authenticator { String user; String pw; public MyAuthenticator (String username, String password) { super(); this.user = username; this.pw = password; } public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(user, pw); } } } 

为了它的价值,你的原始post帮助我解决了我连接已经持续了好几天的问题。

最后一点,您可能需要禁用/更改防病毒设置以允许在端口25上进行访问。

我遇到了同样的问题,在发现javamail不支持NTLMv2身份validation后,我找到了一个需要JCIFS库的解决方法。

我下载了javamail api源代码( https://java.net/projects/javamail/pages/Home )并编辑了类com.sun.mail.auth.Ntlm,使用JCIFS库支持添加了对NTLMv2缺少的支持( http://jcifs.samba.org )。

文件Ntlm.java中的第一个修改是在方法init0中,包括添加缺少的标志NTLMSSP_NEGOTIATE_NTLM2

 private void init0() { // ANDREA LUCIANO: // turn on the NTLMv2 negotiation flag in TYPE1 messages: // NTLMSSP_NEGOTIATE_NTLM2 (0x00080000) // See also http://davenport.sourceforge.net/ntlm.html#type1MessageExample type1 = new byte[256]; type3 = new byte[256]; System.arraycopy(new byte[] {'N','T','L','M','S','S','P',0,1}, 0, type1, 0, 9); type1[12] = (byte) 3; type1[13] = (byte) 0xb2; type1[14] = (byte) 0x08; // ANDREA LUCIANO - added 

…}

第二个修改是用这个替换方法generateType3Msg:

 public String generateType3Msg(String challenge) { /* First decode the type2 message */ byte[] type2 = null; try { type2 = BASE64DecoderStream.decode(challenge.getBytes("us-ascii")); logger.fine("type 2 message: " + toHex(type2)); // ANDREA LUCIANO - added } catch (UnsupportedEncodingException ex) { // should never happen assert false; } jcifs.ntlmssp.Type2Message t2m; try { t2m = new jcifs.ntlmssp.Type2Message(type2); } catch (IOException ex) { logger.log(Level.FINE, "Invalid Type 2 message", ex); return ""; // will fail later } final int type2Flags = t2m.getFlags(); final int type3Flags = type2Flags & (0xffffffff ^ (jcifs.ntlmssp.NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | jcifs.ntlmssp.NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER)); jcifs.ntlmssp.Type3Message t3m = new jcifs.ntlmssp.Type3Message(t2m, password, ntdomain, username, hostname, type3Flags); return jcifs.util.Base64.encode(t3m.toByteArray()); } 

我发现修补库的最简单的方法是编译类并更新库jar文件:

 "c:\Program Files\Java\jdk1.5.0_22\bin\javac.exe" -cp jcifs-1.3.17.jar;javax.mail-1.5.2.jar -d . Ntlm.java jar uvf javax.mail-1.5.2.jar com\sun\mail\auth\Ntlm.class 

为了尽可能地启用调试,我在测试类的main方法中使用了以下代码:

  final InputStream inputStream = Main.class.getResourceAsStream("/logging.properties"); LogManager.getLogManager().readConfiguration(inputStream); Properties props = new Properties(); props.put("mail.debug", "true"); props.put("mail.debug.auth", "true"); 

使用此logging.properties:

  # Logging handlers = java.util.logging.ConsoleHandler .level = INFO # Console Logging java.util.logging.ConsoleHandler.level = INFO 

在应用修补程序之前,测试在发送Type 1消息后被卡住,因为我的Exchange服务器需要NTLMv2身份validation。 在补丁之后,成功完成了身份validation。