EWS API 2.1 Released

Download:

http://www.microsoft.com/en-us/download/details.aspx?id=42022

The EWS Managed API 2.1 package contains the EWS Managed API, a managed interface for developing client applications that use EWS. The EWS Managed API simplifies the implementation of applications that communicate with versions of Exchange starting with Exchange Server 2007 Service Pack 1 (SP1). Built on the EWS SOAP protocol and Autodiscover, the EWS Managed API provides a .NET interface to EWS that is easy to learn, use, and maintain.

For your convenience, the package also includes the Exchange Server 2013 token validation library. You can use the EWS Managed API and the library to build mail apps for Outlook that can be authenticated by the identity tokens issued by Exchange 2013. 

EWS API 1.2 Released

Good news, the Exchange Web Services Managed API 1.2.1 was released and it’s available for download

The EWS Managed API 1.2 introduces the following important changes that might affect your client applications:

Microsoft Exchange Server 2010 Service Pack 2 (SP2) is now the targeted version

  1. The following new functionality is exposed:
  2. Getting password expiration date
  3. Updates to the contact type
  4. Store entry identifiers returned on items
  5. Asynchronous notifications
  6. DateTime object precision values
Documentation

http://msdn.microsoft.com/en-us/library/dd633709(v=exchg.80).aspx

Download

http://www.microsoft.com/en-us/download/details.aspx?id=28952

How to get Exchange Online Folders

You can get all folders based in a criteria, this is useful because it can be queried by a SearchFilter. In this case I’m only get Folders that have at least 1 message because operator is SearchFilter.IsGreaterThan

 

SearchFilter searchFilter = new SearchFilter.IsGreaterThan
(FolderSchema.TotalCount, 0);
 
Unlike messages, in folders, you can use Deep Transversal’s, this means that you can get all Sub Folders on the fly.
 
 

view.Traversal = FolderTraversal.Deep;

 

As always you have to use an Object type of ExchangeService(), see the GetBinding() Method

 

Main Procedure

 

// Create a view with a page size of 10 or number you want.
FolderView view = new FolderView(10)

{
   
PropertySet = new PropertySet
     (BasePropertySet.IdOnly) { FolderSchema.DisplayName }
};

// Identify the properties to return in the results set.
// Return only folders that contain items.
SearchFilter searchFilter = new SearchFilter.IsGreaterThan

  (FolderSchema.TotalCount, 0);

// Unlike FindItem searches, folder searches can be deep traversals.
view.Traversal = FolderTraversal.Deep;

// Send the request to search the mailbox and get the results.
FindFoldersResults findFolderResults = service.FindFolders

  (WellKnownFolderName.Root, searchFilter, view);

// Process each item.
foreach (Folder myFolder in findFolderResults.Folders)

{
    // Go get myFolder.Id, MyFolder.DisplayName etc…
}

// Determine whether there are more folders to return.
if (findFolderResults.MoreAvailable)

{
   
// Make recursive calls with offsets set for the FolderView

    // to get the remaining folders in the result set for Paging.
}

EWS User Impersonation, advantages, why?

 

First off all I respect all points of views, this post is intend only to expose my opinion.

ACTIVATE IMPERSONATION FOR ADMINISTRATOR

First go to Roles & Management and then Discovery Management, Second, add a function ApplicationImpersonation, then add the Administrator User Name

image image

IMPERSONATION IN DETAIL

When you connect to exchange online, you must communicate with an Exchange Web Service within a mailbox user and a password, but if you are logged with a non Administrator user you may not have Full control over the Service. This may be true when you have Hybrid Systems, and in some procedures like CreateReply() or CreateForward() you may experience Access Denied Exceptions.

Another point is if you use the Administrator Credentials and Impersonate another Mailbox you don’t have to know that users credentials and this may be an advantage in all ways.

How can we do this?

Just use your service binding method, or get it here and impersonate the service like this

service.ImpersonatedUserId = new ImpersonatedUserId
   (ConnectingIdType.SmtpAddress, 
      "You non Admin MailBox");

What is the Service Binding in the Exchange Web Services Managed API

The Microsoft Exchange Web Services Managed API have 2 main classes, the FOLDER Class and the ITEM Class. All these 2 need a ServiceObject in order to communicate with a Exchange Web service.

Service Binding use the Autodiscover Object in order to get a Exchange Web Service endpoint URL, something like this https://SERVER.outlook.com/EWS/Exchange.asmx.

The Folder Class

image

The Item Class

image

You can see at the TOP of the hierarchy SERVICEOBJECT that is a type of ExchangeService() Object

So what next? let’s see in more detail, what Outlook do if you add a Microsoft Exchange Account?

image

In this case Outlook will try to resolve thru Autodiscover the domain in the E-mail Address field, and get the Endpoint for the Exchange Web Service, if the credentials are OK, all user configurations and Mail will be attached to Outlook

Service Binding do the same thing, the only difference is that you will assign properties values to a ExchangeService(), and assign user information’s like the Endpoint URL in order to you can use All Objects in the FOLDER and ITEM Class

Let’s see the Method here

Enjoy EWS!

Delete a Message or a List of Messages

You will need the GetBind() method in order to use this code

This method will delete a message based in a Message Unique ID and move it to deleted folders, you can change it for your needs

