Blog - Title

January, 2009

Brijs Blogging... Looking Beyond the Obvious

  • Brijs Blogging... Looking Beyond the Obvious

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

    • 1 Comments

    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
                //http://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();
                    }
                }
            }
        }
    }
      

    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:

    EWS Rocks!

  • Brijs Blogging... Looking Beyond the Obvious

    How to read Internet Headers using WebDAV

    • 0 Comments

    We can get Internet Headers/Message Headers via WebDAV using PR_TRANSPORT_MESSAGE_HEADERS MAPI property.

    PidTagTransportMessageHeaders Canonical Property

    http://msdn.microsoft.com/en-us/library/cc815628.aspx

    PR_TRANSPORT_MESSAGE_HEADERS
    http://schemas.microsoft.com/mapi/proptag/0x007D001F

     

    Here is VBScript sample with WebDAV PROPFIND 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.
     
    Dim objX, strR, strRes
    Set objX = CreateObject("Microsoft.XMLHTTP")
    'Change Item URL, Domain, User, Password
    objX.Open "PROPFIND", "http://server/exchange/user/Inbox/Item123.EML", FALSE, "Domain\User", "Password"
    strR = "<?xml version='1.0'?>"
    strR = strR & "<d:propfind xmlns:d='DAV:' xmlns:m='urn:schemas:mailheader:' "
    strR = strR & "xmlns:e='http://schemas.microsoft.com/exchange/' xmlns:p='http://schemas.microsoft.com/mapi/proptag/'> "
    strR = strR & "<d:prop><d:displayname/><p:0x007D001f/></d:prop></d:propfind>"
     
    objX.SetRequestHeader "Content-type:", "text/xml"
    objX.SetRequestHeader "Depth", "1"
    objx.SetRequestHeader "translate", "f"
    objX.send(strR)
     
    strRes = objX.responseText
    Msgbox strRes

     

    And following is sample WebDAV SELECT request.

    <?xml version="1.0"?>
    <D:searchrequest xmlns:D = "DAV:">
    <D:sql>SELECT "urn:schemas:mailheader:to", http://schemas.microsoft.com/mapi/proptag/0x007D001F, "urn:schemas:httpmail:subject" FROM "/exchange/user/Inbox/" 
    WHERE "DAV:ishidden" = false AND "DAV:isfolder" = false</D:sql>
    </D:searchrequest>

     

    Please also refer the article mentioned below related to supportability of working with MAPI properties

    The Support Guidelines for Client-Side Messaging Development
    http://support.microsoft.com/kb/266353
    Refer Section: Integrating with Outlook properties

  • Brijs Blogging... Looking Beyond the Obvious

    MAPI documentation got Revamped

    • 1 Comments

    If you are developer working on MAPI then here is the news:

    MAPI documentation is revamped and republished on MSDN  

    Welcome to the Outlook 2007 MAPI Reference
    http://msdn.microsoft.com/en-us/library/cc765775.aspx

    Angela also talked about it @ http://blogs.msdn.com/officedevdocs/archive/2009/01/20/where-is-the-mapi-documentation.aspx

    For what is new and what has changed visit:

    What's New in This Edition
    http://msdn.microsoft.com/en-us/library/cc963762.aspx 

    And if you are looking for sample code related to MAPI then there is no better sample available than MFCMAPI.

    MFCMAPI as a Code Sample
    http://msdn.microsoft.com/en-us/library/cc998258.aspx

    Also don't get confused with "MAPI Canonical Properties" http://msdn.microsoft.com/en-us/library/cc979184.aspx

    Because canonical properties are not real properties and are not defined in MAPI header files, you should NOT use canonical property names in code; instead, you should continue to use the exact MAPI property names in code.

    Now, there are now close to 900 properties documented, including tagged properties and named properties. So let's explore...

Page 1 of 1 (3 items)