Best way to add multiple rooms in Outlook appointment programatically - c#

I'm implementing an Outlook plugin and I need to create appointments by code, the appointments I want to model occur in rooms, rooms live in Outlook Exchange. How can I add various rooms to the appointment created by code, consider the following code to create an appointment:
Outlook.AppointmentItem newAppointment =
(Outlook.AppointmentItem)
this.Application.CreateItem(Outlook.OlItemType.olAppointmentItem);
newAppointment.Start = DateTime.Now.AddHours(2);
newAppointment.End = DateTime.Now.AddHours(3);
newAppointment.Location = "SOME_LOCATION";
newAppointment.Body =
"We will discuss progress on the group project.";
newAppointment.AllDayEvent = false;
newAppointment.Subject = "Group Project";
newAppointment.Recipients.Add("Roger Harui");
Outlook.Recipients sentTo = newAppointment.Recipients;
Outlook.Recipient sentInvite = null;
sentInvite = sentTo.Add("Holly Holt");
sentInvite.Type = (int)Outlook.OlMeetingRecipientType
.olRequired;
sentInvite = sentTo.Add("David Junca ");
sentInvite.Type = (int)Outlook.OlMeetingRecipientType
.olOptional;
sentTo.ResolveAll();
newAppointment.Save();
newAppointment.Recipients.ResolveAll();
newAppointment.Display(true);

You add a room the same way you add an attendee - pass the name of the room to Recipients.Add and set the Recipient.Type property to olResource (3).

Related

Error Sending Bulk Calendar Appointments Dynamically Using EWS and C#

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.

Add contact to distribution list programmatically

I am really stuck in this issue and searching didn't yield me a lot. Most answers I found either get Contacts not add them or use LDAP.
The best I've been able to do is display the window where you add people to the distribution list but I am not able to do that part programmatically
Here is the my best attempt:
Microsoft.Office.Interop.Outlook.Application oApp = new Microsoft.Office.Interop.Outlook.Application();
NameSpace oNS = oApp.GetNamespace("MAPI");
//Get Global Address List.
AddressLists oDLs = oNS.AddressLists;
AddressList oGal = oDLs["Global Address List"];
AddressEntries oEntries = oGal.AddressEntries;
AddressEntry oDL = oEntries["MyDistributionList"];
//Get Specific Person
SelectNamesDialog snd = oApp.Session.GetSelectNamesDialog();
snd.NumberOfRecipientSelectors = OlRecipientSelectors.olShowTo;
snd.ToLabel = "D/L";
snd.ShowOnlyInitialAddressList = true;
snd.AllowMultipleSelection = false;
//snd.Display();
AddressEntry addrEntry = oDL;
if (addrEntry.AddressEntryUserType == Microsoft.Office.Interop.Outlook.OlAddressEntryUserType.olExchangeDistributionListAddressEntry)
{
ExchangeDistributionList exchDL = addrEntry.GetExchangeDistributionList();
AddressEntries addrEntries = exchDL.GetExchangeDistributionListMembers();
string name = "John Doe";
string address = "John.Doe#MyCompany.com";
exchDL.GetExchangeDistributionListMembers().Add(OlAddressEntryUserType.olExchangeUserAddressEntry.ToString(), name, address);
exchDL.Update(Missing.Value);
}
Using this i can access the Distribution List but I get "The bookmark is not valid" exception on the
exchDL.GetExchangeDistributionListMembers().Add(OlAddressEntryUserType.olExchangeUserAddressEntry.ToString(), name, address);
line.
I have access on said list.
EDIT:
The thing is that when you use the Outlook API, you use its functionality as a user, not as an admin. More than that, you can only do things that you can do through Outlook UI.
Outlook doesn't allow you to modify distribution lists, so you won't be able to do it using the outlook API.
There are 2 possible ways to do it:
Use the NetApi functions NetGroupAddUser or NetLocalGroupAddMembers, depending on whether the group is a local or global group. This will require importing those functions with P/Invoke and won't work on universal groups.
2. Use LDAP to find the group you need, and add the users you want to it. This can be done using the System.DirectoryServices namespace like this:
using(DirectoryEntry root = new DirectoryEntry("LDAP://<host>/<DC root DN>"))
using(DirectorySearcher searcher = new DirectorySearcher(root))
{
searcher.Filter = "(&(objName=MyDistributionList))";
using(DirectoryEntry group = searcher.findOne())
{
searcher.Filter = "(&(objName=MyUserName))";
using(DirectoryEntry user = searcher.findOne())
{
group.Invoke("Add", user.Path);
}
}
}
These just wrap the old COM ADSI interfaces, that's why I use group.Invoke(). It takes a bit more practice, but is much more powerful than the NetApi functions.

