I am trying to get a list of all the appointments for the day on a shared calendar. I have successfully done it for my own calendar tied to my user account. I tried getting the folderId of the shared calendar, but I haven't been able to find it.
I used this to access my calendar using its folderId and it worked:
Console.WriteLine("Listing appointments...");
//open the calendar
CalendarFolder calendar = CalendarFolder.Bind(service, WellKnownFolderName.Calendar);
//query for appointments in next 10 days
//FindItemsResults<Appointment> appointments = calendar.FindAppointments(new CalendarView(DateTime.Now, DateTime.Now.AddDays(10)));
//find appointments and write out subject
foreach (Appointment appointment in service.FindItems(new FolderId("FOLDERIDHERE"), new ItemView(int.MaxValue)))
Console.WriteLine(appointment.Subject);
I don't know if this will work to access a shared folder, and I can't figure out the folderID of the shared folder.
You could try something like this :
CalendarModule calModule = (CalendarModule)this.Application.ActiveExplorer().NavigationPane.Modules.GetNavigationModule(OlNavigationModuleType.olModuleCalendar);
foreach (NavigationGroup group in calModule.NavigationGroups)
{
NavigationFolders folders = group.NavigationFolders;
MAPIFolder OtherFolder = null;
Items OtherFolderItems = null;
for (int i = 1; i <= group.NavigationFolders.Count; i++)
{
OtherFolder = folders[i].Folder; //This does not work for me
OtherFolderItems = OtherFolder.Items;
}
Unfortunately, this code did not work for me, as trying to access the .Folder launch an exception. I found this on this link : http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/4891d3a5-f578-495c-83aa-f5a914474c78/
Related
I am trying to save an Outllok meeting ics file as an Outlook appointment ics but when i use do SaveAs to a folder location, it is saving as a meeting.
I have the following code but I can not seem to locate the issue. When I use .Display it shows as an appointment but .SaveAs is saving back as a meeting with recipients.
Any help is much appreciated
Outlook.Application App = new Outlook.Application();
string FPath = #"C:\\Documents\TestMeeting.ics"
var item = App.Session.OpenSharedItem(FPath) as Outlook.MeetingItem;
var AppointmentItem = item.GetAsssociatedAppointment(false);
AppointmentItem.MeetingStatus = Outlook.OlMeetingStatus.olNonMeeting;
AppointmentItem.Display(true);
AppointmentItem.SaveAs(#"C:\\Documents\TestAppointment1.ics",Outlook.OlSaveAsType.olIcal);
Use the Save method to save the just opened meeting into your calendar:
string FPath = #"C:\\Documents\TestMeeting.ics"
var item = App.Session.OpenSharedItem(FPath) as Outlook.MeetingItem;
item.Save();
// only after that you can try reprieving the associated appointment
var AppointmentItem = item.GetAsssociatedAppointment(false);
Also I'd recommend creating a new appointment item from scratch and then saving it to the disk.
Thanks Eugene. I managed to get this working by creating a new appointment and using .BodyFormat and .RTFBody of the associated appointment. I have included the full code below for anyone in the future and marked your answer as correct. Apologies but at present I don't have enough rep to upvote otherwise I would. Many thanks
Outlook.Application App = new Outlook.Application();
string FPath = #"C:\\Documents\TestMeeting.ics"
var item = App.Session.OpenSharedItem(FPath) as Outlook.MeetingItem;
var AppointmentItem = item.GetAsssociatedAppointment(false);
Outlook.AppointmentItem ap1 = (Outlook.AppointmentItem)App.CreateItem(Outlook.OlItemType.olAppointmentItem);
ap1.Start = AppointmentItem.Start;
ap1.Subject = AppointmentItem.Subject;
ap1.BodyFormat = AppointmentItem.BodyFormat;
ap1.RTFBody = AppointmentItem.RTFBody;
ap1.Location = AppointmentItem.Location;
ap1.SaveAs(#"C:\\Documents\TestAppointment1.ics",Outlook.OlSaveAsType.olIcal);
We're using EWS to integrate our CRM with Exchange Online 2010SP2. One of the tasks: provide one calendar for Sales persons with the next rule: every Sales can see all appointments in Scheduler, but can open and see details (body) only his/her own appointment. Appointment are being placed by CRM in response of certain business events. We tried to use impersonate and Sensitivity.Private property. Appointment is being placed with impersonated user name, but it can't be opened by that user neither through OWA nor via Outlook. So it's placed as private appointment of 'master' user (user who created shared calendar and his credentials is used for service connection), he can open it in Outlook or OWA. EWSEditor shows appointment's LastModifiedUser - correct impersonated username (not master's). In Fiddler we can see 'success' Response on appointment placement request (under impersonated user). In OutlookSpy, we can see that appointments PR_SENDER_NAME_W, PR_SENT_REPRESENTING_NAME_W properties shows 'master's' username. We stuck.
Impersonated user has 'owner' rights upon that shared calendar.
If Impersonating doesn't resolve this issue, can Delegate technique do that?
Thanks in advance for any help.
static void Main(string[] args)
{
ExchangeService services = new
ExchangeService(ExchangeVersion.Exchange2010_SP2);
services.Credentials = new WebCredentials("master#exchserver.com",
"MasterPwd");
services.Url = new Uri("https://someserver.com/ews/exchange.asmx");
FolderId rfRootFolderid = new FolderId(WellKnownFolderName.Calendar);
FolderView fvFolderView = new FolderView(100);
DateTime startDate = DateTime.Now.AddDays(1);
DateTime endDate;
string SalesCalendarId = "AAMkADVlMGVjZWVkLT....AADo8XAAA=";
CalendarFolder folder = CalendarFolder.Bind(services, new
FolderId(SalesCalendarId));
TimeSpan ts = new TimeSpan(10, 00, 0);
startDate = startDate.Date + ts;
endDate = startDate.AddMinutes(60);
services.HttpHeaders.Add("X-AnchorMailbox","impersonateduser#exchserver.com");
appointment.Subject = "from Test";
appointment.Body = "Test";
appointment.Start = startDate;
appointment.End = appointment.Start.AddMinutes(30);
appointment.ReminderDueBy = appointment.Start.AddHours(1);
appointment.Sensitivity = Sensitivity.Private;
ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "impersonateduser#exchserver.com");
appointment.Save(SalesCalendarId, SendInvitationsMode.SendToNone);
}
You could use impersonated user to obtain ‘owner’ permissions.
Please include the code below before services.Credentials = new WebCredentials("master#exchserver.com", "MasterPwd")
services.PreAuthenticate = true;
you need to make sure that we have required permissions for EWS Impersonation as per the article mentioned below:
Configuring Exchange Impersonation in Exchange 2010
Using Exchange Impersonation in Exchange 2010
You could reference the following link:
Get all calendar events for a specific user
I am creating simple app for appointments scheduling and I want to implement ability for me to create appointments for my users.
I managed to create,update and delete my calendar on Exchange Server, and I somewhat managed to create appointments adding my colleagues as RequiredAttendees like so:
//service variable is being created using my credidentals
Appointment meeting = new Appointment(service);
meeting.Subject = "Some subject ";
meeting.Body = "Some body.";
meeting.Start = DateTime.Now;
meeting.End = meeting.Start.AddHours(4);
meeting.Location = "Some Location";
meeting.RequiredAttendees.Add("myCollegue#mail.com");
meeting.ReminderMinutesBeforeStart = 60;
meeting.Save(new FolderId(WellKnownFolderName.Calendar,
"myCollegue#mail.com"),
SendInvitationsMode.SendToAllAndSaveCopy);
But it is just setting him as required attendee. Next thing is I tried using impersonation, but I can't access hosting server to set myself as master and others to have to share calendar with me (due to permissions and stuff) so I had to scrape that as well. Also, he set me up to be his publishing author on his calendar.
Is there something I am missing, or can't seem to find on MSDN sites?
EDIT: I am able to create appointment in his calendar in outlok.
If anyone comes across same issues as I did in here please follow these steps:
Make sure that person for which you are creating appointment sets you up (on exchange server or in outlok as "Editing author" with all permissions.
After that you can create appointments for him (verify this by going to your outlok and creating some test appointments).
This code works for me:
Folder inboxFolder = Folder.Bind(service, new FolderId(WellKnownFolderName.Calendar, "your.colleague#company.com"));
Appointment appointmentOther = new Appointment(service);
appointmentOther.Subject = "Test 2";
appointmentOther.Body = "Body text";
appointmentOther.Start = DateTime.Now;
appointmentOther.End = DateTime.Today.AddHours(16);
appointmentOther.Location = "My Office";
appointmentOther.IsReminderSet = true;
appointmentOther.ReminderMinutesBeforeStart = 30;
appointmentOther.Save(inboxFolder.Id,SendInvitationsMode.SendToNone);
Good luck :)
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();
I am building an app that is required to live in a trusted domain, monitor a collection of mailbox-calendars on an exchange server in that domain, and sync appointments to different mailboxes on one or many other servers. The mailbox it is synced with is defined in an internal mapping table (sqlce) that is maintained by the user of this application.
The problem I have is I can not work out a way to keep track of the remote appointment so that I can update or delete it if necessary. After I create the appointments on the remote server they have a new itemid which does not correspond to the one returned by the sync folder items call on the local exchange server. I can't find the item by start time/subject as these may have been changed or deleted.
My sync method is below - am I going about this entirely the wrong way or is there a better way to use the SyncFolderItems method?
The best approach I have come up with so far to get around my problem is to save ItemID of the remote appointment into a property of the local appointment but even this I am not sure will work because I don't know what properties are maintained after a delete? Please Help!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Exchange.WebServices.Data;
using System.Net;
namespace ProExchangeSync2012
{
class ExchangeWebServiceMethods
{
public string ProExchangeSyncCalendars(string LocalMailbox
,string RemoteMailbox
,string SyncState
,ExchangeService RemoteService
,ExchangeService LocalService
)
{
//if SyncState is empty string set to null
if (SyncState.ToString().Length == 0)
{ SyncState = null; }
ExchangeService LocalExchangeService = LocalService;
ExchangeService RemoteExchangeService = RemoteService;
RemoteExchangeService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress,RemoteMailbox);
//Folders and mailboxes to pass to the webservice in SyncItems call.
Mailbox DonorMailBox = new Mailbox(LocalMailbox);
Mailbox DestinationMailBox = new Mailbox(RemoteMailbox);
FolderId DonorFolder = new FolderId(WellKnownFolderName.Calendar, DonorMailBox);
FolderId DestinationFolder = new FolderId(WellKnownFolderName.Calendar, DestinationMailBox);
//Create a ChangeCollection object and call syncfolderitems on local exchange service.
ChangeCollection<ItemChange> ItemChanges
= LocalExchangeService.SyncFolderItems(new FolderId(WellKnownFolderName.Calendar, DonorMailBox) //PASS IN THE MAILBOX HERE>
, PropertySet.FirstClassProperties
, null
, 512
, SyncFolderItemsScope.NormalItems
, SyncState
);
//Store the SyncState
SyncState = ItemChanges.SyncState;
//Fetch all the required properties of the items
//LocalService.LoadPropertiesForItems(ItemChanges, PropertySet.FirstClassProperties);
if (ItemChanges.Count == 0)
{
Console.WriteLine("There are no items to synchronize.");
}
else
{
foreach (ItemChange ic in ItemChanges)
{
if (ic.ChangeType == ChangeType.Create)
{
Appointment lappointment = Appointment.Bind(LocalExchangeService, ic.ItemId);
Appointment rappointment = new Appointment(RemoteExchangeService);
rappointment.Subject = lappointment.Subject;
rappointment.Start = lappointment.Start;
rappointment.Body = lappointment.Body;
rappointment.End = lappointment.End;
rappointment.Location = lappointment.Location;
rappointment.Save();
}
else if (ic.ChangeType == ChangeType.Update)
{
//Bind to the local appointment and get the start date
Appointment lappointment = Appointment.Bind(LocalExchangeService, ic.ItemId);
DateTime StartDate = lappointment.Start;
ItemId ItemToUpdate = ItemIDSearch(RemoteExchangeService,StartDate,lappointment.Subject);
//Bind to the remote appointment using ItemToUpdate & update all the details
//this is is less intensive than comparing the appointments for changes.
Appointment rappointment = Appointment.Bind(RemoteExchangeService, ItemToUpdate);
rappointment.Subject = lappointment.Subject;
rappointment.Start = lappointment.Start;
rappointment.Body = lappointment.Body;
rappointment.End = lappointment.End;
rappointment.Location = lappointment.Location;
rappointment.Save();
}
else if (ic.ChangeType == ChangeType.Delete)
{
Appointment lappointment = Appointment.Bind(LocalExchangeService, ic.ItemId.UniqueId);
DateTime StartDate = lappointment.Start;
ItemId ItemToUpdate = ItemIDSearch(RemoteExchangeService, StartDate, lappointment.Subject);
Appointment rappointment = Appointment.Bind(RemoteExchangeService, ic.ItemId.UniqueId);
rappointment.Delete(DeleteMode.MoveToDeletedItems);
}
}
}
return SyncState;
}
//End of Sync Method
//Below method returns a single itemid from exchange service based on start datetime of an appointment in a mailbox.
public ItemId ItemIDSearch(ExchangeService ExchangeService, DateTime AppointmentStart, string subject)
{
ItemId FoundItem;
ItemView iv = new ItemView(1000);
iv.Traversal = ItemTraversal.Associated;
SearchFilter.SearchFilterCollection searchFilterCollection = new SearchFilter.SearchFilterCollection(LogicalOperator.And);
searchFilterCollection.Add(new SearchFilter.IsEqualTo(AppointmentSchema.Subject,subject));
searchFilterCollection.Add(new SearchFilter.IsEqualTo(AppointmentSchema.Start, AppointmentStart));
FindItemsResults<Item> fiitems = ExchangeService.FindItems(WellKnownFolderName.Calendar, searchFilterCollection, iv);
if (fiitems.Items.Count == 1)//if we only get one result do the work else return null
{
FoundItem = fiitems.Items[0].Id;
}
FoundItem = null;
return FoundItem;
}
}
}
So the final solution to all this, which came from the messiah of Exchange Web Services, Glen Scales, was that I stored the "CleanGlobalObjectId" of the appointments I was synching with in my internal database along with the EWS UniqueId that is returned when calling the EWS SyncFolderItems method.
Using the CleanGlobalObjectId which is an extended property of the appointment, I was always able to find a specific appointment on the server even if it had been hard deleted, because the value of this property never changes.