HOWTO: Create Search Folder using Exchange Impersonation for multiple users via Exchange Web Services
What are we doing here? What is Search Folder? Why do I care?
Search folders are a quick way to bookmark your frequently searched items. It allows you to save a search query with predefined parameters for quick access. For instance I am always looking for emails with attachments and from a particular sender where the subject has some specific words. Yeah a rule could do that but I want to search in multiple folders and keep the individual mails in their individual folders. Complex? not really!
Search folders can help you in creating all those complex queries and mapping them to a single folder to bring all the items under one umbrella, whether its raining or not.
So far everything sounds good now I want to implement this solution enterprise wide, I want to role out a specific query for everyone in my organization is it possible from GUI, server side script or any way to do this. Don’t even think about sending Outlook Macro Project to everyone in your organization. You have a better solution with Exchange 2007 SP1 – Exchange Web Services
I feel blessed with the existence of Exchange Web Services. You can use Exchange Impersonation to act on behalf of every individual in your Organization, go to every individual’s mailbox and create a search folder for them.
Ok now… stop talking and show me the code.. here you go!
using System;
using System.Collections.Generic;
using System.Text;
using SearchFolderCreator.MyEWS;
using System.Net;
using System.IO;
namespace SearchFolderCreator
{
class Program
{
static ExchangeServiceBinding esb = null;
const string strSearchText = "IPM.Note";
const string strEWSURL = "https://server/ews/exchange.asmx";
const string strUsername = "Username";
const string strPassword = "********";
const string strDomain = "Domain.com";
const string strSearchFolderName = "EWS Created Search Folder";
static void Main(string[] args)
{
esb = new ExchangeServiceBinding();
esb.Credentials = new NetworkCredential(strUsername, strPassword, strDomain);
esb.AllowAutoRedirect = true;
esb.Url = strEWSURL;
try
{
InstallForUser("NewUser@exchangeserver.com");
InstallForUser("Vikas@exchangeserver.com");
}
catch (Exception e)
{
Console.WriteLine("Exception Caught: " + e.ToString());
}
}
static BaseFolderType CreateSearchFolder()
{
FolderIdType folderID = new FolderIdType();
//create the request that will create a new searchfolder under the finder directory
CreateFolderType folderType = new CreateFolderType();
SearchFolderType[] folderArray = new SearchFolderType[1];
folderArray[0] = new SearchFolderType();
folderArray[0].SearchParameters = new SearchParametersType();
folderArray[0].SearchParameters.Traversal = SearchFolderTraversalType.Deep; // deep traversal
folderArray[0].SearchParameters.TraversalSpecified = true; // must set it to true otherwise traversal will have no effect
folderArray[0].SearchParameters.BaseFolderIds = new DistinguishedFolderIdType[1];
DistinguishedFolderIdType dType = new DistinguishedFolderIdType();
dType.Id = new DistinguishedFolderIdNameType();
dType.Id = DistinguishedFolderIdNameType.inbox; // we are looking at Inbox only
folderArray[0].SearchParameters.BaseFolderIds[0] = dType;
PathToUnindexedFieldType path = new PathToUnindexedFieldType();
path.FieldURI = UnindexedFieldURIType.itemItemClass; // Evaluating a string with Item Class
folderArray[0].SearchParameters.Restriction = new RestrictionType();
ContainsExpressionType expressionType = new ContainsExpressionType();
expressionType.Item = path;
expressionType.ContainmentModeSpecified = true;
expressionType.ContainmentMode = ContainmentModeType.FullString; // Matching full string
expressionType.ContainmentComparison = ContainmentComparisonType.Exact; // With Exact match
expressionType.ContainmentComparisonSpecified = true;
expressionType.Constant = new ConstantValueType();
expressionType.Constant.Value = strSearchText; // Subject to look for
folderArray[0].SearchParameters.Restriction.Item = expressionType;
folderArray[0].DisplayName = strSearchFolderName; // Give your search folder a unique name
folderType.Folders = folderArray;
TargetFolderIdType targetFolder = new TargetFolderIdType();
//Create the searchfolder under the Finder Folder
DistinguishedFolderIdType searchFolder = new DistinguishedFolderIdType();
searchFolder.Id = DistinguishedFolderIdNameType.searchfolders; // Saving it under searchfolders root
targetFolder.Item = searchFolder;
folderType.ParentFolderId = targetFolder;
// Uncomment the following lines of code to make it a hidden search folder, can be consumed by other programs and not visible to users
// See the explanintion below
// folderArray[0].ExtendedProperty = new ExtendedPropertyType[1];
// folderArray[0].ExtendedProperty[0] = new ExtendedPropertyType();
// folderArray[0].ExtendedProperty[0].ExtendedFieldURI = new PathToExtendedFieldType();
// folderArray[0].ExtendedProperty[0].ExtendedFieldURI.PropertyTag="0x10F4"; //PR_ATTR_HIDDEN
// folderArray[0].ExtendedProperty[0].ExtendedFieldURI.PropertyType = MapiPropertyTypeType.Boolean;
// folderArray[0].ExtendedProperty[0].Item = "true";
//Create the search folder
CreateFolderResponseType createFolderResponse = esb.CreateFolder(folderType);
//Return the newly created search folder
FolderInfoResponseMessageType folderInfo = (FolderInfoResponseMessageType)createFolderResponse.ResponseMessages.Items[0];
return folderInfo.Folders.Length == 0 ? null : folderInfo.Folders[0];
}
static bool DeleteSearchFolder()
{
string strSearchFolderID = null;
//get the search folder's ID
strSearchFolderID = SearchFolderExists();
if (strSearchFolderID==string.Empty || strSearchFolderID ==null)
return false;
FolderIdType folderID = new FolderIdType();
folderID.Id = strSearchFolderID;
//Now create the request that will delete the searchfolder using FolderID we have already
DeleteFolderType folderType = new DeleteFolderType();
folderType.DeleteType = DisposalType.HardDelete;
folderType.FolderIds = new BaseFolderIdType[1];
folderType.FolderIds[0] = folderID;
//Delete the search folder
DeleteFolderResponseType deleteFolderResponse = esb.DeleteFolder(folderType);
return deleteFolderResponse.ResponseMessages.Items[0].ResponseClass == ResponseClassType.Success ? true : false;
}
// Search for folder if it already exists
static string SearchFolderExists()
{
if (null == esb)
return false;
//get the root folder ID
DistinguishedFolderIdType[] fit = new DistinguishedFolderIdType[1];
fit[0] = new DistinguishedFolderIdType();
fit[0].Id = DistinguishedFolderIdNameType.searchfolders;
//set the props that we want to retrieve
FolderResponseShapeType frst = new FolderResponseShapeType();
frst.BaseShape = DefaultShapeNamesType.IdOnly;
//restrict the search on the folder name
PathToUnindexedFieldType ftFolderName = new PathToUnindexedFieldType();
ftFolderName.FieldURI = UnindexedFieldURIType.folderDisplayName;
ConstantValueType cvt = new ConstantValueType();
cvt.Value = strSearchFolderName;
FieldURIOrConstantType ctFolderName = new FieldURIOrConstantType();
ctFolderName.Item = cvt;
ContainsExpressionType cet = new ContainsExpressionType();
cet.Constant = cvt;
cet.Item = ftFolderName;
cet.ContainmentComparison=ContainmentComparisonType.Exact;
cet.ContainmentComparisonSpecified = true;
cet.ContainmentMode = ContainmentModeType.FullString;
cet.ContainmentModeSpecified = true;
RestrictionType rt = new RestrictionType();
rt.Item = cet;
//find the folder
FindFolderType fft = new FindFolderType();
fft.Traversal =FolderQueryTraversalType.Shallow;
fft.ParentFolderIds = fit;
fft.FolderShape = frst;
fft.Restriction = rt;
FindFolderResponseType ffrt = esb.FindFolder(fft);
ResponseMessageType rmt =
((ResponseMessageType)ffrt.ResponseMessages.Items[0]);
if (rmt.ResponseClass == ResponseClassType.Success)
{
FindFolderResponseMessageType folderInfo = (FindFolderResponseMessageType)ffrt.ResponseMessages.Items[0];
if (folderInfo.RootFolder.Folders.Length == 0)
return string.Empty;
else
{
return folderInfo.RootFolder.Folders[0].FolderId.Id;
}
}
else
return string.Empty;
}
static void InstallForUser(string primarySMTPaddress)
{
string SubscriptionID = null;
esb.ExchangeImpersonation = new ExchangeImpersonationType();
esb.ExchangeImpersonation.ConnectingSID = new ConnectingSIDType();
esb.ExchangeImpersonation.ConnectingSID.PrimarySmtpAddress = primarySMTPaddress;
Console.WriteLine("Processing \"" + primarySMTPaddress + "\"...");
Console.WriteLine("Checking if search folder already exists...");
if (!SearchFolderExists())
{
Console.WriteLine("Search folder does not exist, creating one...");
strSearchFolderID = CreateHiddenSearchFolder().FolderId.Id;
Console.WriteLine("Search folder created.");
}
else
{
Console.WriteLine("Search folder already exist... deleting existing one...");
DeleteHiddenSearchFolder();
Console.WriteLine("Search folder deleted, creating new one...");
strSearchFolderID = CreateHiddenSearchFolder().FolderId.Id;
Console.WriteLine("Search folder created.");
}
Console.WriteLine("Search Folder ID: " + strSearchFolderID);
}
}
}
I talked about inside code, about Hidden Search Folder. You can make your search folders hidden but what could be the use of search folders if they are hidden? Users cannot see them so who will use them? Well that’s for later :)
Comments
Anonymous
February 23, 2009
PingBack from http://www.anith.com/?p=12900Anonymous
July 29, 2009
Hi I was trying to compile the code , but it always complains about using SearchFolderCreator.MyEWS; Can you send me the complete code and where do I get the reference library. Thanks Koomar kramessu@hotmail.comAnonymous
August 05, 2009
Add a web reference to Exchange Web Services to your project and change the SearchFolderCreator.MyEWS to that class , it should compile. Sorry I cannot provide the entire solution.