I add an extended property in this way:
ExtendedPropertyDefinition ep = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.CalendarAssistant, "AppointmentID", MapiPropertyType.Integer);
Appointment newApp = new Appointment(service);
newapp.SetExtendedProperty(ep, appID);
newApp.Save(SendInvitationsMode.SendToNone);
All is good. The appointment shows up in Outlook as expected.
Later I tried to search through all Outlook appointment with an AppointmentID assigned by:
List<SearchFilter> filters = new List<SearchFilter>();
filters.Add(new SearchFilter.Exists(ep));
filters.Add(new SearchFilter.IsLessThan(AppointmentSchema.Start, DateTime.Now.AddDays(60)));
filters.Add(new SearchFilter.IsGreaterThanOrEqualTo(AppointmentSchema.Start, DateTime.Today));
FindItemsResults<Item> allOutlookAppt = service.FindItems(WellKnownFolderName.Calendar, new SearchFilter.SearchFilterCollection(LogicalOperator.And, filters.ToArray()), viewFind);
allOutlookAppt returns the expected collection (calendar entries with AppointmentID set). However I could not retrieve the AppointmentID by this code:
foreach (var a in allOutlookAppt) // contains correct calendar entries!
{
object oid;
if (a.TryGetProperty(ep, out oid))
{
// a.TryGetProperty is always false, oid is always null thus never enter here!
}
}
What did I do wrong?
Edit: I tried a.ExtendedProperties.Count and it actually returns 0.
After googling a bit I have to add this before searching the calendar
viewFind.PropertySet = new PropertySet(ep);
Related
I'm writing an Outlook COM add-in in C#/.NET using Microsoft.Office.Interop.Outlook. I can create a new appointment item like so:
using Outlook = Microsoft.Office.Interop.Outlook;
[...]
var appointment = (Outlook.AppointmentItem)Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olAppointmentItem);
appointment.Display(true);
However, I have 2 different accounts set up in my Outlook. If I then go into the appointment's "Invite Attendees", the "From" always shows the first of my two Outlook accounts.
I tried setting the .SendUsingAccount property to the other account in my Outlook profile, which I got from the current session:
var accounts = Globals.ThisAddIn.Application.Session.Accounts;
foreach (Outlook.Account acct in accounts) {
if (acct.DisplayName == "[desired account display name]") {
appointment.SendUsingAccount = acct;
break;
}
}
However, this just makes the "From" field blank in the "Invite Attendees" section rather than showing the account I set it to. What am I doing wrong here?
Try to call the Save method to apply your changes made through the OOM.
The AppointmentItem.SendUsingAccount property allows to specify an Account object that represents the account under which the AppointmentItem is to be sent.
What is the property of AppointmentItem Object, that changes the meeting host?
The easiest way is to create an appointment item in the calendar folder which belongs to a particular account. What code do you use for creating appointment items?
The How To: Create a new Outlook Appointment item article explains all possible ways for creating appointment items in Outlook. Try to get the right folder and use the Add method of the Items class. For example:
items.Add(Outlook.OlItemType.olAppointmentItem)
The GetDefaultFolder method of the Store class returns a Folder object that represents the default folder in the store and that is of the type specified by the FolderType argument. This method is similar to the GetDefaultFolder method of the NameSpace object. The difference is that this method gets the default folder on the delivery store that is associated with the account, whereas NameSpace.GetDefaultFolder returns the default folder on the default store for the current profile.
In the end, I managed to get this to work by finding out the currently-selected folder via Application.ActiveExplorer().CurrentFolder and then getting its default calendar folder through .Store.GetDefaultFolder(). This allowed me to create a new calendar item through the correct calendar, automatically setting the appropriate "From" address for the currently-selected folder. Here's the code used:
using Outlook = Microsoft.Office.Interop.Outlook;
[...]
Outlook.Explorer activeExplorer = null;
Outlook.Store currentStore = null;
Outlook.MAPIFolder calendarFolder = null;
Outlook.Items items = null;
Outlook.AppointmentItem appointment = null;
try {
// Get default calendar for currently-selected folder
activeExplorer = Globals.ThisAddIn.Application.ActiveExplorer();
if (activeExplorer == null) {
throw new Exception("No active explorer.");
}
currentStore = activeExplorer?.CurrentFolder?.Store;
if (currentStore == null) {
throw new Exception("No current store.");
}
calendarFolder = currentStore?.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
if (calendarFolder == null) {
throw new Exception("No default calendar folder.");
}
items = calendarFolder?.Items;
if (items == null) {
throw new Exception("No calendar folder items.");
}
// Populate a new outlook appointment object with the appointment info
appointment = items.Add(Outlook.OlItemType.olAppointmentItem) as Outlook.AppointmentItem;
// Setup appointment
[...]
// Display the appointment window to the user
appointment.Display(true);
}
catch (Exception ex) {
MessageBox.Show(Resources.AppointmentError + ": " + ex.Message);
}
finally {
if (activeExplorer != null) { Marshal.ReleaseComObject(activeExplorer); }
if (currentStore != null) { Marshal.ReleaseComObject(currentStore); }
if (calendarFolder != null) { Marshal.ReleaseComObject(calendarFolder); }
if (items != null) { Marshal.ReleaseComObject(items); }
if (appointment != null) { Marshal.ReleaseComObject(appointment); }
}
I've create a small application that gets all my emails. I add each email to a list. However before I add them to a list I filter them. All of my filters are working apart from one. My search filter for filtering my email by sender is not working as I'm only trying to filter the domain and not the whole email address. For example xxx#xxx.com will filter however I want to filter out everything with xxx.com domain and for some reason it doesn't filter it. I tried using substring and this doesn't work either.
My code is as fallows
private static SearchFilter.SearchFilterCollection sFilter = new SearchFilter.SearchFilterCollection();
private static FindItemsResults<Item> findResults;
sFilter.Add(new SearchFilter.Not(new SearchFilter.ContainsSubstring(EmailMessageSchema.Sender, "#xxx.com",ContainmentMode.Substring,ComparisonMode.IgnoreCase)));
sFilter.Add(new SearchFilter.Not(new SearchFilter.Exists(EmailMessageSchema.InReplyTo)));
DateTime startTime = GetDateValueforFilter();
startTimefilter = new SearchFilter.IsGreaterThanOrEqualTo(EmailMessageSchema.DateTimeReceived, startTime);
sFilter.Add(startTimefilter);
sFilter.Add(startTimefilter);
findResults = service.FindItems(
WellKnownFolderName.Inbox
,sFilter
,new ItemView(25));
foreach (EmailMessage item in findResults.Items)
{
//if (item.IsRead == false)
//{
// if (item.InReplyTo == null)
// {
bool replyToAll = true;
string myReply = "This is the message body of the email reply.";
item.Reply(myReply, replyToAll);
item.IsRead = true;
item.Send();
//}
//}
}
I would suggest you try using the Extended Property PidTagSenderSmtpAddress https://msdn.microsoft.com/en-us/library/office/jj713594.aspx and try something like
ExtendedPropertyDefinition PidTagSenderSmtpAddress = new ExtendedPropertyDefinition(0x5D01,MapiPropertyType.String);
SearchFilter sf = new SearchFilter.ContainsSubstring(PidTagSenderSmtpAddress, "#yahoo.com");
How to restore deleted appointment using EWS 2.0?
I think i could search for it in the WellKnownFolderName.RecoverableItemsDeletions folder. But all i have is ItemId. And sadly I cant use it in SearchFilter...
What is the best way?
my try:
ItemView view = new ItemView(10);
SearchFilter searchFilter = new SearchFilter.IsEqualTo(ItemSchema.Id, itemChange.ItemId);
var findResults = exchangeService.FindItems(WellKnownFolderName.RecoverableItemsDeletions, searchFilter, view);
List<ItemId> ids = null;
foreach (var findResult in findResults)
{
Debug.WriteLine(findResult.Id.ToString());
ids.Add(findResult.Id);
}
exchangeService.MoveItems(ids, WellKnownFolderName.Calendar);
an error occurs:
{"Values of type 'ItemId' can't be used as comparison values in search filters."}
Set your WellKnownFolderName to DeletedItems when you are searching for the appointments. And you should set up your search filter to only return appointments since the DeletedItems folder can hold more than just the appointments you are looking for. Here is an example that should work for you.
ItemView view = new ItemView(10);
// Only look for appointments
SearchFilter searchFilter = new SearchFilter.IsEqualTo(ItemSchema.ItemClass, "IPM.Appointment");
// Look for items in the DeletedItems folder
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.DeletedItems, searchFilter, view);
// Move each of the deleted items back to the calendar
List<ItemId> ItemsToMove = new List<ItemId>();
foreach (Item item in results)
{
ItemsToMove.Add(item.Id);
}
service.MoveItems(ItemsToMove, WellKnownFolderName.Calendar);
I'm developing an outbound call system that shows the user the next company to call with a means to add an appointment for a selected sales rep.
I initially programmed the appointment to be sent in real time as the user saves the current data and move to the next lead. However, there was a significant delay while the appointment was being sent to the email account on Office 365. So I decided to create a small app to send them in batch every 15 minutes.
This works great for the first three appointments, but then I get an error on the 4th appointment:
The Autodiscover service couldn't be located.
I'm suspecting this is something like a hosting company stopping a mailbox from being used for bulk email and there is a limit. Is there something within EWS to allow more than three at a time? Or do I need to amend my code?
Here is my code for sending the appointments:
const string o365Server = "mydomain.co.uk";
var appointmenntList = AppointmentList.GetAppointnmetsToSend();
ExchangeService service = new ExchangeService();
foreach (var appointment in appointmenntList)
{
Console.WriteLine(appointment.IntLeadID);
service.Credentials = new WebCredentials(appointment.StrSalesRepEmail, apointment.StrSalesRepEmailPassword, o365Server);
service.AutodiscoverUrl(appointment.StrSalesRepEmail, RedirectionCallback);
Appointment app = new Appointment(service);
app.Subject = "ASH Waste Appointment with " + appointment.StrLeadAppointmentContact;
app.Body = appointment.StrLeadAppointmentNotes;
app.Start = appointment.DtLeadAppointmentDate;
app.End = app.Start.AddHours(1);
app.Location = appointment.StrLeadAppointmentLocation;
app.RequiredAttendees.Add(appointment.StrSalesRepEmail);
app.ReminderMinutesBeforeStart = 60;
app.Save(SendInvitationsMode.SendOnlyToAll);
Console.WriteLine(appointment);
}
static bool RedirectionCallback(string url)
{
return url.ToLower().StartsWith("https://");
}
I could set the app to do only three at a time and run the app every 2 minutes. Although this would be enough for our sales team, it is limiting the operation.
Any suggestions?
Edit:
Here's the full error:
An unhandled exception of type
Microsoft.Exchange.WebServices.Data.AutodiscoverLocalException'
occurred in Microsoft.Exchange.WebServices.dll
and it occurs on this line of code:
service.AutodiscoverUrl(appointment.StrSalesRepEmail, RedirectionCallback);
I can batch 4 calendar items when using the CreateItems method instead. Have you tried that? Here's some sample code.
public static Collection<ItemId> BatchCreateCalendarItems(ExchangeService service)
{
// These are unsaved local instances of an Appointment object.
// Despite the required parameter of an ExchangeService object (service), no call
// to an Exchange server is made when the objects are instantiated.
// A call to the Exchange server is made when the service.CreateItems() method is called.
Appointment appt1 = new Appointment(service);
Appointment appt2 = new Appointment(service);
Appointment appt3 = new Appointment(service);
Appointment appt4 = new Appointment(service);
// Set the properties for a single instance appointment
appt1.Subject = "Appt1";
appt1.Body = "Appt1";
appt1.Start = DateTime.Now.AddDays(1);
appt1.End = appt1.Start.AddHours(3);
appt1.Location = "My office";
appt1.ReminderMinutesBeforeStart = 30;
// Set the properties for a single instance appointment
appt2.Subject = "Appt2";
appt2.Body = "Appt2";
appt2.Start = DateTime.Now.AddDays(1);
appt2.End = appt1.Start.AddHours(4);
appt2.Location = "My office";
appt2.ReminderMinutesBeforeStart = 30;
// Set the properties for a single instance appointment
appt3.Subject = "Appt3";
appt3.Body = "Appt3";
appt3.Start = DateTime.Now.AddDays(1);
appt3.End = appt1.Start.AddHours(5);
appt3.Location = "My office";
appt3.ReminderMinutesBeforeStart = 30;
// Set the properties for a single instance appointment
appt4.Subject = "Appt4";
appt4.Body = "Appt4";
appt4.Start = DateTime.Now.AddDays(1);
appt4.End = appt1.Start.AddHours(6);
appt4.Location = "My office";
appt4.ReminderMinutesBeforeStart = 30;
// Add the appointment objects to a collection
Collection<Appointment> calendarItems = new Collection<Appointment>() { appt1, appt2, appt3, appt4 };
// Instantiate a collection of item ids to populate from the values that are returned by the Exchange server.
Collection<ItemId> itemIds = new Collection<ItemId>();
// Send the batch of appointment objects.
// Note that multiple calls to the Exchange server may be made when appointment objects have attachments.
// Note also that the item collection passed as the first parameter to CreateItems will have their ids set on return.
ServiceResponseCollection<ServiceResponse> response = service.CreateItems(calendarItems,
WellKnownFolderName.Calendar,
MessageDisposition.SendAndSaveCopy,
SendInvitationsMode.SendToAllAndSaveCopy);
if (response.OverallResult == ServiceResult.Success)
{
Console.WriteLine("All appointments and meetings sucessfully created.");
}
// Collect the item ids from the created calendar items.
foreach (Appointment appt in calendarItems)
{
itemIds.Add(appt.Id);
}
int counter = 1;
// Show the ids and errors for each message
foreach (ServiceResponse resp in response)
{
// Note that since item ids are long, show only 5 characters.
Console.WriteLine("Result (message {0}), id {1}: {2}", counter, itemIds[counter - 1].ToString().Substring(0, 5), resp.Result);
Console.WriteLine("Error Code: {0}", resp.ErrorCode);
Console.WriteLine("ErrorMessage: {0}\r\n", resp.ErrorMessage);
counter++;
}
// Return the collection of item ids
return itemIds;
}
Well, it isn't that you're getting blocked from sending a specific number of appointments, it's that Autodiscover is failing. That error is one that the EWS Managed API likes to return for all kinds of scenarios, so it doesn't tell me for sure why it is failing. It could be a temporary network issue, or it could be that the Autodiscover servers are throttling you. I'm not sure offhand if Autodiscover does any throttling, but it's certainly possible.
To see why it's failing, you could enable tracing with all of the Autodiscover-related trace flags turned on and see what kinds of errors are coming back.
I want to programmatically add an event to a calendar in SharePoint 2010. I get the list of events and add element to this list.
SPList list = web.Lists.TryGetList(sCalendarName);
if (list != null)
{
SPListItem item = list.Items.Add();
item["Title"] = "New Event";
item["Description"] = "New Event created using SharePoint Object Model";
item["Location"] = "First Floor";
item["EventDate"] = DateTime.Now;
item["EndDate"] = DateTime.Now.AddDays(2);
item["Category"] = "Business";
item["fAllDayEvent"] = false;
item["Author"] = web.EnsureUser(#"domen\username");
item.Update();
}
But I can't find how to add a value to the "Particiants" ("Attendee") field.
If you look throw the item.Xml there is ows_ParticipantsPicker element, which contains users, that added by Sharepoint Calendar interface.
How can I add a participant (Attendee) to the event?
Have you tried using SPFieldUserValueCollection as the value of field?
SPFieldUserValueCollection values = new SPFieldUserValueCollection();
SPUser user = web.EnsureUser(#"domen\username");
values.Add(new SPFieldUserValue(web, user.ID, user.Name));
item["Participants"] = values;
Also, don't use SPList.Items.Add(), it gets all items before adding a new one. Use SPList.AddItem().