EWS API: Anything I call update_item for a meeting, it ends up canceling the meeting for any attendees - exchangewebservices

I'm using the EWS API (targeting Exchange 2010) I cannot figure out why anything I make a request to update a calendar meeting/item. Is there something I'm missing or is this the expected behavior? I'm able to make a change from Outlook to the meeting without it sending out a cancellation email to all attendees except the organizer.
The below is a sample of the relevant portion of the SOAP request. I replaced the actual attendee's email addresses, item ID and change key.
{:send_meeting_invitations_or_cancellations=>"SendOnlyToChanged",:conflict_resolution=>"AutoResolve", :item_changes=>[{:updates=>[{:set_item_field=>{:field_uRI=>{:field_uRI=>"item:Subject"},
:calendar_item=>{:sub_elements=>[{:subject=>{:text=>"Thursday 11AM Recurring"}}]}}},
{:set_item_field=>{:field_uRI=>{:field_uRI=>"item:Body"}, :calendar_item=>{:sub_elements=>[{:body=>{"BodyType"=>"HTML", :text=>"HI"}}]}}},
{:set_item_field=>{:field_uRI=>{:field_uRI=>"calendar:Location"},:calendar_item=>{:sub_elements=>[{:location=>{:text=>"LA, CA"}}]}}},
{:set_item_field=>{:field_uRI=>{:field_uRI=>"calendar:Start"}, :calendar_item=>{:sub_elements=>[{:start=>{:text=>"2019-03-07T19:00:00.0000000"}}]}}},
{:set_item_field=>{:field_uRI=>{:field_uRI=>"calendar:StartTimeZone"}, :calendar_item=>{:sub_elements=>[{:start_time_zone=>{"Id"=>"UTC"}}]}}},
{:set_item_field=>{:field_uRI=>{:field_uRI=>"calendar:End"}, :calendar_item=>{:sub_elements=>[{:end=>{:text=>"2019-03-07T19:30:00.0000000"}}]}}},
{:set_item_field=>{:field_uRI=>{:field_uRI=>"calendar:EndTimeZone"},:calendar_item=>{:sub_elements=>[{:end_time_zone=>{"Id"=>"UTC"}}]}}},
{:set_item_field=>{:field_uRI=>{:field_uRI=>"calendar:RequiredAttendees"},:calendar_item=>{:sub_elements=>[{:required_attendees=>{:sub_elements=>[
{:mailbox=>{:name=>"Joe ABC",:email_address=>"joe#abc.com", :routing_Type=>"SMTP"}},
{:mailbox=>{:name=>"John ABC", :email_address=>"john#abc.com",:routing_Type=>"SMTP"}}]}}]}}}],
:item_id=>{:id=>"AAMkAGJjNWIzNzI2LTM1N2YtNDVkMi05NzU5LTRj",
:change_key=>"DwAAABYAAADWK9s0Y5iSSLP"}}]}

If you use Set_Item_Field to update the required attendees this will overwrite the current property so if any attendees aren't in the updated collection your effectively canceling the meeting for those attendees. If you want to use Set_Item_Field to update attendees then you need to include all the attendees for that type because your replacing the collection for the recipient type not appending to it.

Related

How do I construct a link to a Google Calendar event?

