Monday, August 23, 2010

Connecting to Microsoft Exchange Server from a Java Client




Recently I was involved in a project to create a Java client to connect to MS Exchange Server in order to send mails from an online e-commerce system. Though I have worked with Java Mail to send / read mails, this was new to me. So I started researching on this and soon found out even though there were many articles regarding connectivity I could not find any that gave a complete end to end description about connecting from a Java client to MS Exchange. Hence I thought of writing this article so anyone who wants to do the same would find it much more easier to get the connectivity up and running.



Well from what I got to know from my research is that there are two ways to connect to MS Exchange server. One is to use WEBDAV, which is an open source implementation of MODDAV, and the other is to use EWS (Exchange Web Service). There are several commercial and open source API's you can use mainly exjello-1.0, j-xchange_1_01, ewsj1.20_35. I of course being me wanted to code from scratch so I used both EWS and WEBDAV to see how both worked and ended up using the more conventional EWS. However in this article I will use EWS to connect to Exchange Server / Send a Mail via EWS. My next article would be on the WEBDAV implementation for the same set of operations. So here goes with the EWS implementation.


First things first, you need to decide how you want to do the EWS connectivity. Are you going to write the SOAP messages by hand (which is going to take some time for research in order to find the correct messages and implement, So good luck as you will need that ) or to use a web service client package to create the RPC calls like Axis or JAX-WS. Again I of course tried both so will give you a glimpse into both but I recommend using Axis or JAX-WS which is lot more easier/ cleaner and more standardized.



Axis2 implementation

First you will need to download the Axis2 package, and set that up (which I will not in to detail as you can get that from Axis website)
Second you will need to have a valid MS Exchange server setup properly with EWS enabled. (which is outside the scope of this document)
Get the MS Exchange services WSDL which you can get from connecting to your exchange server Exchange.asmx i.e. https://<your exchange server>/EWS/Exchange.asmx”



You will have to get the following files to build your connectivity Services.wsdl, types.xsd, messages.xsd. Note that there are some small changes that needs to be done here. After you get the schemas (xsd) files change the names to lowers case. Then check and see if you have “wsdl:service” element in your services.wsdl. Normally in MS Exchange 2010, this is available, but in previous implementations this is missing, so you may need to put the following after the “wsdl:bindings”

<!-- SetUserOofSettings -->
<wsdl:operation name="SetUserOofSettings">
<soap:operation soapAction="http://schemas.microsoft.com/exchange/services/2006/messages/SetUserOofSettings"/>
<wsdl:input>
<soap:body parts="SetUserOofSettingsRequest" use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body parts="SetUserOofSettingsResult" use="literal"/>
<soap:header message="tns:SetUserOofSettingsSoapOut" part="ServerVersion" use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ExchangeServices">
<wsdl:port name="ExchangeServicePort" binding="tns:ExchangeServiceBinding">
<soap:address location="https://<your exchange server>/EWS/Exchange.asmx"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>


Once you have these done, use wsdl2java tool in Axis (I used axis2) to generate the schema objects. Note that you will need to have the two XSD's in the same location as the wsdl file.
i.e. ./wsdl2java.sh -uri Services.wsdl -o EWS
Once the tool completes without any errors you will get three folders structures. Mainly you will get the generated java stubs for messages and types and a set of binaries for the connectivity.
You will get the following folder structures
EWS/resources
EWS/src


The src folder will contain all the Exchange messages and types while the resources will contain the binaries.
Now we move to our IDE, I used eclipse 3.4



First create a Dynamic Web Project. Add EWS folder to your project. You will need to add EWS/resources folder to your compile/run-time class-path.


Add your Axis2 libraries to your IDE compile/ run-time class-path
Now we are ready to connect to EWS and send mails


Connecting EWS via Axis stubs

The following code snippet connects to an EWS instance and sends an email. I will explain part by part how the application works.


