How to identify the same Exchange calendar events? - exchange-server

I use EWS to get data about user calendar events. I connect to MS Exchange on behalf of the user. If I connect as user B, how can I tell if I found the same calendar event which I found before in mailbox of user A?
Maybe something like the same message identifier or something like that?

There's a few way you can do that the best way (which is the way Outlook uses) is to use the Goid properties eg GlobalCleanObjectId https://learn.microsoft.com/en-us/office/client-developer/outlook/mapi/pidlidcleanglobalobjectid-canonical-property a quick example
Appointment newAppointment = new Appointment(service);
newAppointment.Subject = "Test Subject";
newAppointment.Start = new DateTime(2012, 03, 27, 17, 00, 0);
newAppointment.StartTimeZone = TimeZoneInfo.Local;
newAppointment.EndTimeZone = TimeZoneInfo.Local;
newAppointment.End = newAppointment.Start.AddMinutes(30);
newAppointment.Save();
newAppointment.Body = new MessageBody(Microsoft.Exchange.WebServices.Data.BodyType.Text, "test");
newAppointment.RequiredAttendees.Add("attendee#domain.com");
newAppointment.Update(ConflictResolutionMode.AlwaysOverwrite ,SendInvitationsOrCancellationsMode.SendOnlyToAll);
ExtendedPropertyDefinition CleanGlobalObjectId = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Meeting, 0x23, MapiPropertyType.Binary);
PropertySet psPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
psPropSet.Add(CleanGlobalObjectId);
newAppointment.Load(psPropSet);
object CalIdVal = null;
newAppointment.TryGetProperty(CleanGlobalObjectId, out CalIdVal);
Folder AtndCalendar = Folder.Bind(service, new FolderId(WellKnownFolderName.Calendar,"attendee#domain.com"));
SearchFilter sfSearchFilter = new SearchFilter.IsEqualTo(CleanGlobalObjectId, Convert.ToBase64String((Byte[])CalIdVal));
ItemView ivItemView = new ItemView(1);
FindItemsResults<Item> fiResults = AtndCalendar.FindItems(sfSearchFilter, ivItemView);
if (fiResults.Items.Count > 0) {
//do whatever
}

Related

How to create an evet in other user calendar which I have write permision, using C#?

I am trying to create an application where I add an event in other calendar which I have write access to it.
I was manage to create an application to send an meeting invitation. But I would like to direct add to calendar?
Second step if the schedule was change I would like to change the event date.
Any one could give any idea in how can I create a C# code to add an event in other calendar?
Thanks for any idea!
Tried alredy sending an invitation for a meeting, this worked but it is necessary user approval, them it will not work very well for the application.
using OutLook = Microsoft.Office.Interop.Outlook;
public void NovoAtendimento(MeetInfo nwVisit)
{
OutLook.Application objOL = new OutLook.Application();
OutLook.AppointmentItem objAppt = (OutLook.AppointmentItem)objOL.CreateItem(OutLook.OlItemType.olAppointmentItem);
objAppt.Subject = nwVisit.Titulo;
objAppt.Body = nwVisit.Detalhe;
objAppt.Location = nwVisit.Local;
objAppt.Start = nwVisit.DiaInicio;
objAppt.End = nwVisit.DiaFim;
objAppt.MeetingStatus = OutLook.OlMeetingStatus.olMeeting;
objAppt.RequiredAttendees = nwVisit.Email;
objAppt.Save();
objAppt.Send();
objAppt = null;
objOL = null;
}
Instead of using Application.CreateItem, retrieve the shared folder using Namespace.CreateRecipient / Namespace.GetSharedDefaultFolder, then add an appointment using MAPIFolder.Items.Add.
After checking the hint from Dmitry, this was the final prograns lines that worked:
public void TestCheckCalendar(MeetInfo usrCall)
{
OutLook.Application myApp = new OutLook.Application();
OutLook.NameSpace myNs = myApp.GetNamespace("MAPI");
OutLook.Recipient myReci = myNs.CreateRecipient(usrCall.Email);
OutLook.MAPIFolder calFolder = myApp.Session.GetSharedDefaultFolder(myReci,OutLook.OlDefaultFolders.olFolderCalendar);
OutLook.Items itemTest = null;
OutLook.AppointmentItem appItem = null;
itemTest = calFolder.Items;
appItem = itemTest.Add(OutLook.OlItemType.olAppointmentItem) as OutLook.AppointmentItem;
appItem.Start = usrCall.DiaInicio;
appItem.End = usrCall.DiaFim;
appItem.Location = usrCall.Local;
appItem.Subject = usrCall.Titulo;
appItem.Body = usrCall.Detalhe;
appItem.Save();
}

