Follow @abushalihu Abu The Geek: Microsoft Exchange Connector - Exchange Web Services (EWS) API in Java

Thursday, October 13, 2011

Microsoft Exchange Connector - Exchange Web Services (EWS) API in Java

     Hi! Friends... After a long gap I would like to share an useful Java API called EWS.
Exchange Web Services (EWS) is an open source Java API written by Microsoft. This API provides developers programmatic access to Microsoft Exchange Servers (Versions 2007 and above) through Java. The latest version is 1.1.5. By using the API you can send, receive emails. To use this API in your Java program you have to download and install the below third party libraries. In the given version 1.1.5 there was an issue with handling of Control Characters. That API failed to handle the Control Character's. I found that issue when i receive an email which contains Control Characters from MS Exchange Server 2010. I have upgraded this API to 1.1.5.1 in which i have removed all the Control Characters.

Pre-requisites

Download and install the Java SDK

The below required libraries included in the lib directory.

Apache Commons HttpClient 3.1
Apache Commons Codec 1.4
Apache Commons Logging 1.1.1
JCIFS 1.3.15

Accessing EWS by using the EWS Java API
ExchangeService service = new ExchangeService();
ExchangeCredentials credentials = new WebCredentials("emailId@domain.com", "password");
service.setCredentials(credentials);
To set the Exchange webservice URL
String uri = https://hostName/ews/Exchange.asmx;
URI uriObj = new URI(uri);
service.setUrl(uriObj);

Here hostName is your exchange server's domain name. (eg. mail.microsoft.com)

To set the Exchange webservice URL by Autodiscover
service.autodiscoverUrl("<your e-mail address>");
The autodiscoverurl method takes your emailId as argument and it automatically fetches the exchange webservice's nearest endpoint.
You have to set your endpoint URL by manually or using autodiscovery but not both!.

Sample Program to receive unread emails in inbox from MS Exchange Server:

import java.net.URI;
import java.util.Iterator;
import microsoft.exchange.webservices.data.ConflictResolutionMode;
import microsoft.exchange.webservices.data.EmailMessage;
import microsoft.exchange.webservices.data.EmailMessageSchema;
import microsoft.exchange.webservices.data.ExchangeCredentials;
import microsoft.exchange.webservices.data.ExchangeService;
import microsoft.exchange.webservices.data.FindItemsResults;
import microsoft.exchange.webservices.data.Item;
import microsoft.exchange.webservices.data.ItemId;
import microsoft.exchange.webservices.data.ItemSchema;
import microsoft.exchange.webservices.data.ItemView;
import microsoft.exchange.webservices.data.SearchFilter;
import microsoft.exchange.webservices.data.SortDirection;
import microsoft.exchange.webservices.data.WebCredentials;
import microsoft.exchange.webservices.data.WellKnownFolderName;

class EWSReadEmail {
public static void main(String args[]) throws Exception {
    ExchangeService service = new ExchangeService();
    ExchangeCredentials credentials = new WebCredentials("emailId@domain.com", "password");
    service.setCredentials(credentials);
    URI uri = new URI("https://yourhostname/ews/Exchange.asmx");
    service.setUrl(uri);
    ItemView view = new ItemView(100);    //Read maximum of 100 emails
    view.getOrderBy().add(ItemSchema.DateTimeReceived, SortDirection.Ascending);    // Read emails by received date order by Ascending
    FindItemsResults < Item > results = service.findItems(WellKnownFolderName.Inbox, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false), view);    //Read only unread emails in inbox
    Iterator<Item> itr = results.iterator();
    System.out.println("Total Unread Emails="+ results.getTotalCount());
    while(itr.hasNext()) {
        Item item = itr.next();
        ItemId itemId = item.getId();
        EmailMessage email = EmailMessage.bind(service, itemId);
        System.out.println("Sender= " + email.getSender());
        System.out.println("Subject= " + email.getSubject());
        System.out.println("Body= " + email.getBody());
        email.setIsRead(true);        //Set the email to read.
        email.update(ConflictResolutionMode.AlwaysOverwrite);
    }
    }
}
You can download the source and binaries here

