3

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

Azzedine madi
  • 93
  • 1
  • 3
  • 10
  • did you check out this question? http://stackoverflow.com/questions/4337812/javamail-ntlm-authentication-failure – epoch Sep 29 '13 at 09:33
  • @epoch : yes i did,its'nt the same thing ,in this exemple i use the smtp protocol and in the other he use the imap protocol and the LOGIN mechanism : "DEBUG SMTP: check mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM AUTH LOGIN" – Azzedine madi Sep 29 '13 at 09:43
  • Depending on exchange configuration it may be necessary to specify username in DOMAIN\username form – Jk1 Sep 29 '13 at 09:46
  • @jk1 : i try all this combinaison : user_name,user_name@myDomain.com,myDomain.com\user_name but the same msg error appear – Azzedine madi Sep 29 '13 at 09:59
  • @Azzedinemadi, it is not myDomain.com, it should be the windows domain name – epoch Sep 29 '13 at 10:21
  • @epoch : i put the domain name of my company of course,that what i mean with my domain – Azzedine madi Sep 29 '13 at 10:25
  • Based on the error message in the exception, it looks like something is messed up with the protocol exchange. Can you post the entire debug output? Also, do you have an anti-virus program running, which might be filtering your email connections? – Bill Shannon Sep 30 '13 at 06:54
  • @BillShannon : ok,i will edit my post to put my entire debug output,and for the anti-virus i disable it but i have the same msg error – Azzedine madi Sep 30 '13 at 08:05
  • It looks like you might be getting an unexpected exception while trying to initialize the NTLM authentication. Please contact me at javamail_ww@oracle.com so we can debug this further. – Bill Shannon Sep 30 '13 at 18:06
  • After some offline debugging, this appears to be a problem with the JDK installation or configuration related to cryptography support. JavaMail was hiding the real source of the error, which is something I will fix, but the underlying problem needs to be fixed as well and that's not related to JavaMail. – Bill Shannon Oct 01 '13 at 21:06
  • @BillShannon : thanks bill,i have done a new instalation of the jdk and it's work,you're an angel!! ^^ – Azzedine madi Oct 02 '13 at 09:09

2 Answers2

5

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.

Cookalino
  • 1,559
  • 14
  • 19
0

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.

Andrea Luciano
  • 461
  • 3
  • 5