Automatically map a Contact to an Account

I want to add a field to Accounts which shows the email domain for that account e.g. #BT.com. I then have a spreadsheet which lists all the Accounts and their email domains. What I want to do is when a new Contact is added to Dynamics that it checks the spreadsheet for the same email domain (obviously without the contacts name in the email) and then assigned the Contact to the Account linked to that domain. Any idea how I would do this. Thanks
Probably best chance would be to develop CRM plugin. Register your plugin to be invoked when on after contact is created or updated (so called post-event phase). And in your plugin update the parentaccountid property of the contact entity to point to account of your choice.
Code-wise it goes something like (disclaimer: not tested):
// IPluginExecutionContext context = null;
// IOrganizationService organizationService = null;
var contact = (Entity)context.InputParameters["Target"];
var email = organizationService.Retrieve("contact", contact.Id, new ColumnSet("emailaddress1")).GetAttributeValue<string>("emailaddress1");
string host;
try
{
var address = new MailAddress(email);
host = address.Host;
}
catch
{
return;
}
var query = new QueryExpression("account");
query.TopCount = 1;
// or whatever the name of email domain field on account is
query.Criteria.AddCondition("emailaddress1", ConditionOperator.Contains, "#" + host);
var entities = organizationService.RetrieveMultiple(query).Entities;
if (entities.Count != 0)
{
contact["parentaccountid"] = entities[0].ToEntityReference();
}
organizationService.Update(contact);
I took Ondrej's code and cleaned it up a bit, re-factored for pre-operation. I also updated the logic to only match active account records and moved the query inside the try/catch. I am unfamiliar with the MailAddress object, I personally would just use string mapping logic.
var target = (Entity)context.InputParameters["Target"];
try
{
string host = new MailAddress(target.emailaddress1).Host;
var query = new QueryExpression("account");
query.TopCount = 1;
// or whatever the name of email domain field on account is
query.Criteria.AddCondition("emailaddress1", ConditionOperator.Contains, "#" + host);
query.Criteria.AddCondition("statecode", ConditionOperator.Equals, 0); //Active records only
var entities = organizationService.RetrieveMultiple(query).Entities;
if (entities.Count != 0)
{
target["parentaccountid"] = entities[0].ToEntityReference();
}
}
catch
{
//Log error
}

Visual Studio Online SDK

I am working on a project where I have a requirement to create workitem on Visual Studio Online instance. I am using personal access token. This will set CreatedBy as my name (Expected behavior). I am considering to use Oauth2; However, I am not sure if there's the way to do this Server-to-Server (Non-Interactive)? Any suggestions thoughts?
var personalAccessToken = "PAT Value fro Config";
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalAccessToken))));
return client;
PAT's are created in Security context of the user. I need to find a way to use Oauth without having to involved UI. So I'm looking for Server-to-Server Auth.
object[] patchDocument = new object[5];
patchDocument[0] = new { op = "add", path = "/fields/System.Title", value = bugTitle };
patchDocument[1] = new { op = "add", path = "/fields/Microsoft.VSTS.TCM.ReproSteps", value = bugReproSteps };
patchDocument[2] = new { op = "add", path = "/fields/Microsoft.VSTS.Common.Priority", value = "1" };
patchDocument[3] = new { op = "add", path = "/fields/Microsoft.VSTS.Common.Severity", value = "2 - High" };
patchDocument[4] = new { op = "add", path = "/fields/System.IterationPath", value = deserializeIteration };
//System.IterationPath
string postUrl = $"{_vsoInstanceUrl}/DefaultCollection/ProjectName/_apis/wit/workitems/$Bug?api-version=1.0";
await ExecutePatch(patchDocument.ToArray(), postUrl, "application/json-patch+json");
No there is no Server-to-Server OAuth support. If you use the .NET Client Object Model you can leverage Impersonation support.
If your account has "Act on behalf of others" permissions you can also achieve a "User X via YourAccount".

save smtp sent mail in outlook sent folder using outlook add in