13 comments:

  1. Hey Abu,
    Great article! I'm having problems overriding the autodiscoverURL method with the callback argument. Have you had any luck with this? I'm not a C# coder, and am having a hard time implementing the interface they want me to. The rest of the API seems simple enough!

    Thank you...Matt

    ReplyDelete
  2. Hello,
    I'm really interested about the source and binaries you published, but the file don't exist anymore. Can I hope you to put them again on your blog?

    ReplyDelete
  3. Hi Slade,

    First of all Thanks for your comment and Sorry for the inconvenience. Now i have uploaded the source and binary of the Exchange connector api in zippyshare.com. Enjoy!!

    ReplyDelete
  4. In the Above COde Leave out this one:
    ***********************************************
    mess=email.getSubject();
    if(mess.length()>10)
    {
    System.out.println("******************************");
    System.out.println("\nEntire Message::"+mess);
    nopart=mess.substring(4,14);
    System.out.println("\nMessage number::"+nopart);

    subpart=mess.substring(15);
    System.out.println("\nMessage sub::"+subpart);
    SMSClient.client(nopart,subpart);
    System.out.println("******************************");

    //System.out.println("Body= " + email.getBody());
    email.setIsRead(true); //Set the email to read.
    email.update(ConflictResolutionMode.AlwaysOverwrite);
    }
    else
    {
    System.out.println("Not a valid message for sending SMS");
    }


    ***********************************************************

    ReplyDelete
  5. I get this error using your code:

    Nov 21, 2012 12:40:05 PM org.apache.commons.httpclient.auth.AuthChallengeProcessor selectAuthScheme
    INFO: NTLM authentication scheme selected
    Nov 21, 2012 12:40:05 PM org.apache.commons.httpclient.HttpMethodDirector processWWWAuthChallenge
    INFO: Failure authenticating with NTLM @mail.gruporumos.com:443
    microsoft.exchange.webservices.data.EWSHttpException: Connection not established
    at microsoft.exchange.webservices.data.HttpClientWebRequest.throwIfConnIsNull(Unknown Source)

    ReplyDelete
  6. Hi Abu,
    I have downloaded your project and configuration but I get Bad verion number error in Eclipse although I am using the same configuration you providing. Why do you think this is happening?

    ReplyDelete
  7. Hi,
    You have not given the Error Stack here. In general Bad version number error might be you have compiled your java file to a class file with one version and trying to run it with an earlier version. Make sure you are using the same version of java to compile and run. If still you have problem please share your sample program and the error stack trace and include the version of eclipse and java.

    ReplyDelete
  8. Thanks Abu, I have seen the problem, i should have run it with Java 1.6 instead of 1.5.
    Now I am having this kind of exception, could you please help?
    Thanks a lot

    My code is as follows,
    try{
    ExchangeService service = new ExchangeService();
    ExchangeCredentials credentials = new WebCredentials("testemail@mycompany.com,
    "thisismypassword");
    service.setCredentials(credentials);
    service.setUrl(new URI("https://fbexccas.testserver.local"));
    EmailMessage msg= new EmailMessage(service);
    msg.setSubject("Hello world!");
    msg.setBody(MessageBody.getMessageBodyFromText("Sent using the EWS Managed API."));
    msg.getToRecipients().add("testemail@mycompany.com");
    msg.send();
    }catch (Exception e) {
    e.printStackTrace();
    // TODO: handle exception
    }
    Then this is my exception.

    microsoft.exchange.webservices.data.ServiceRequestException: The request failed. An element node 'soap:Envelope' of the type START_ELEMENT was expected, but node 'head' of type START_ELEMENT was found.
    at microsoft.exchange.webservices.data.SimpleServiceRequestBase.internalExecute(Unknown Source)
    at microsoft.exchange.webservices.data.MultiResponseServiceRequest.execute(Unknown Source)
    at microsoft.exchange.webservices.data.ExchangeService.internalCreateItems(Unknown Source)
    at microsoft.exchange.webservices.data.ExchangeService.createItem(Unknown Source)
    at microsoft.exchange.webservices.data.Item.internalCreate(Unknown Source)
    at microsoft.exchange.webservices.data.EmailMessage.internalSend(Unknown Source)
    at microsoft.exchange.webservices.data.EmailMessage.send(Unknown Source)
    at MyTest.main(MyTest.java:45)

    ReplyDelete
  9. Hi Friend,
    Try your Exchange URI something like the one given below
    https://your_host_name/EWS/Exchange.asmx

    thanks
    Abu

    ReplyDelete
  10. Hi,

    I have tested your API with EWS 2010 and NTLM auth... it works fine!!!

    thanks

    Enrico

    ReplyDelete
  11. Hi Abu,

    Excellent, solved the problem which I had, even coming from a non java background was able to do it easily.

    Thanks
    Tapan

    ReplyDelete
  12. hi,
    Do you have any idea how to check user availability before sending a meeting request to outlook from a java application

    ReplyDelete
  13. This is a great inspiring article.I am pretty much pleased with your good work.You put really very helpful information... Best SEO Services Company

    ReplyDelete