Appointment.Save and Appointment.Update always set IsMeeting to true - c#

I want to create appointments, not meetings:
Appointment app = new Appointment(ews);
app.Start = DateTime.Now;
app.End = DateTime.Now.AddMinutes(60);
app.Subject = "My Subject";
app.Save();
string unid = app.Id.UniqueId;
// here the unid is given to the client, that may make another call leading to:
ItemId iid = new ItemId(unid);
app = Appointment.Bind(ews, iid, calendarFullEntryProperties);
return app.IsMeeting; // Will return true, although I never added any participants.
Why is that? Did I overlook anything in the docs?

EWS uses the same object type for meetings and appointments. The default behavior when you Save() or Update() an appointment is to send meeting invitations even if you haven't invited anyone. This essentially sets the IsMeeting to true. To save this as an appointment, change your line of code for saving to this:
app.Save(SendInvitationsMode.SendToNone);
This will keep invitations from being sent and keep IsMeeting set to false.

Related

Can't create an impersonated appoinement in C#

I'm trying to create a program that allows me to add multiple appointments/events to multiple users (without using a shared calendar).
The problem arrives when I try to impersonate someone (I'm admin so I think that I don’t have "rights" problems), I get an error System.NullReferenceException : 'Object reference not set to an instance of an object.' when the appoinment is saved (not when the impersonation is created, I don't understand why)
I don’t know what object I have to instantiate
If I don’t impersonate, the code works. The appointment is created
try
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.UseDefaultCredentials = true;
service.Credentials = new WebCredentials(userEmail, userPassword);
service.Url = new Uri("https://outlook.office365.com/ews/exchange.asmx");
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, destEmail);
//service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, myEmail);
Appointment appointment = new Appointment(service);
// Set the properties on the appointment object to create the appointment.
appointment.Subject = subject;
appointment.Body = "Test Event";
appointment.Start = DateTime.Now.AddDays(2);
appointment.End = appointment.Start.AddHours(1);
appointment.Location = "Here";
appointment.ReminderDueBy = DateTime.Now;
// Save the appointment to your calendar.
appointment.Save();
// Verify that the appointment was created by using the appointment's item ID.
Item item = Item.Bind(service, appointment.Id, new PropertySet(ItemSchema.Subject));
Console.WriteLine("Appoinement created");
}
catch (Exception ex)
{
Console.WriteLine("The following error occurred: " + ex.Message);
}
Error when I try to save the appoinement
-------------------- Update 02.07.2021
Thanks for the remarks.
I removed service.UseDefaultCredentials = true, that's dummy if a set new credentials in the next line.
The Appointment class is the default Microsoft.Exchange.WebServices.Data.Appointment, i didnt change anything there.
IT WAS a security/rights problem. Eventhough I'm admin, admins doesn't have Impersonnation ritghs by default.
The thing is that I added to myself the impersonation rights needed, and it worked. Thanks
It worked for a while. It stopped working without reason, i didnt change anything.
So I waited a few hours, tryed again, still didnt work and then I re-added the rights, and it works again.
Thanks you very much for the comments/hints

Is it possible to directly open the Outlook meeting window?

I am trying to have my application to open the Outlook meeting window with some pre-populated fields.
I have found that this question was already asked here.
However, the code provided in the answer(which works fine) doesn't open the meeting window but the appointement window. Those are two different things that are handled differently in Outlook and what I need is indeed the meeting window.
Is there any way to achieve this or do I absolutely have to open the appointement window first and then invite people to turn it into a meeting?
Create an appointment just as in the other question, but then set the MeetingStatus property of the appointment.
Microsoft.Office.Interop.Outlook.Application outlookApplication = new Microsoft.Office.Interop.Outlook.Application(); ;
Microsoft.Office.Interop.Outlook.AppointmentItem appointmentItem = (Microsoft.Office.Interop.Outlook.AppointmentItem)outlookApplication.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olAppointmentItem);
// This line was added
appointmentItem.MeetingStatus = Microsoft.Office.Interop.Outlook.OlMeetingStatus.olMeeting;
appointmentItem.Subject = "Meeting Subject";
appointmentItem.Body = "The body of the meeting";
appointmentItem.Location = "Room #1";
appointmentItem.Start = DateTime.Now;
appointmentItem.Recipients.Add("test#test.com");
appointmentItem.End = DateTime.Now.AddHours(1);
appointmentItem.ReminderSet = true;
appointmentItem.ReminderMinutesBeforeStart = 15;
appointmentItem.Importance = Microsoft.Office.Interop.Outlook.OlImportance.olImportanceHigh;
appointmentItem.BusyStatus = Microsoft.Office.Interop.Outlook.OlBusyStatus.olBusy;
appointmentItem.Recipients.ResolveAll();
appointmentItem.Display(true);
One more note to NineBerries good solution, because I had an issue here:
The line
appointmentItem.Recipients.ResolveAll();
is necessary if you have optional attendees in the meeting.
Otherwise they will be reset to "required" even if you set
recipient.Type = Microsoft.Office.Interop.Outlook.OlMeetingRecipientType.olOptional;
before, which is due to "late auto-resolving" of names in Outlook (or so it seems).