I would like to send smtp send mail from outlook-addin that mail save into outlook sent folder
Note: Save mail item in sent folder from address must be which i specified smtp from address not outlook login username.
public bool SendEMail()
{
MailMessage mailNew = new MailMessage();
var smtp = new SmtpClient("SmtpServer")
{
EnableSsl = false,
DeliveryMethod = SmtpDeliveryMethod.Network
};
smtp.Port = 587;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.UseDefaultCredentials = false;
System.Net.NetworkCredential credentials =
new System.Net.NetworkCredential("UserName", "password");
smtp.EnableSsl = false;
smtp.Credentials = credentials;
MailAddress mailFrom = new MailAddress("clark#gmail.com");
mailNew.From = mailFrom;
mailNew.To.Add("someone#gmail.com");
mailNew.Subject = Subject;
mailNew.IsBodyHtml = Html;
mailNew.Body = Body;
smtp.Send(mailNew);
return true;
}
thanks in advance
You will need to create a sent item in the Sent Items folder and set all the relevant properties using MailItem.PropertyAccessor. Note that PropertyAccessor will not let you set some sender related properties. In Outlook 2010 or higher you can set the MailItem.Sender property.
Also note that the sent flag cannot be changed after the message is saved, so to create a sent item using OOM, you will need to create a post item, then change its MessageClass property to "IPM.Note".
Also note that ReceivedTime and SentOn properties are reset by OOM every time the message is saved.
If using Redemption is an option (I am its author), you can do something like the following (off the top of my head):
Redemption.RDOSession session = new Redemption.RDOSession();
session.MAPIOBJECT = Application.Session.MAPIOBJECT;
Redemption.RDOMail message = session.GetDefaultFolder(rdoDefaultFolders.olFolderSentMail).Items.Add("IPM.Note");
message.Sent = true;
message.Subject = "test";
message.Body = "fake sent message";
message.Recipients.AddEx("The Recipient", "recipient#domain.com", "SMTP", olTo);
string senderEntryID = session.AddressBook.CreateOneOffEntryID("Some Name", "SMTP", "user#domain.com", false, true);
addressEntry = session.AddressBook.GetAddressEntryFromID(senderEntryID);
message.Sender = addressEntry;
message.SentOnBehalfOf = addressEntry;
message.Save();

EWS Managed API : Checking Responses

I'm using EWS Managed API 2.0. I'm using the Calendaring part where you can book appointments as follows :
Appointment appointment = new Appointment(service);
//Set properties on the appointment.
appointment.Subject = "Dentist Appointment";
appointment.Body = "The appointment is with Dr. Smith.";
appointment.Start = new DateTime(2009, 3, 1, 9, 0, 0);
appointment.End = appointment.Start.AddHours(2);
//Save the appointment.
appointment.Save(SendInvitationsMode.SendToNone);
How can I using the API check the status of the booking and whether it was booked or not due to a conflict in the date (Success/Error/Conflict)? right now I'm able to check this through the outlook, but I'd like to know this information from the API. I've looked into the API documentation but I couldn't find anything.
Appreciate your help/guidance.
You should first check the availability of all attendees before saving your appointment. AvailabilityData will return you Result (ServiceResult.Success, ServiceResult.Warning, or ServiceResult.Error) and further you can check ErrorMessage property to find proper return message for each conflicting availability. If availability is not conflicting for any of the attendees, you can save your Appointment object.
AvailabilityOptions availabilityOptions = new AvailabilityOptions();
availabilityOptions.MeetingDuration = 60;
availabilityOptions.MaximumNonWorkHoursSuggestionsPerDay = 4;
availabilityOptions.MinimumSuggestionQuality = SuggestionQuality.Good;
availabilityOptions.RequestedFreeBusyView = FreeBusyViewType.FreeBusy;
List<AttendeeInfo> attendees = new List<AttendeeInfo>();
attendees.Add(
new AttendeeInfo()
{
SmtpAddress = "org#acme.com",
AttendeeType = MeetingAttendeeType.Organizer
});
attendees.Add(
new AttendeeInfo()
{
SmtpAddress = "at1#acme.com",
AttendeeType = MeetingAttendeeType.Required
});
attendees.Add(
new AttendeeInfo()
{
SmtpAddress = "room1#acme.com",
AttendeeType = MeetingAttendeeType.Room
});
GetUserAvailabilityResults availabilityResults =
service.GetUserAvailability(
attendees,
new TimeWindow(DateTime.Now, DateTime.Now.AddDays(1)),
AvailabilityData.FreeBusyAndSuggestions,
availabilityOptions
);
// Here check the availability Result and ErrorMessage of each attendees
// availabilityResults.AttendeesAvailability[0].Result
// availabilityResults.AttendeesAvailability[0].ErrorMessage
// ServiceResult.Success
// ServiceResult.Warning
// ServiceResult.Error

Resources