How to delete an attendee from Meeting Request using Exchange Web Services?

In order to remove attendees from an attendee collection, we have to call the UpdateItem Web method for the meeting with the SetItemField change description to include all current members of the attendee array minus those you want removed.

Please refer to the sample code below which demonstrates:

  • CreateItem (How to create a meeting request)
  • GetItem (How to perform GetItem with additional properties)
  • UpdateItem (How to delete an attendee from the Meeting Request)

NOTE: Following programming examples is for illustration only, without warranty either expressed or implied, including, but not limited to, the implied warranties of merchantability and/or fitness for a particular purpose. This sample code assumes that you are familiar with the programming language being demonstrated and the tools used
to create and debug procedures.

 using System;
 using System.Linq;
 using System.Text;
 using System.Net;
 using System.Net.Security;
 using EWSDeleteAnMeetingAttendee.EWSMsgEX07;
 using System.Security.Cryptography.X509Certificates;
  
 namespace EWSDeleteAnMeetingAttendee
 {
     class DeleteAttendee
     {
         private static ExchangeServiceBinding binding = null;
         private static string itemID = "";
         private static string email = "user@domain.com";
  
         static void Main(string[] args)
         {
             // Setup the binding with credentials and URL.
             DeleteAttendee prg = new DeleteAttendee();
  
             binding = new ExchangeServiceBinding();
             //Update UserName, Password, Domain, EWS URL
             binding.Credentials = new NetworkCredential("User", "Password", "domain.com");
             binding.Url = @"https://Server/EWS/Exchange.asmx";
  
             System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate(Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
             {
                 // Replace this line with code to validate server certificate.
                 return true;
             };
  
             prg.CreateMeetingRequest();
             prg.DeleteMeetingAttendee(email);
         }
  
         public void CreateMeetingRequest()
         {
             //Migrating to Exchange Web Services, Part 2: Calendaring
             //https://msdn.microsoft.com/en-us/library/cc788131.aspx
             // Create the appointment.
             CalendarItemType appointment = new CalendarItemType();
  
             // Set the properties of the appointment.
             appointment.Start = new DateTime(2009, 01, 29, 8, 30, 0, DateTimeKind.Unspecified);
             appointment.StartSpecified = true;
             appointment.End = new DateTime(2009, 01, 29, 9, 30, 0, DateTimeKind.Unspecified);
             appointment.EndSpecified = true;
             appointment.Subject = "New Planning meeting";
             appointment.Location = "Building 007";
             appointment.Body = new BodyType();
             appointment.Body.BodyType1 = BodyTypeType.Text;
             appointment.Body.Value = "This is a Meeting Invite for discussion";
  
             // Add required attendees.
             appointment.RequiredAttendees = new AttendeeType[2];
             appointment.RequiredAttendees[0] = new AttendeeType();
             appointment.RequiredAttendees[0].Mailbox = new EmailAddressType();
             appointment.RequiredAttendees[0].Mailbox.EmailAddress = "User1@domain.com";
  
             appointment.RequiredAttendees[1] = new AttendeeType();
             appointment.RequiredAttendees[1].Mailbox = new EmailAddressType();
             appointment.RequiredAttendees[1].Mailbox.EmailAddress = "User2@domain.com";
  
             // Create the array of items that will contain the appointment.
             NonEmptyArrayOfAllItemsType arrayOfItems = new NonEmptyArrayOfAllItemsType();
             arrayOfItems.Items = new ItemType[1];
  
             // Add the appointment to the array of items.
             arrayOfItems.Items[0] = appointment;
  
             // Create the CreateItem request.
             CreateItemType createRequest = new CreateItemType();
  
             // The SendMeetingInvitations attribute is required for calendar items.
             createRequest.SendMeetingInvitations = CalendarItemCreateOrDeleteOperationType.SendToAllAndSaveCopy;
             createRequest.SendMeetingInvitationsSpecified = true;
  
             // Add the destination folder to the CreateItem request.
             DistinguishedFolderIdType folder = new DistinguishedFolderIdType();
             folder = new DistinguishedFolderIdType();
             folder.Id = DistinguishedFolderIdNameType.calendar;       
             createRequest.SavedItemFolderId = new TargetFolderIdType();
             createRequest.SavedItemFolderId.Item = folder ;
             
             // Add the items to the CreateItem request.
             createRequest.Items = arrayOfItems;
  
             // Create the appointment by calling the CreateItem method, which has
             // the side effect of sending invitations to attendees.
             CreateItemResponseType createResponse = binding.CreateItem(createRequest);
  
             // Check the result.
             if (createResponse.ResponseMessages.Items[0].ResponseClass !=  ResponseClassType.Success)
             {
                 throw new Exception("Create Meeting failed.");
             }
             
             ItemInfoResponseMessageType iirmt = ((ItemInfoResponseMessageType)createResponse.ResponseMessages.Items[0]);
             if (iirmt.ResponseClass == ResponseClassType.Success)
             {
                 ItemType it = (ItemType)iirmt.Items.Items[0];
                 itemID = it.ItemId.Id;
             }
         }
  
         static CalendarItemType  GetCalItem(string itemIDCal)
         {
             // Create the request.
             GetItemType request = new GetItemType();
  
             // Create the response shape.
             ItemResponseShapeType responseShape = new ItemResponseShapeType();
             responseShape.BodyType = BodyTypeResponseType.Text;
             responseShape.BodyTypeSpecified = true;
             responseShape.BaseShape = DefaultShapeNamesType.Default;
             // Add more properties to the request.
  
             PathToUnindexedFieldType[] attendees = new PathToUnindexedFieldType[1];
             attendees[0] = new PathToUnindexedFieldType();
             attendees[0].FieldURI = UnindexedFieldURIType.calendarRequiredAttendees;
             responseShape.AdditionalProperties = attendees;
                  
             // Add the response shape to the request.
             request.ItemShape = responseShape;
             
             // Identify the items to get.
             ItemIdType[] items = new ItemIdType[1];
             items[0] = new ItemIdType();
             items[0].Id = itemIDCal;
                        
             // Add items to the request.
             request.ItemIds = items;
  
             try
             {
                 // Send the request and get the response.
                 GetItemResponseType resp = binding.GetItem(request);
                 ArrayOfResponseMessagesType aormt = resp.ResponseMessages;
                 ResponseMessageType[] rmta = aormt.Items;
  
                 foreach (ResponseMessageType rmt in rmta)
                 {
                     ItemInfoResponseMessageType iirmt = (rmt as ItemInfoResponseMessageType);
                     ArrayOfRealItemsType aorit = iirmt.Items;
                     ItemType[] myItems = aorit.Items;
                     
                     if (myItems[0] is CalendarItemType)
                     {
                         CalendarItemType calendar = (myItems[0] as CalendarItemType);
                         return calendar;
                     }
                     else
                     {
                         // Check for other item types.
                         return null;
                     }
                 }
                 return null;
             }
             catch (Exception e)
             {
                 throw new Exception("GetItem failed");
             }
         }
  
         public void DeleteMeetingAttendee(string email)
         {
             CalendarItemType cal = GetCalItem(itemID); 
             CalendarItemType newcalendar = new CalendarItemType();
             newcalendar.RequiredAttendees = new AttendeeType[2];
             Int32 oi = 0;
             foreach (AttendeeType oattendee in cal.RequiredAttendees)
             {
                 if (oattendee.Mailbox.EmailAddress != email)
                 {
                     newcalendar.RequiredAttendees[oi] = new AttendeeType();
                     newcalendar.RequiredAttendees[oi].Mailbox = new EmailAddressType();
                     newcalendar.RequiredAttendees[oi].Mailbox.EmailAddress = oattendee.Mailbox.EmailAddress;
                     oi++;
                 }
             }
  
             // Create calendar items to contain each non-deletion update.
             // Add the calendar item and the identified set field to
             // the ItemChangeDescriptionType. This is a SetItemFieldType.
  
             PathToUnindexedFieldType att = new PathToUnindexedFieldType();
             att.FieldURI = UnindexedFieldURIType.calendarRequiredAttendees;
             
             SetItemFieldType set = new SetItemFieldType();
             set.Item = att;
             set.Item1 = newcalendar;
                        
             // Create the identifier of the item to update.
             ItemIdType itemId = new ItemIdType();
             itemId.Id = cal.ItemId.Id ;
             itemId.ChangeKey = cal.ItemId.ChangeKey  ;
  
             // Create and populate the request.
             UpdateItemType request = new UpdateItemType();
             request.ItemChanges = new ItemChangeType[1] { new ItemChangeType() };
             request.ItemChanges[0].Item = itemId;
             request.ItemChanges[0].Updates = new ItemChangeDescriptionType[1];
             request.ItemChanges[0].Updates[0] = set;
             
             request.ConflictResolution = ConflictResolutionType.AutoResolve;
             request.SendMeetingInvitationsOrCancellations = CalendarItemUpdateOperationType.SendToAllAndSaveCopy;
             request.SendMeetingInvitationsOrCancellationsSpecified = true;
  
             // Send the update request and receive the response.
             UpdateItemResponseType response = binding.UpdateItem(request);
             ArrayOfResponseMessagesType aormt = response.ResponseMessages;
             ResponseMessageType[] rmta = aormt.Items;
  
             foreach (ResponseMessageType rmt in rmta)
             {
                 ItemInfoResponseMessageType respMsg = (rmt as ItemInfoResponseMessageType);
                 foreach (ItemType item in respMsg.Items.Items)
                 {
                     Console.WriteLine("Item ID: " + item.ItemId.Id);
                     Console.WriteLine("New change key: " + item.ItemId.ChangeKey);
                     Console.ReadLine();
                 }
             }
         }
     }
 }
   .csharpcode, .csharpcode pre
{
  font-size: small;
   color: black;
   font-family: consolas, "Courier New", courier, monospace;
   background-color: #ffffff;
  /*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
   background-color: #f4f4f4;
  width: 100%;
    margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Remember, If we try to use a DeleteItemField change description, we would remove all attendees from the collection. Any attendee who is removed from an attendee list as the result of an update will be sent a meeting cancellation (unless the SendMeetingInvitationsOrCancellations value was set to "SendToNone" ).

Any attendee who has been removed from all attendee collections, but has not been sent a meeting cancellation, will still have a copy of the meeting on his calendar. The removed attendee may still register a response even after being removed from the attendee list. If that happens, the removed attendee will be re-added to the optional attendees collection on the meeting in the organizer's calendar.

Best Practices
As a general rule, we recommend you not to use the combination of a ConflictResolution value of 'AlwaysOverwrite' and a SendMeetingInvitationsOrCancellations value of 'SendToNone' in your calls to the UpdateItem Web method. The combination of these values will result in any removed attendees not receiving a meeting message indicating they have been removed.

I also recommend you to refer to the following articles:

-
Best Practices for Using Exchange Web Services for Calendaring Tasks
https://msdn.microsoft.com/en-us/library/bb738399.aspx

EWS Rocks!