My favorites | Sign in
Project Home Downloads Issues Source
Search
for
ExchangeWebServices  
Updated Nov 28, 2009 by joseph.j...@gmail.com

Home | Intro to Exchange Web Services

Introduction to Exchange Web Services

Configuring Exchange for Web Services

MS Exchange 2007 does provide Web Services out of the box, but you have to set it up.

Modify https://my.exchange.com/ews/Services.wsdl

This WSDL file can be accessed either via the URL above directly or by going to the Web Service like this https://my.exchange.com/ews/Exchange.asmx?wsdl which will just redirect you there. This WSDL file DOES NOT contain a

<service>
</service>
tag. So you have to add it to the end of the WSDL file.

...

   <wsdl:service name="ExchangeServices">
     <wsdl:port name="ExchangeServicePort" binding="tns:ExchangeServiceBinding">
       <soap:address location="https://my.exchange.com/EWS/Exchange.asmx"/>
     </wsdl:port>
   </wsdl:service>

</wsdl:definitions>

I also added xml:lang="EN" attribute to the root element in the following files to avoid warnings during WSDL-to-Java code generation.

Using Java to Access Exchange Web Services

wsdl-to-java Code Generation

I tried using Axis2 via the Eclipse Plugin, but it creates a monolithic stub that makes Eclipse puke. I also tried Axis, but it failed for some reason that I can't remember now that I am writing this, but I think it had to do with the complexity of Exchanges XML Schema files. Any how I ended up using JAXWS to generate my stubs. I copied the three files above locally and generated off of those, since Exchange is locked down with ssl.

JAXWS will create two packages:

  1. com.microsoft.schemas.exchange.services.2006.messages
  2. com.microsoft.schemas.exchange.services.2006.types

The most important Classes generated are in the com.microsoft.schemas.exchange.services.2006.messages package: ExchangeServices.java and ExchangeServicePortType, since they are used in connecting to the Web Service. Here is my ExchangeServerFactory class. Please note that you have to Authenticate via Basic Auth to the server.

public class YaleExchangeServerPortFactory extends ExchangeServerPortFactory {
	
	String uri;
	String adDomain;
	String uid;
	String pwd;
	ExchangeServices service;
	Authenticator basicAuth;
	
	static{
		javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(new AllTrustingSocketFactory());
	}
	
	/**
	 *  Set up Authentication
	 *
	 */
	protected void setupAuthenticator(){
		if(basicAuth == null){
			basicAuth = new Authenticator(){
				protected PasswordAuthentication getPasswordAuthentication(){
					String superUid = YaleExchangeServerPortFactory.this.adDomain
					                + "\\" 
					                + YaleExchangeServerPortFactory.this.uid;
					String superPwd = YaleExchangeServerPortFactory.this.pwd;
					return new PasswordAuthentication(superUid
							                 ,superPwd.toCharArray());
				}
			};
			Authenticator.setDefault(basicAuth);
		}
	}

	public ExchangeServicePortType getExchangeServerPort() {
		ExchangeServicePortType port = null;
		try{
			port = getExchangeServices().getExchangeServicePort();
		} catch (Exception e){
			throw new RuntimeException(e);
		}
		return port;
	}
	
	protected ExchangeServices getExchangeServices() throws Exception{
		setupAuthenticator();
		if(service == null) service = new ExchangeServices(new URL(uri));
		return service;
	}

	public String getAdDomain() {
		return adDomain;
	}

	public void setAdDomain(String adDomain) {
		this.adDomain = adDomain;
	}

	public String getUri() {
		return uri;
	}