Create appointment with custom properties in EWS

I try to add a custom property to created appointments like this:
var newEvent = new Appointment(service)
{
Start = start,
End = end,
Subject = subject,
ReminderMinutesBeforeStart = 15
};
var extendendProperty = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Address, "organizer",
MapiPropertyType.String);
newEvent.SetExtendedProperty(extendendProperty, organizer);
but problem is that when I try get this appointment from server, property ExtendedProperty is empty.
In addition I create new appointment and add 'room' as a required attendee, and when I try get this appointment, I don't get it from my calendar but from room calendar.
So, I want to add extend property to my appointment and invite 'room'. Next get all appointments of the room and here I want read this property. It is even possible?
I read this topic: EWS Create Appointment in exchange with extra custom properties and as I understand I'll must have access to ExtendendPropertyDefinition when I want read this property, and must known id of this appointment before. Now I download all appointments from outlook by this code:
var folderId = new FolderId(WellKnownFolderName.Calendar, new Mailbox(userName));
var calendar = CalendarFolder.Bind(service, folderId, new PropertySet());
return calendar.FindAppointments(new CalendarView(start, stop)).ToList();
EDIT
Thanks Glen Scales!
It almost works as I want, but one thing. I can read this additional property if I download my own appointments, but in that code I download appointments from room calendar.
As I suppose when creating new appointment and add room as required attendant, it create his own appointment and this additional property isn't copied.
So is any way to get this additional property from room appointment, when I add this property to my?
You need to first Create a property set, add the extended property you want to load to that property set. Then tell EWS you want that property returned when you execute the FindAppointment method see https://msdn.microsoft.com/en-us/library/office/dd633697(v=exchg.80).aspx eg in your example
PropertySet YourProperyset = new PropertySet(BasePropertySet.FirstClassProperties);
var extendendProperty = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Address, "organizer",MapiPropertyType.String);
YourProperyset.Add(extendendProperty);
var folderId = new FolderId(WellKnownFolderName.Calendar, new Mailbox(userName));
var calendar = CalendarFolder.Bind(service, folderId);
var calendarView = new CalendarView(start, stop);
calendarView.PropertySet = YourProperyset;
return calendar.FindAppointments(calendarView).ToList();

Unable to fetch built in properties of email along with the extended property