public void send() throws EWSException {
      // Exchange service client stub that is used for all connectivities 
        ExchangeServicesStub service = null;
        try {
            service = new ExchangeServicesStub(null, ewsURI);
            ServiceClient sc = service._getServiceClient();
            
            // If authentication is required
            HttpTransportProperties.Authenticator auth = new
             HttpTransportProperties.Authenticator();
            auth.setPassword(passWord);
            auth.setDomain(domain);
            auth.setUsername(userName);
            auth.setHost(host);

            sc.getOptions().setProperty(HTTPConstants.AUTHENTICATE, auth);

            // Creating EWS email request object. 
            CreateItemType createEmailRequest = CreateItemType.Factory
                    .newInstance();
            createEmailRequest
                 .setMessageDisposition(MessageDispositionType.SEND_AND_SAVE_COPY);

            // Set up the folder to send
                            createEmailRequest.setSavedItemFolderId(TargetFolderIdType.Factory
                    .newInstance());
            DistinguishedFolderIdType sentitems = DistinguishedFolderIdType.Factory
                    .newInstance();
            sentitems.setId(DistinguishedFolderIdNameType.SENTITEMS);
            createEmailRequest.getSavedItemFolderId().setDistinguishedFolderId(
                    sentitems);

            // Create a message to Send
            BodyType bodyType = BodyType.Factory.newInstance();
            bodyType.setStringValue(HTMLMessage);
            MessageType message = MessageType.Factory.newInstance();
            message.setSubject(subject);
            message.setBody(bodyType);
            message.getBody().setBodyType(BodyTypeType.HTML);

            // Setting the From Address
            EmailAddressType sender = EmailAddressType.Factory.newInstance();
            sender.setEmailAddress(fromAddress);
            SingleRecipientType singleRecp = SingleRecipientType.Factory
                    .newInstance();
            singleRecp.setMailbox(sender);
            message.setSender(singleRecp);



            // Setting To Addresses
            EmailAddressType[] toMailAddressTypeArray = new
                       EmailAddressType[toAddress.length];

            for (int i = 0; i < toAddress.length; i++) {
                EmailAddressType toMailAddressType = EmailAddressType.Factory
                        .newInstance();
                toMailAddressType.setEmailAddress(toAddress[i]);
                toMailAddressTypeArray[i] = toMailAddressType;
            }

            ArrayOfRecipientsType recipientsArray = ArrayOfRecipientsType.Factory
                    .newInstance();
            recipientsArray.setMailboxArray(toMailAddressTypeArray);
            message.setToRecipients(recipientsArray);
            message.setSensitivity(SensitivityChoicesType.NORMAL);

            // Setup the messages to send
            NonEmptyArrayOfAllItemsType nonEmptyArrayOfElements = 
                        NonEmptyArrayOfAllItemsType.Factory    .newInstance();
            MessageType[] messageArray = new MessageType[1];
            messageArray[0] = message;
            nonEmptyArrayOfElements.setMessageArray(messageArray);
            createEmailRequest.setItems(nonEmptyArrayOfElements);

            CreateItemDocument crDoc = CreateItemDocument.Factory.newInstance();
            crDoc.setCreateItem(createEmailRequest);

            // Ready to send and sending.
            CreateItemResponseDocument crRepDoc = service.createItem(crDoc,
                    null, null, null, null);

            // Get a list of response messages.
            CreateItemResponseType responses = crRepDoc.getCreateItemResponse();
            ArrayOfResponseMessagesType responseMessages = responses
                    .getResponseMessages();

            for (int i = 0; i < responseMessages
                    .getCreateItemResponseMessageArray().length; i++) {
                     System.out.println(responseMessages.
                        getCreateItemResponseMessageArray()[i].xmlText());
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                service.cleanup();
            } catch (Exception err) {
                err.printStackTrace();
            }
        }

    }
 



Well that's it. Now you can use Exchange server to send mail. Hope this guide helps you to connect to EWS using Axis. In the next article I will show how to use a pure SOAP message to connect to EWS without axis and then we will move on to the WEBDAV implementation.