If I have the event ID of a Google Calendar event, for example:
4htgpmm1hmak744r0kbkdcodar#google.com
How can I construct a URL to view the event details in the Google Calendar interface?
For example, if I go to a google calendar event, I see a URL such as this:
https://calendar.google.com/calendar/r/eventedit/NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw
What function/algorithm can I run to go from 4htgpmm1hmak744r0kbkdcodar#google.com to NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw?
Bonus: A bonus would be if there was also a shortcut method that worked on a CalendarEvent via Google Apps Script. For example, if there was a method such as getUrl() just like there is a getId() method.
Since the same event can exist in multiple calendars (e.g. by inviting others to it), the event id is not sufficient information.
To construct a URL you need both the event id (refresher for how find it), AND the Calendar ID (see below for instructions as to how to find it). You'll then need to encode both as base64, and finally you'll you have a valid Google Calendar event link.
For the following instructions, imagine we have an event, Event1, and it exists in both calendars, CalendarA and CalendarB.
In the Google Calendar interface, you would be able to view any of these combinations:
Event1 in CalendarA
Event1 in CalendarB
Let's assign the following IDs:
Event1 ID: 4htgpmm1hmak744r0kbkdcodar#google.com
CalendarA ID: eugu9kan1ddi1pmi6sk3ib56g#group.calendar.google.com
CalendarB ID: afd3zeuguoepmi32s5i56g#group.calendar.google.com
To construct an event URL:
Get the event-id, which is the event id without the #google.com
E.g. for Event1 we have 4htgpmm1hmak744r0kbkdcodar
Get the calendar-id, which is the calendar id with the #group.calendar.google.com replaced with #g
E.g. for CalendarA we have eugu9kan1ddi1pmi6sk3ib56g#g
Join the two values with a space in the middle.
<event-id> <calendar-id>
E.g. for Event1 + CalendarA, we have:
4htgpmm1hmak744r0kbkdcodar eugu9kan1ddi1pmi6sk3ib56g#g
Encode the value as base64 (e.g. on https://www.base64decode.org):
NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw==
Remove the training ==:
NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw
You can now append this value to https://www.google.com/calendar/event?eid= (view event page) or https://calendar.google.com/calendar/r/eventedit/ (edit event page):
https://www.google.com/calendar/event?eid=NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw
or
https://calendar.google.com/calendar/r/eventedit/NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw
You're done! That URL will take you to the calendar event in the Google interface.
How to find the calendar ID
If you need instructions for how to find the calendar id...
To find the calendar ID:
Go to the calendar settings
Scroll down until you find the calendar id field.
This might be a value that ends with #group.calendar.google.com, your email address, or some other value.
If you are having trouble finding the calendar id, another tool that might help is adding the eventdeb=1 parameter to the URL, going to the Troubleshooting info of an event, and then looking for either the organizer or participant values, both of which contain calendar ids.
In Apps Script
var eventUrl = "https://www.google.com/calendar/event?eid=" +
Utilities.base64Encode(event.getId().split('#')[0] +
" " +
event.getOriginalCalendarId())
.replace(/\=/g, '');
#Senseful had was a super helpful answer, and it works!
A few important things to note adding to the above. Firstly, when base64 encoding, you'll end up with a == at the end, remove that
Second, the base calendar URL will not work when the calendar the event belongs to does not belong in the primary account the user is logged in with. For example, if you're logged into 3 accounts, you'll have a different URL for each one e.g.
https://calendar.google.com/calendar/r/...
https://calendar.google.com/calendar/b/2/r/...
https://calendar.google.com/calendar/b/3/r/...
and so on... I don't think there's a solution that'll help with this situation since it's impossible to predict what accounts a specific user is logged into at any time.

Cant update exchange appointment in EWS

Im using EWS to update exchange appointments but sometimes I can't update them after they are created. I'm receiving:
"At least one recipient isn't valid., A message can't be sent because it contains no recipients."
The code is essentially:
Appointment appointment = getAppointment();
... set some properties
appointment.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToNone);
Isn't that supposed to work? Beforehand I didn't use the SendInvitationsOrCancellationsMode.SendToNone enum, but even with that I get the same exception.
It's never a problem to create the appointment, it's always the updates that we are having problems with.
For the sake of the log, I send a solution here. I managed to solve it with a workaround. It accepts it if I add a new item to the OptionalAttendees collection, when it is empty. Since I add the SendInvitationsOrCancellationsMode.SendToNone flag, it will send nothing, but finally accepts it without an exception.
if (EWSItem.OptionalAttendees.Count == 0)
EWSItem.OptionalAttendees.Add("me#me.com");
EWSItem.Update(ConflictResolutionMode.AlwaysOverwrite,
SendInvitationsOrCancellationsMode.SendToNone);

Office 365 Rest API - Changing message Id

Is there any scenario in which the Id field on a message could change?
We received a message at today (Thu, 19 Feb 2015 10:29:48 GMT +00:00) with an ID ending in 'MT80AAA='. However when trying to retrieve message details at a later time I get a 404 error with the message:
{ "error" : { "code": "ErrorItemNotFound", "message" : "The specified object was not found in the store." } }
When I do another request to get all messages from that inbox the same message appears however it has another ID ending in 'TwDlAAA='.
Both the message ID and the Attachment ID have been changed at some point from the first time receiving the message and now.
Is this a common occurrence? What could cause this? Or is it a bug?
It's not a bug, it's definitely a common occurrence with Exchange. Entry ID's aren't static, and can change in a number of scenarios. Common ones are moving the item (which is essentially a copy and delete operation, copy gets a new ID since it's a new item), or mailbox move (which may be applicable to your case).
Typically I would advise a strategy of optimistically storing the ID and using it first, since it will usually work. Then I'd recommend storing the record key and search key as a backup, so you could try searching for the item in the event the Id no longer works. However, the REST API doesn't expose these fields! So you'd have to make do with searching for the item based on whatever fields are important to you, which isn't ideal. I'll provide this feedback to our developers.

Invitations on Trello API

What is the JSON structure for an invitation, and under what circumstances is one returned. For example,
GET /1/boards/5144051cbd0da6681200201e/invitations?key=[myKey]
always returns an empty array, even after I invite a fake email.
That route no longer returns anything (and should probably be marked deprecated).
Instead of invitation objects, we add a member to the board representing the invited person (where member.memberType = "ghost") so that you can interact with that person (mention in comments, add to cards) before they join Trello. If you invited that person, you will be able to see the 'ghost' member's email address.

Exchange EWS Calendar AppointmentState

I am using EWS against Exchange 2010 SP1.
I am trying to retrieve a list of appointments that have been neither accepted or declined. I thought AppointmentState may be the field i was looking for, but this does not seem to be the correct field (see links), does anyone know where i can find if a appointment has been accepted or declined?
AppointmentState
[http://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.appointment_members(v=exchg.80).aspx]
AppointmentState Definition
[http://msdn.microsoft.com/en-us/library/aa564700(v=exchg.140).aspx]
after further research it appears that this is not the field you need to look at. the RequiredAttendee sand OptionalAttendees collections is where it's at, as detailed here:
EWS-manged: Fetch required and optional attendees of appointments
You can check whether the appointment was accepted or declined in the MyResponseType poperty.
This will have one of the following values:
Unknown - Response status is unknown
Organizer - The item owner is the meeting organizer
Tentative - The item owner accepted tentatively
Accept - The item owner accepted
Decline - The item owner declined
NoResponseReceived - The item owner did not yet respond to the invitation
The values are explained a little better in the documentation of the property in the EWS managed API documentation.