	public void setUri(String uri) {
		this.uri = uri;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getUid() {
		return uid;
	}

	public void setUid(String uid) {
		this.uid = uid;
	}

}

One other quick note: If you are connecting to a Development Server, or any server that does not have a Trusted SSL certificate, you will have to import that Cert into your java cert store.

Keep reading we are almost there!!!!

You can see from the Factory Class that our proxy object is ExchangeServicePortType. This class needs modification so that you can use it. See blow the example for the explaination of what I did. This is only a sample of the file:

//    @WebMethod(operationName = "FindFolder", action = "http://schemas.microsoft.com/exchange/services/2006/messages/FindFolder")
//    public void findFolder(
//        @WebParam(name = "FindFolder", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", partName = "request")
//        FindFolderType request,
//        @WebParam(name = "ExchangeImpersonation", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "Impersonation")
//        ExchangeImpersonationType impersonation,
//        @WebParam(name = "SerializedSecurityContext", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "S2SAuth")
//        SerializedSecurityContextType s2SAuth,
//        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
//        @WebParam(name = "MailboxCulture", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "MailboxCulture")
//        String mailboxCulture,
//        @WebParam(name = "FindFolderResponse", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", mode = WebParam.Mode.OUT, partName = "FindFolderResult")
//        Holder<FindFolderResponseType> findFolderResult,
//        @WebParam(name = "ServerVersionInfo", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, mode = WebParam.Mode.OUT, partName = "ServerVersion")
//        Holder<ServerVersionInfo> serverVersion);