Sharepoint calendar event attendees

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().

add multiple appointmentsTask in windows phone 8

I have successfully added single appointment using this code now i want to add multiple appointment pro grammatically in a single loop.for example i want to add 5 appointment at a time using loop where dates for every appointment is available in a List.
Thanks in advance :)
SaveAppointmentTask saveAppointmentTask = new SaveAppointmentTask();
saveAppointmentTask.StartTime = nearestDate;
saveAppointmentTask.EndTime = nearestDate.AddMinutes(3) ;
saveAppointmentTask.Subject = "Meet Ali"; // appointment subject
saveAppointmentTask.Location = "In Office"; // appointment location
saveAppointmentTask.Details = "Meet Ali to discuss product launch";//appointment details
saveAppointmentTask.IsAllDayEvent = false;
saveAppointmentTask.Reminder = Microsoft.Phone.Tasks.Reminder.FifteenMinutes;
saveAppointmentTask.AppointmentStatus = Microsoft.Phone.UserData.AppointmentStatus.OutOfOffice;
saveAppointmentTask.Show();
use this code as Navigated To event is all the time called when you land up in the page
private SaveAppointmentTask saveAppointmentTask;
private List<int> listMinutes = new List<int>();
// Constructor
public MainPage()
{
InitializeComponent();
for (int i = 0; i < 10; i++) {
listMinutes.Add(i);
}
}
int countAdded = 0;
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (countAdded < 10)
{
saveAppointmentTask = new SaveAppointmentTask();
saveAppointmentTask.StartTime = DateTime.Now.AddMinutes(listMinutes[countAdded]);
saveAppointmentTask.EndTime = saveAppointmentTask.StartTime.Value.AddMinutes(2);
saveAppointmentTask.Subject = "Meet Ali"; // appointment subject
saveAppointmentTask.Location = "In Office"; // appointment location
saveAppointmentTask.Details = "Meet Ali to discuss product launch";//appointment details
saveAppointmentTask.IsAllDayEvent = false;
saveAppointmentTask.Reminder = Microsoft.Phone.Tasks.Reminder.FifteenMinutes;
saveAppointmentTask.AppointmentStatus = Microsoft.Phone.UserData.AppointmentStatus.OutOfOffice;
countAdded++;
saveAppointmentTask.Show();
}
else {
// do not add anything
}
}
save i that is the count in some application state or a tokes so that you can know if you have added the events :) Appplication.Current.Resources.Add("token", "number added")
Thanks
You cannot automatically save all appointments. You would have to launch the task in each iteration, and user interaction would be nedded in each.
A possible option is to use the Live Connect API. That would allow you to programatically create apointments in user's Live calendar:
Interacting with calendars (Live Connect API)
This way you don't interact with the phone calendar, but the users's Live calendar, which can be synchronized in the phone. Of course, the user will need to authenticate.

Outlook Interop c# sort items not working

I have stumbled upon a problem where the Outlook items table sort method does not give desired results - despite the ascending or descending the method GetLast() always returns the same email item. Code as follows:
Application olApp = new Application();
NameSpace olNS = olApp.GetNamespace("MAPI");
MAPIFolder oFolder = olNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
Explorer oExp = oFolder.GetExplorer(false);
//olNS.Logon( false, true);
result = new IOActionResult(null);
oFolder.Items.Sort("[ReceivedTime]");
var subject = oFolder.Items.GetLast().Subject;
I have tried specifying following:
oFolder.Items.Sort("[ReceivedTime]", true);
oFolder.Items.Sort("[ReceivedTime]", false);
oFolder.Items.Sort("[ReceivedTime]", OlSortOrder.olAscending);
oFolder.Items.Sort("[ReceivedTime]", OlSortOrder.olDescending);
Which did not seem to work either... Any thoughts appreciated!
On your last line;
var subject = oFolder.Items.GetLast().Subject;
You are being returned a new Items object from Outlook, so your sort was actually performed on an instance that you no longer have a reference to.
Change your code to look like this;
Application olApp = new Application();
NameSpace olNS = olApp.GetNamespace("MAPI");
MAPIFolder oFolder = olNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
Items items = oFolder.Items;
items.Sort("[ReceivedTime]");
var subject = items.GetLast().Subject;
A good rule of thumb when developing against Outlook is to always assign intermediary members of objects to their own local variable. This is particular relevant for releasing them later on.

Categories

Resources