Search
Close this search box.

Hunting those elusive Public Folders using Exchange Web Services (Part 1)

Recently the Exchange server at work has been upgraded to an Exchange 2007 SP1 server. With this has come the chance to finally get rid of the MAPI CDO solutions we have, by switching to using Exchange Web Services (EWS).

I’ve spent quite a while looking for easy ways of doing this, and for the majority of the time, it seems ok, but the biggest issue I’ve had (and unfortunately the solution I needed) was accessing public folders. Specifically public folders in a hierarchy.

 Public Folders\
               \Testing
               \Testing\Test 1\
               \Testing\Test 2\

In all the examples I’ve seen, we can find folders, but, by and large – they all only work for the first level of folders… and the other issue is that the examples are usually specific – i.e. they expect (for example) DistinguishedFolderIdType instead of it’s base – BaseFolderIdType.

Anyhews, on with the show!

First, we need to connect to our service, and that is as simple as adding a web reference (and yes – that’s in Visual Studio 2008 as well)… This will create our proxy to the EWS and we can begin to code.

The first object we need is the ExchangeServiceBinding class, this allows us to connect to the service.

ExchangeServiceBinding esb = new ExchangeServiceBinding();
esb.Credentials = CredentialCache.DefaultNetworkCredentials;
esb.Url = @"http://<your-server>/EWS/Exchange.asmx";

You can set credentials to be logged in as who you want, but in this case, I’m just taking the logged in users account. Also – as we need to access the public folders, we need to tell the binding that we’ll be using Exchange2007_SP1 (public folders aren’t accessible in non-SP1 versions).

esb.RequestServerVersionValue = new RequestServerVersion();
esb.RequestServerVersionValue.Version = ExchangeVersionType.Exchange2007_SP1;

Ok, let’s start with a method that can *find* a folder…

private static FolderIdType FindFolder(ExchangeServiceBinding esb,
                                       BaseFolderIdType folderId,
                                       string folderName) {
  FindPublicFolderType request = new FindPublicFolderType();
  request.Traversal = FolderQueryTraversalType.Shallow;
  request.FolderShape = new FolderResponseShapeType();
  request.FolderShape.BaseShape = DefaultShapeNamesType.AllProperties;
  request.ParentFolderIds = new BaseFolderIdType[] { folderId };
  ;

  FindPublicFolderResponseType response = esb.FindPublicFolder(request);

  foreach (ResponseMessageType rmt in response.ResponseMessages.Items) {
    if (rmt.ResponseClass == ResponseClassType.Success) {
      FindPublicFolderResponseMessageType ffResponse =
          (FindPublicFolderResponseMessageType)rmt;
      if (ffResponse.RootFolder.TotalItemsInView > 0) {
        foreach (BaseFolderType subFolder in ffResponse.RootFolder.Folders)
          if (subFolder.DisplayName == folderName)
            return subFolder.FolderId;

        return null;
      }
      Console.WriteLine("Can't find '" + folderName + "'.");
    } else {
      Console.WriteLine("Response was: " + rmt.ResponseClass +
                        Environment.NewLine + rmt.MessageText);
    }
  }
  return null;
}

The basic flow is to generate a request, then call the service and deal with the response.
To use this on a public folder we’d do:

DistinguishedFolderIdType rootPublicFolders = new DistinguishedFolderIdType() { Id=DistinguishedFolderIdNameType.publicfoldersroot };
FolderIdType testingFolderId = FindPublicFolder( esb, rootPublicFolders, "Testing" );

This would find ‘Testing’ without any problems, but if we want to find ‘Test1’ we’re in trouble, for example, if we try:

FolderIdType test1FolderId = FindPublicFolder( esb, parentFolder, "Test1" );

We get nothing, if we try:

FolderIdType test1FolderId = FindPublicFolder( esb, parentFolder, "Testing\\Test1" );

Nothing.

FolderIdType test1FolderId = FindPublicFolder( esb, parentFolder, "Testing/Test1" );

Again nothing.
The reason?
The search traversal… we’re only doing a shallow traversal – so we can only find the folders off of the root. Ok – so why not go ‘deep’? Well, the answer is that you can’t use a deep traversal on public folders. Presumably because it effects everyone, and not just your own account (just a guess there).

Anyhews – we’re stuck on that fact, and as a result need to implement some recursive snazziness here…
We know we can find a folder on the same level (i.e. such as testing)… and if we do something like:

FolderIdType test1FolderId = FindPublicFolder( esb, FindPublicFolder( esb, parentFolder, "Testing" ), "Test1" );

We can get the correct folder ID. So let’s begin the coding based on the fact we *know* the folder explicitly… The input we want to take is something like:
 “Testing\Test1”

So, we’re gonna want to split this string up:

private static void SplitFolder(string folder, out string first,
                                out string rest) {
  if (string.IsNullOrEmpty(folder)) {
    first = folder;
    rest = null;
    return;
  }

  if (!folder.Contains("\\")) {
    first = folder;
    rest = null;
    return;
  }

  first = folder.Substring(0, folder.IndexOf("\\"));
  rest = folder.Substring(folder.IndexOf("\\") + 1,
                          folder.Length - folder.IndexOf("\\") - 1);
}

In a call:

string first, rest;
SplitFolder("Testing\\Test1", out first, out rest);

We’ll get:

first == "Testing"
rest == "Test1"

Now let’s modify the FindFolder method to be recursive when needed…

private static FolderIdType FindPublicFolder(ExchangeServiceBinding esb,
                                             BaseFolderIdType folderId,
                                             string folderName) {
  string first, rest;
  SplitFolder(folderName, out first, out rest);

  FindFolderType request = new FindFolderType();
  request.Traversal = FolderQueryTraversalType.Shallow;
  request.FolderShape = new FolderResponseShapeType();
  request.FolderShape.BaseShape = DefaultShapeNamesType.AllProperties;
  request.ParentFolderIds = new BaseFolderIdType[] { folderId };
  ;

  FindFolderResponseType response = esb.FindFolder(request);

  FolderIdType outId = null;
  foreach (ResponseMessageType rmt in response.ResponseMessages.Items) {
    if (rmt.ResponseClass == ResponseClassType.Success) {
      FindFolderResponseMessageType ffResponse =
          (FindFolderResponseMessageType)rmt;
      if (ffResponse.RootFolder.TotalItemsInView > 0) {
        foreach (BaseFolderType subFolder in ffResponse.RootFolder.Folders)
          if (subFolder.DisplayName == first) {
            outId = subFolder.FolderId;
            break;
          }

      } else
        Console.WriteLine("Can't find '" + first + "'.");
    } else {
      Console.WriteLine("Response was: " + rmt.ResponseClass +
                        Environment.NewLine + rmt.MessageText);
    }
  }

  if (string.IsNullOrEmpty(rest))
    return outId;

  return FindPublicFolder(esb, outId, rest);
}

So, now we can do:

FolderIdType folderId = FindPublicFolder(esb, parentFolder, "Testing\\Test1");

and we’ll get the correct folder Id.
Phew!

What’s next?
There’s a few avenues we can take – maybe attempt to implement a deep traversal of the public folders?
But I feel of more interest is actually getting the messages in our newly discovered folder!
I’ll cover that in the next post, on the ‘FindItem’ API call…

This article is part of the GWB Archives. Original Author: XClave

Related Posts