  @WebMethod(operationName = "FindFolder", action = "http://schemas.microsoft.com/exchange/services/2006/messages/FindFolder")
  public void findFolder(
      @WebParam(name = "FindFolder", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", partName = "request")
      FindFolderType request,
      @WebParam(name = "ExchangeImpersonation", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, partName = "Impersonation")
      ExchangeImpersonationType impersonation,
      @WebParam(name = "FindFolderResponse", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", mode = WebParam.Mode.OUT, partName = "FindFolderResult")
      Holder<FindFolderResponseType> findFolderResult,
      @WebParam(name = "ServerVersionInfo", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, mode = WebParam.Mode.OUT, partName = "ServerVersion")
      Holder<ServerVersionInfo> serverVersion);

  @WebMethod(operationName = "FindFolder", action = "http://schemas.microsoft.com/exchange/services/2006/messages/FindFolder")
  public void findFolder(
      @WebParam(name = "FindFolder", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", partName = "request")
      FindFolderType request,
      @WebParam(name = "FindFolderResponse", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages", mode = WebParam.Mode.OUT, partName = "FindFolderResult")
      Holder<FindFolderResponseType> findFolderResult,
      @WebParam(name = "ServerVersionInfo", targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/types", header = true, mode = WebParam.Mode.OUT, partName = "ServerVersion")
      Holder<ServerVersionInfo> serverVersion);

The commented method signature is what was created by JAXWS. When you use it, the parameter of SerializedSecurityContext does not support isNil, and the call fails if you leave this information out. It is used for server to server communcation. Good luck to ya, if you want to figure it out and use it. By removing the paramter, the element is never written in the soap message getting around the problem. I broke each stub into two signatures to allow for the use of Impersonation.

MS Exchange Impersonation

Impersonation is the use of credentials that have impersonation privileges to perform actions as an other individual. You have to set this up.

Please follow directions here: http://msdn2.microsoft.com/en-us/library/bb204095.aspx

Exchange Web Service Calls

Well... that just about does it for setup, now you can start to write Web Services calls for Exchange. Just to help out, here are two methods I use to get data from Exchange WS.

These are used to get the list of root folders... In this case I only want mail folders, so the results are limited.

        public static String EXCHANGE_MAIL_FOLDER_CLASS = "IPF.Note";

	public static List<BaseFolderType> getRootMailFolders(User user){
		DistinguishedFolderIdType root = new DistinguishedFolderIdType();
		root.setId(DistinguishedFolderIdNameType.MSGFOLDERROOT);
		return getChildFolders(user, root);
	}

	public static List<BaseFolderType> getChildFolders(User user, BaseFolderIdType parentFolderId){

		// Create FindFolder
		FindFolderType finder = new FindFolderType();
		
		NonEmptyArrayOfPathsToElementType paths = new NonEmptyArrayOfPathsToElementType();
		paths.getPath().add(PrStatus.PR_STATUS_PATH);

		FolderResponseShapeType folderShape = new FolderResponseShapeType();
		folderShape.setBaseShape(DefaultShapeNamesType.ALL_PROPERTIES);
		folderShape.setAdditionalProperties(paths);
		
		finder.setFolderShape(folderShape);
		finder.setTraversal(FolderQueryTraversalType.SHALLOW);
		
		IndexedPageViewType index = new IndexedPageViewType();
		index.setBasePoint(IndexBasePointType.BEGINNING);
		index.setOffset(0);
		
		finder.setIndexedPageFolderView(index);
		
		NonEmptyArrayOfBaseFolderIdsType folderIds = new NonEmptyArrayOfBaseFolderIdsType();
		List<BaseFolderIdType> ids = folderIds.getFolderIdOrDistinguishedFolderId();
		ids.add(parentFolderId);
		finder.setParentFolderIds(folderIds);
		
		// define response Objects and their holders
		FindFolderResponseType findFolderResponse = new FindFolderResponseType();
		Holder<FindFolderResponseType> responseHolder = new Holder<FindFolderResponseType>(findFolderResponse);

		ServerVersionInfo serverVersion = new ServerVersionInfo();
		Holder<ServerVersionInfo> serverVersionHolder = new Holder<ServerVersionInfo>(serverVersion);

		ExchangeServicePortType proxy = null;
		List<BaseFolderType> mailFolders = new ArrayList<BaseFolderType>();
		List<JAXBElement <? extends ResponseMessageType>> responses = null;
		try{
			proxy = ExchangeServerPortFactory.getInstance().getExchangeServerPort();
			proxy.findFolder(finder, user.getImpersonation() ,responseHolder, serverVersionHolder);
			responses = responseHolder.value.getResponseMessages()
			                                    .getCreateItemResponseMessageOrDeleteItemResponseMessageOrGetItemResponseMessage();
			                                

			for(JAXBElement <? extends ResponseMessageType> jaxResponse : responses){
				ResponseMessageType response = jaxResponse.getValue();
				if(response.getResponseClass().equals(ResponseClassType.ERROR)){
					logger.warn("Get Child Folders Response Error: " + response.getMessageText());
					user.getConversion().warnings++;
				} else if(response.getResponseClass().equals(ResponseClassType.WARNING)){
					logger.warn("Get Child Folders Response Warning: " + response.getMessageText());
					user.getConversion().warnings++;
				} else if(response.getResponseClass().equals(ResponseClassType.SUCCESS)){
					FindFolderResponseMessageType findResponse = (FindFolderResponseMessageType)response;
					List<BaseFolderType> allFolders =  findResponse.getRootFolder().getFolders().getFolderOrCalendarFolderOrContactsFolder();
					for(BaseFolderType folder : allFolders){
						mailFolders.add(folder);
					}
				}
			}

		} catch (Exception e){
			throw new RuntimeException("Exception Performing getChildFolders", e);
		} 
		return mailFolders;
		
	}

This method is used to return message meta data from within a folder.

	public static List<MessageType> getMessages(User user, BaseFolderIdType folderId){
		
		FindItemType finder = new FindItemType();
	
		NonEmptyArrayOfPathsToElementType paths = new NonEmptyArrayOfPathsToElementType();
		paths.getPath().add(CONVERSION_UID_PATH);
		paths.getPath().add(IS_READ_PATH);
		paths.getPath().add(PrMessageFlags.PR_MESSAGE_FLAGS_PATH);

	        ItemResponseShapeType itemShape = new ItemResponseShapeType();		
		itemShape.setBaseShape(DefaultShapeNamesType.ID_ONLY);
		itemShape.setAdditionalProperties(paths);
		finder.setItemShape(itemShape);
	
		finder.setTraversal(ItemQueryTraversalType.SHALLOW);
		
		IndexedPageViewType index = new IndexedPageViewType();
		index.setBasePoint(IndexBasePointType.BEGINNING);
		index.setOffset(0);
		
		finder.setIndexedPageItemView(index);
		
		NonEmptyArrayOfBaseFolderIdsType folderIds = new NonEmptyArrayOfBaseFolderIdsType();
		List<BaseFolderIdType> ids = folderIds.getFolderIdOrDistinguishedFolderId();
		ids.add(folderId);
		finder.setParentFolderIds(folderIds);
		
		// define response Objects and their holders
		FindItemResponseType findItemResponse = new FindItemResponseType();
		Holder<FindItemResponseType> responseHolder = new Holder<FindItemResponseType>(findItemResponse);
	
		ServerVersionInfo serverVersion = new ServerVersionInfo();
		Holder<ServerVersionInfo> serverVersionHolder = new Holder<ServerVersionInfo>(serverVersion);
	
		ExchangeServicePortType proxy = null;
		List<MessageType> messages = new ArrayList<MessageType>();
		List<JAXBElement <? extends ResponseMessageType>> responses = null;
		try{
			proxy = ExchangeServerPortFactory.getInstance().getExchangeServerPort();
			proxy.findItem(finder, user.getImpersonation() ,responseHolder, serverVersionHolder);
			responses = responseHolder.value.getResponseMessages()
	                   .getCreateItemResponseMessageOrDeleteItemResponseMessageOrGetItemResponseMessage();
			
			for(JAXBElement <? extends ResponseMessageType> jaxResponse : responses){
				ResponseMessageType response = jaxResponse.getValue();
				if(response.getResponseClass().equals(ResponseClassType.ERROR)){
					logger.warn("Get Messages Response Error: " + response.getMessageText());
					user.getConversion().warnings++;
				} else if(response.getResponseClass().equals(ResponseClassType.WARNING)){
					logger.warn("Get Messages Response Warning: " + response.getMessageText());
					user.getConversion().warnings++;
				} else if(response.getResponseClass().equals(ResponseClassType.SUCCESS)){
					FindItemResponseMessageType findResponse = (FindItemResponseMessageType)response;
					for(ItemType item : findResponse.getRootFolder().getItems().getItemOrMessageOrCalendarItem()){
						// This filters out all the messages not moved by an earlier conversion...
						if((item.getExtendedProperty() != null) 
						&& !(item.getExtendedProperty().isEmpty())
						&& item instanceof MessageType){
							messages.add((MessageType)item);
						}
					}
				}
			}
	
		} catch (Exception e){
			throw new RuntimeException("Exception performing getMessages", e);
		} 
		return messages;
	}

The last tid-bit of information is that MS actual does a good job on documentation: http://msdn2.microsoft.com/en-us/library/bb204119.aspx

Well that is it for this introduction to Exchange Web Services. I hope I didn't forget anything, and I hope this helps...

Comment by mas...@gmail.com, Feb 17, 2010

Hi,

thanks for the great tutorial. I implemented methods for finding, creating, getting and deleting items (in my case CalendarItems?). All these are working well. Now I tried to implement the updateItem functionality and it always keeps me getting an internal server error message with no further information. Im sure that the server allows this and Im also quite sure, that my code should be right, since I oriented the code on the c# examples provided by msdn. So my question is, did you try implementing this method and did it work on your side? If so, could you post this method? Thank you very much in advance!!!!

Best regards

Nils

Comment by joseph.v...@gtempaccount.com, Feb 17, 2010

Nils,

I did not implement Calendar functionality. My project consisted of converting mail only. I would just make sure you are handling the response correctly, to get as much info as you can out of it. Since you say that it is an internal server error, there must be a error code returned, search that. The last bit of advise I have is to get your Exchange Admins to help see if they can give you more information from their side.

Good luck,

- Joe

Comment by faustole...@gmail.com, May 18, 2010

Hi. I have services.wsdl and the two xsd file. Could you post the exact command to execute to generate two packages jar? Many thanks

Comment by awilk...@spt.com, Jun 16, 2010

Hi,

on the ExchangeImpersonation? object which gets passed to the proxy operations it has the field shown below that shold contain the SID of the user.

@XmlElement?(name = "ConnectingSID", required = true) protected ConnectingSIDType connectingSID;

how do you retrieve this using Java ?

many thanks

Andy

Comment by bsturz...@gmail.com, Jul 12, 2010

but the class ExchangeServerPortFactory? where you have it?

Comment by shrivan...@gmail.com, Jul 12, 2010

Hello, i am getting en error stating

Caused by: org.apache.axis2.AxisFault?: No service was not found in the WSDL

Please help me to generate stub classes,

Himanshu

Comment by joseph.v...@gtempaccount.com, Jul 12, 2010

bsturzoiu,

Please check the svn repo for all classes...

Comment by joseph.v...@gtempaccount.com, Jul 12, 2010

shrivanshh,

The first section listed above states that you have to add the actual endpoint, the service tag, to the wsdl before you can generate off it.

Comment by shrivan...@gmail.com, Jul 13, 2010

Hello joseph,

Thanks for help, i am able to generate the stub classes. But the next problem is that while creating class YaleExchangeServerPortFactory? i am getting two errors 1. Cannot instantiate the type ExchangeServices?, and 2. AllTrustingSocketFactory? cannot be resolved to a type

Please let me know the solution. Thanks is advance

Comment by shrivan...@gmail.com, Jul 14, 2010

Hello,

My all of the errors get resolved, but while making a call to web service iam getting an error stating

<code> Exception in thread "main" java.lang.RuntimeException: javax.xml.ws.WebServiceException: {http://schemas.microsoft.com/exchange/services/2006/messages}ExchangeServices is not a valid service. Valid services are: at edu.yale.its.tp.email.conversion.yale.YaleExchangeServerPortFactory.getExchangeServerPort(YaleExchangeServerPortFactory.java:86) at main.java.Main.main(Main.java:16) </code>

The part of code which i tried on my side is:

<code> YaleExchangeServerPortFactory instance = new YaleExchangeServerPortFactory(); instance.setAdDomain("domain"); instance.setPwd("password"); instance.setUid("username"); instance.setUri("c:\Services.wsdl"); System.out.println(instance.getExchangeServerPort()); </code>

Please let me know the solution.

Comment by joseph.v...@gtempaccount.com, Jul 14, 2010

shrivanshh,

The URI is the end point for the ACTUAL service you are attempting to connect to. ie: https://my.company.com/ews/exchange.asmx

Comment by shrivan...@gmail.com, Jul 15, 2010

How can i define user object for exchange user? PrimarySMTPAddress, SourceImapPo?, and UPN properties are mandatory according to code. But how can i found those values for exchange user.

Comment by shrivan...@gmail.com, Jul 16, 2010

Thanks,

I got the solution i.e. instead of using user one can directly use <code> ExchangeServicePortType proxy = instance.getExchangeServerPort(); proxy.findFolder(finder, responseHolder, serverVersionHolder); </code>

Thanks a lot again :-)

Comment by prati.ba...@gmail.com, Jul 19, 2010

Hello joseph, I am stuck in findItem method. I am not getting any properties except ItemId?. Can anyone help me to get out of this issue..

Comment by shrivan...@gmail.com, Jul 19, 2010

Hello Prati, I was also facing the issue of getting only ItemId? during find/getItem methods. What you need to do is change the property of DefaultShapeNamesType?.ID_ONLY to DefaultShapeNamesType?.ALL_PROPERTIES Hope it works :-)

Comment by prati.ba...@gmail.com, Jul 19, 2010

Thanks shrivanshh, It works :-)

Comment by baloghzo...@gmail.com, Jul 29, 2010

Hi,

I would like to fetch all entries from an folder (actually from an contact). And if it possible search in the contact folder and fetch those entries which match the search filter. Somebody knows how to do it with exchange SOAP? What I find is that only ho to get a folder, how to find folders and hot to get an item from a folder.

Thanks for your help in advance!

Comment by bahuguna...@gmail.com, Aug 5, 2010

Hi, I am trying to retrieve Calendar events for a specific user. How to put search restriction may be on date while doing findItem operation ?

Comment by project member joseph.j...@gmail.com, Oct 7, 2010

bahuguna.yogesh,

Please read this page again. I clearly state that the distributed wsdl DOES NOT have a wsdl.service defined and you have to edit the file... This is because MS does not generate a wsdl, and provides an actual file. Each server will have its own endpoint and the Exchange Admins NEED to modify if before you can access the web service.

Comment by thomas.p...@telenet.be, Oct 7, 2010

Hey,

I commented out "<!--xs:attribute ref="xml:lang" use="optional" /-->" in types.xsd. Otherwise I couldn't finish the wsimport to get the java classes.

However I do seem to find other problems after that. For one I can't extend from ExchangeServerPortFactory? because it does not exist.

And

protected ExchangeServices? getExchangeServices() throws Exception{

setupAuthenticator(); if(service == null) service = new ExchangeServices?(new URL(uri)); return service;
}
the constructor ExchangeServices?(URL) doesn't exist either...

Does this sound familiar?

Comment by project member joseph.j...@gmail.com, Oct 7, 2010

thomas,

This project is for imap2exchange. I just posted this page a a helper to others that might want to use java ws to interact with exchange. The classes that you are looking for are extensions to the generated ws code that I wrote, and they are located in the svn repo of this project.

Comment by thomas.p...@telenet.be, Oct 7, 2010

as addition...

ExchangeService?(...) requires a QName... I did find some ObjectFactories? with lots of QNames defined in these generated MS classes, however finding the right one for this (if any) might be time consuming.

Either I'm using an older or newer exchange version, or something fishy is going on.

Comment by efere...@gmail.com, Jul 22, 2011

Greetings,

I used the following command to generate stub

/usr/lib/jvm/java-6-sun-1.6.0.26/bin/wsimport Services.wsdl -p edu.nau.its.ps -d jaxws/classes -s jaxws/src

Also I do not get the 2 packages you mentioned. We are using exchange 2010 service pack 1

When I use my test script to send a message I get " The request failed. Connection Error java.net.ProtocolException?: Server redirected too many times (20)" error.

Any help is appreciated.

Sincerely, Ahsan

Comment by project member joseph.j...@gmail.com, Jul 22, 2011

Add the following to you java options: -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe?.dump=true -Dcom.sun.xml.internal.ws.transport.http.HttpAdapter?.dump=true -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe?.dump=true -Dcom.sun.xml.ws.transport.http.HttpAdapter?.dump=true

This will trace the soap calls and hopefully you can follow the redirects to determine where the miss configuration is.

- Joe

Comment by nalinas...@gmail.com, Jul 23, 2011

Hi,

I need to create a calendar event/Meeting request in my application. Creating a meeting is a write service. For this above requirement I need to find the users to add them as participants and rooms based on the locations. For this above requirement, Can I use the same procedure which mentioned above? Or how shall I proceed? Please I need your advice.

Thanks, Nalin.

Comment by nalinas...@gmail.com, Jul 23, 2011

Adding to the previous comment. I need to develop using java technologies. My application is portlet based. When I googled around I found some "Exchange Web Services java API".Any idea on EWS java api? Is it advisable to use EWS java api?

Comment by alan.phi...@gmail.com, Sep 11, 2011

Guys, please take pity on what you'll think is a newbie question, but I'm an Exchange admin not a Java coder, and my knowledge of the Java technologies here is about zero. I do have a need to get an IMAP to Exchange migration under way almost imediately, though.

IMAP2Exchange is giving me the "WSDL.. contains no service definition" error.

Now, I can see from the top of this page that the MS Services.wsdl is missing things, but looking at the fix I'm still puzzled. Do I fix this with something in the client program? Or should I edit the various files on my Exchange servers?

I can do the Exchange changes; but I have no idea how to go about changes in the client.

All help gratefull received.

Alan

Comment by alan.phi...@gmail.com, Sep 11, 2011

Oh - to add to my post above, this is Exchange 2010 SP1. I think I do understand how to use the endorsed SOAP codec for this.

Alan

Comment by kamal.va...@gmail.com, Dec 7, 2011

Guys, what code modification is req for ntlm authentication instead of basic


Sign in to add a comment
Powered by Google Project Hosting