/// <summary>
/// Deletes the message.
/// </summary>
/// <param name="messId">The mess id.</param>
public static bool DeleteMessageByID(string messId)

{
   
Item mess = Item.Bind(GetBinding(), messId);
   
EmailMessage message = mess as EmailMessage;
   
if (message == null) return false;
   
message.Delete(DeleteMode.MoveToDeletedItems);
   
return true;
}
 

This method will delete a List of messages based in a Message Unique ID that you pass in the List<String> and move it to deleted folders, you can change it for your needs

/// <summary>
/// Deletes the message list.
/// </summary>
/// <param name="messId">The mess id.</param>
public static bool DeleteListOfMessagesByID<string> messId)

{
   
foreach (EmailMessage message in
       
messId.Select(messIdList => Item.Bind(GetBinding(), 
           
messIdList)).Select(mess => mess as EmailMessage))

   
{
       
if (message == null) return false;
       
message.Delete(DeleteMode.MoveToDeletedItems);
   
}
   
return true;
}

 

I you think this helped you, please take 10 second’s and respond to the question in the side bar, Thanks.

EWS Connect with SharePoint, Performance

For my experience using EWS with SharePoint I want to share some useful information.

When you connect to Exchange Online with SharePoint a big performance improvement is to write a console application in order to get your Service URL and pass it directly. But to do this SharePoint ask you for a certificate, the workaround is to pass a Dummy X509 CER, code bellow, comment if it help.

// <summary>
/// Gets the binding.
/// </summary>
/// <returns></returns>
public static ExchangeService GetBinding()

{
   
try
   
{
       
//Create Service
        ExchangeService service = new

           
ExchangeService(ExchangeVersion.Exchange2010_SP1);
       
//Assign Credentials
        service.Credentials = new

           
WebCredentials("admin@contoso.com", "password");
       
ServicePointManager.ServerCertificateValidationCallback +=
           
RemoteCertificateValidationHandler;
       
//Change this line by your EndPoint Url
        service.Url = new Uri("https://SERVER.outlook.com/EWS/Exchange.asmx");

       
return service;
   
}
   
catch (AutodiscoverRemoteException ex)
   
{
       
Console.WriteLine("Exception thrown: " + ex.Error.Message);
       
return null;
   
}
}

private static bool RemoteCertificateValidationHandler
   
(object sender, X509Certificate certificate,
   
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
   
return true; //ignore the checks and go ahead
}

Reply and Forward with full information

When you use message.Reply() or message.Forward() you are unable to add extra information, like recipients, attachments etc.., in order to workaround you must use the CraeteReply() and CreateForward() methods.

You will need the GetBind() method in order to use this code

REPLY

/// Replies the message. 
/// <param name="messId">The mess id.</param>
/// <param name="body">The body.</param>
/// <param name="replyAll">if set to <c>true</c> [reply all].</param>
/// <returns></returns>
private bool ReplyMessageCreate(string messId, string body, bool replyAll)

{
   
ExchangeService service = GetBinding();

    try
   
{
       
Item mess = Item.Bind(service, messId);
       
EmailMessage message = mess as EmailMessage;
       
if (message != null)
       
{
           
ResponseMessage reply = message.CreateReply(replyAll);
           
reply.BodyPrefix = body;

            EmailMessage replyMessage = reply.Save(WellKnownFolderName.Drafts);
           
foreach (string item in YourRecipients)
           
{
               
replyMessage.ToRecipients.Add(item);
           
}

            foreach (string item in YourRecipients)
           
{
               
replyMessage.CcRecipients.Add(item);
           
}

            foreach (string item in YourRecipients)
           
{
               
replyMessage.BccRecipients.Add(item);
           
}

            replyMessage.Attachments.AddFileAttachment(c:\att.txt);
        
           
replyMessage.Update(ConflictResolutionMode.AlwaysOverwrite);
           
replyMessage.SendAndSaveCopy();
       
}

        return true;
   
}

    catch (Exception)
   
{
       
return false;
   
}
}

FORWARD

// <summary>
/// Replies the message. 
/// <param name="messId">The mess id.</param>
/// <param name="body">The body.</param>        
/// <returns></returns>
private bool ForwardMessageCreate(string messId, string body)

{
   
ExchangeService service = Bind.GetBinding(Bind._ImpersonateUser);

    try
   
{
       
Item mess = Item.Bind(service, messId);
       
EmailMessage message = mess as EmailMessage;
       
if (message != null)
       
{
           
ResponseMessage forward = message.CreateForward();
           
forward.BodyPrefix = body;

            EmailMessage forwardMessage = forward.Save(WellKnownFolderName.Drafts);
           
foreach (string item in YourRecipients)
           
{
               
forwardMessage.ToRecipients.Add(item);
           
}

            foreach (string item in YourRecipients)
           
{
               
forwardMessage.CcRecipients.Add(item);
           
}

            foreach (string item in YourRecipients)
           
{
               
forwardMessage.BccRecipients.Add(item);
           
}

            forwardMessage.Attachments.AddFileAttachment(c:\att.txt);

            forwardMessage.Update(ConflictResolutionMode.AlwaysOverwrite);
           
forwardMessage.SendAndSaveCopy();
       
}

        return true;
   
}

    catch (Exception)
   
{

        return false;
   
}
}