I am working with Exchange Web Services Managed API. I am adding a single extended property to mail items in inbox as they get processed based on some condition. Thus, not all mails will get this extended property attached to them.
Next I am refetching all mails in inbox and if they have this property attached to them, I process them again.
Below is the simple method getAllMailsInInbox(), I have written to refetch the mails in inbox:
class MyClass
{
private static Guid isProcessedPropertySetId;
private static ExtendedPropertyDefinition isProcessedPropertyDefinition = null;
static MyClass()
{
isProcessedPropertySetId = new Guid("{20F3C09F-7CAD-44c6-BDBF-8FCB324244}");
isProcessedPropertyDefinition = new ExtendedPropertyDefinition(isProcessedPropertySetId, "IsItemProcessed", MapiPropertyType.String);
}
public List<EmailMessage> getAllMailsInInbox()
{
List<EmailMessage> emails = new List<EmailMessage>();
ItemView itemView = new ItemView(100, 0);
FindItemsResults<Item> itemResults = null;
PropertySet psPropSet = new PropertySet(BasePropertySet.IdOnly);
itemView.PropertySet = psPropSet;
PropertySet itItemPropSet = new PropertySet(BasePropertySet.IdOnly,
ItemSchema.Attachments,
ItemSchema.Subject,
ItemSchema.Importance,
ItemSchema.DateTimeReceived,
ItemSchema.DateTimeSent,
ItemSchema.ItemClass,
ItemSchema.Size,
ItemSchema.Sensitivity,
EmailMessageSchema.From,
EmailMessageSchema.CcRecipients,
EmailMessageSchema.ToRecipients,
EmailMessageSchema.InternetMessageId,
ItemSchema.MimeContent,
isProcessedPropertyDefinition); //***
itemResults = service.FindItems(WellKnownFolderName.Inbox, itemView);
service.LoadPropertiesForItems(itemResults.Items, itItemPropSet);
String subject = itItem.Subject; //Exception: "You must load or assign this property before you can read its value."
//....
}
}
As you can see, on call service.LoadPropertiesForItems(), it does not load any properties, thus resulting in You must load or assign this property before you can read its value. exception while accessing any of those properties.
If I remove isProcessedPropertyDefinition from the itItemPropSet property set, it fetches all the properties properly.
So can I just know how can I fetch all built in EmailMessage properties along with the extended property?
Your GUID is two digits too short after the last dash. Strange that you're not seeing a FormatException. Still, you should update your code to inspect the GetItemResponse for each item. That way if some error occurs on one item, your code can be aware of it. That means you'll need to make another collection to return.
Update your code with this:
ServiceResponseCollection<ServiceResponse> responses = service.LoadPropertiesForItems(itemResults.Items, itItemPropSet);
foreach (ServiceResponse response in responses)
{
if (response.Result == ServiceResult.Error)
{
// Handle the error associated
}
else
{
String subject = (response as GetItemResponse).Item.Subject;
}
}
Instead of doing
service.LoadPropertiesForItems(itemResults.Items, itItemPropSet);
Try doing
itemResult.LoadPropertiesForItems(itItemPropSet);
Casue once you have the item, you can load the extended property of the item by loading the specific one.

RemoveExtendedProperty throws error when used on an occurrence of a recurring appointment

I am developing an application that syncs an exchange calendar to another calendar. I put extended properties on the exchange appointments in order to preserve the mapping between appointments in the two calendars. Everything is working fine until I try to remove an extended property from an occurrence of a recurring appointment. When I try doing this, I get the error:
The delete action is not supported for this property.
Here is a code snippet that demonstrates the error:
public void ExchangeTest()
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1)
{
Credentials = new NetworkCredential("username", "password", "domain")
};
service.AutodiscoverUrl("username#domain.com");
Appointment appt = new Appointment(service)
{
Recurrence = new Recurrence.DailyPattern(DateTime.Now, 2) { NumberOfOccurrences = 3},
Start = DateTime.Now,
End = DateTime.Now.AddHours(2),
Subject = "Test Appointment"
};
NameResolutionCollection resolutionCollection = service.ResolveName("username", ResolveNameSearchLocation.DirectoryOnly, false);
string mailboxAddress = resolutionCollection.First().Mailbox.Address;
FolderId folderId = new FolderId(WellKnownFolderName.Calendar, mailboxAddress);
appt.Save(folderId);
PropertySet properties = new PropertySet(AppointmentSchema.ICalUid);
appt.Load(properties);
CalendarView view = new CalendarView(DateTime.Today, DateTime.Today.AddDays(8)){PropertySet = properties};
IEnumerable<Appointment> occurrences = service.FindAppointments(folderId, view)
.Where(a => a.ICalUid == appt.ICalUid);
ExtendedPropertyDefinition definition = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "TestProperty", MapiPropertyType.String);
Appointment firstOccurrence = occurrences.First();
firstOccurrence.SetExtendedProperty(definition, "test");
firstOccurrence.Update(ConflictResolutionMode.AutoResolve);
//The error occurs on the next line.
firstOccurrence.RemoveExtendedProperty(definition);
firstOccurrence.Update(ConflictResolutionMode.AutoResolve);
//clean up
appt.Delete(DeleteMode.HardDelete);
}
It appears that the error is only thrown for an Exchange 2007 server (It works on 2010). Am I doing something wrong, or is this a problem with Exchange? Is there a way to work around this issue? Any help will be appreciated.
I ended up not using the RemoveExtendedProperty function. Instead, I worked around it by just setting the property again, but setting it to an empty space. I then handled the empty space in code. This appears to be a problem with Exchange or the managed API.
Did you try;
appointment.Delete(DeleteMode.SoftDelete,SendCancellationsMode.SendToAllAndSaveCopy);

Categories