问题
i try to send email with java in local network,using microsoft exchange server
there is my code :
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);
}
}
}
and this is my authentificator class :
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);
}
}
i use the NTLM mechanism but i get this error :
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]
please help me,i past several day to search solution but i found nothing
回答1:
I have this working connecting to our Exchange 2010 server via NTLM.
NTLM uses your Windows login and password for authentication rather than your email address and password.
I made the following changes:
1) Username should be Windows login, NOT email address. NTLM uses your Windows credentials for authentication.
2) mail.smtp.auth.ntlm.domain should be your windows domain - i.e. the part before the slash if you normally log on to your Windows machine with "MYDOMAIN\id12345" as username.
Updated code below:
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);
}
}
}
For what it's worth, your original post helped me solve the problems I have had connecting which have been going on for several days.
One final point, you probably need to disable / change antivirus settings to allow access out on port 25.
回答2:
I had the same problem and after finding out that javamail does not support NTLMv2 authentication, I worked out a workaround that requires JCIFS library though.
I downloded the javamail api source code (https://java.net/projects/javamail/pages/Home) and edited the class com.sun.mail.auth.Ntlm to add the missing support for NTLMv2 using the JCIFS library support (http://jcifs.samba.org).
The first modification in file Ntlm.java was in method init0, and consisted of adding the missing flag 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
... }
The second modification was to replace the method generateType3Msg with this:
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());
}
The simpest way I found to patch the library is to compile the class and update the library jar file:
"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
To enable debug as much as possible, I used the following code in the main method of my test class:
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");
with this logging.properties:
# Logging
handlers = java.util.logging.ConsoleHandler
.level = INFO
# Console Logging
java.util.logging.ConsoleHandler.level = INFO
Before applying the patch the test was stuck after sending Type 1 message, because my Exchange server required NTLMv2 authentication. After the patch the athentication was done successfully.
来源:https://stackoverflow.com/questions/19076270/javamail-auth-ntlm-failed