How to stop meeting being stripped on forward (EWS) - c#

I am using C# with the Exchange Web Service (EWS).
I have meetings that I need to forward and whenever I do they get stripped, but only from some accounts and not others. The link for the meeting is still there but it is not being recognised by the online Outlook as a meeting item, nor by Teams which is connected to the account.
This even happens if I manually forward, but again only if I forward emails that are from some accounts - some other accounts are fine!
I'm using this on incoming emails:
var fwdEmailArr = new EmailAddress[1];
fwdEmailArr [0] = fwdEmail;
MeetingRequest appointment = MeetingRequest.Bind(service, email.Id);
appointment.Forward("", fwdEmailArr);
This is the same issue if I use the email.forward as well, etc.
However, if I create a new appointment and send it, it doesn't get stripped - this is with the same addresses.
Appointment appt = new Appointment(service);
appt.Subject = email.Subject;
appt.Body = appointment.Body;
appt.Start = appointment.Start;
appt.End = appointment.End;
appt.Location = appointment.Location;
appt.RequiredAttendees.Add(fwdEmail);
foreach (var reqAtt in appt.RequiredAttendees)
{
appt.RequiredAttendees.Add(reqAtt);
}
foreach (var reqAtt in appt.OptionalAttendees)
{
appt.OptionalAttendees.Add(reqAtt);
}
appt.RequiredAttendees.Add(appointment.From.Address);
appt.Save(SendInvitationsMode.SendToAllAndSaveCopy);
So, I could do this but it means that they are no longer the same meeting and declining the original wont decline this. Unless there's a way I can connect the meetings or something?
Any ideas how I can stop the meeting being stripped?
Or alternatively just add another recipient to the current meeting, that will show on their calendar?

If anyone comes here with a similar issue, it turns out that, first of all you need to make sure you define the correct server version on the service declaration:
service = new ExchangeService(ExchangeVersion.Exchange2016){}
In addition, for some reason some images when attached to the forwarded email for some reason confuse EWS and make it think there's no meeting. I got around this by scanning the MIME content and just extracting the calendar block and deleting all other attachments.
This has been working flawlessly for about 5 months.

Related

Getting display name from EWS when passing in just an email address

I've using a custom GetMailTips SOAP call (since the EWS for Core 2.0 doesn't support it) to get Out of Office info for a batch of email addresses.
How can I get the display names of the users that I am passing in the email address for?
I can call ResolveName of the managed API and that works but it has to be done one at a time and that is slow. I would like to ideally get this info out when I make my GetMailTips request and failing that make a call with all the email addresses to get the Display Names all at once. I read there is meant to be a ResolveNames method but that's not in the API either.
Any help appreciated
Autodiscover can return that for multiple users eg
AutodiscoverService adService = new AutodiscoverService(ExchangeVersion.Exchange2013_SP1);
adService.Credentials = new NetworkCredential("user#d.com", "pass");
adService.RedirectionUrlValidationCallback = adAutoDiscoCallBack;
List<String> Users = new List<string>();
Users.Add("user1#domain.com");
Users.Add("user2#domain.com");
GetUserSettingsResponseCollection usrSettings = adService.GetUsersSettings(Users, UserSettingName.UserDisplayName);
foreach(GetUserSettingsResponse usr in usrSettings)
{
Console.WriteLine(usr.Settings[UserSettingName.UserDisplayName]);
}
Another way would be to create a Message and add the email address as recipients then save it to the drafts folders and the address should get resolved against the GAL.

EWS: Exchange Items not available right after Update

I'm working on a project to sync calendar items from specific Exchange users to another application and back. In the other application there are meetings, too. My problem in several parts of my project is that I want to add attendees to the appointment, then get the appointment with the credentials of the attendee and accept it. But when I want to check bind the new appointment immediatly after updating the appointment there is no Item with the iCalUid in the folder. When I wait 2000ms after updating the meeting request is there but I don't think this is best practice. I have a short code sample:
string attendeeAddress = "mymailaddress";
ExchangeService service =
new ExchangeService(ExchangeVersion.Exchange2013)
{
Url = new Uri("https://exchange.sample.de/EWS/Exchange.asmx"),
Credentials = new WebCredentials("username", "password", "domain")
};
Appointment app = Appointment.Bind(service, id);
app.RequiredAttendees.Add(attendeeAddress);
app.IsResponseRequested = false;
app.Update(ConflictResolutionMode.AutoResolve);
CalendarView view = new CalendarView(app.Start, app.End);
Thread.Sleep(2000);
FindItemsResults<Appointment> attendeeApps =
serviceAttendee.FindAppointments(WellKnownFolderName.Calendar, view);
Appointment appAttendee;
foreach (Appointment a in attendeeApps)
{
if (a.ICalUid.Equals(app.ICalUid))
{
appAttendee = Appointment.Bind(serviceAttendee, a.Id);
}
}
appAttendee.Accept(false);
From the looks of what your doing your adding an attendee to a meeting and then connecting to the attendees Mailbox to accept that meeting ? If that's the case on the backend this is going to produce a Meeting Invitation that will need to be sent via Email and routed to the Attendees Mailbox via the Hub Transport Role. Even if all the recipients and server roles are on the same server you will need to allow time for the message to be delivered to the Attendees Mailbox this is just the normal way Exchange handles Meeting for local (or remote attendees) it will never be instant as Exchange stores each copy of the Appointment as a separate store Item.

get mails in a conversation for exchange mails

I want to retrieve all mails in a conversation when a user selects an email.
I know that I can use this - https://msdn.microsoft.com/en-us/library/office/ff869870(v=office.15).aspx, but for some microsoft exchange accounts, getrootitems returning zero.
So, is there any other way that works for microsoft exchange ?
More details:
My outlook showing "Online with microsoft exchange" at bottom right.
Below process is slow as I have 1000's of mails in inbox, so this wont help me.
IEnumerable mail =
folder.Items.OfType().Where(m => m.Subject == "Test").Select(m => m);
The GetRootItems method of the Conversation class has the following description in MSDN:
If all items are deleted from the conversation after the Conversation object has been obtained, GetRootItems returns a SimpleItems collection with zero objects. In this case, the Count property of the SimpleItems collection returns 0.
Try to use the cached exchange mode instead.

Exchange Web Service (EWS) FindItems does not work if contact is in GAL

I created a small application that gets Contact objects from an external source. Then, depending on some configurations, I have to create/upadate these contacts in a user's contact folder on our exchange server, so that the next time this user opens its MS Outlook, he sees the new contacts (on the exchange server, I have a user with impersonation capabilities, so security is not a concern).
For that, I use the FindItems(folderId, filter, view) method of the EWS library that works good. For the filter, I'm using the user's email address which is quite a good key... If I get a result back, this simply means that the Contact already exist, and that I need to do an update instead of a create. Everything works as expected until here...
BUT, I encounter a problem when the Contact (email address in fact) is already existing in the GAL (Global Address List). In this case, the FindItems method returns no result even if the Contact exists in the folder! It seems (this is a supposition) that the exchange server creates a link for contacts which have an email address that already exist in the GAL and not a new contact. And this could explain why the FindItems method does not return anything in this case. The strange thing is that if I'm filtering on another property (for example on the combination of first and lastname), it works!
Currently, what happens is that for each Contact that already exist in the GAL, a creation instead of an update is done (because the FindItems method returns nothing), and as a result, the same Contact is created X time (instead of beeing created once, and then updated X-1 time).
The question is of course, how can I know if a Contact exists in an exchange folder when it already exists in the GAL?
Current code:
ItemView view = new ItemView(5)
{
PropertySet = new PropertySet(BasePropertySet.FirstClassProperties)
};
SearchFilter f = new SearchFilter.IsEqualTo(ContactSchema.EmailAddress1, email);
FindItemsResults<Item> contactItems = _service.FindItems(folderId, f, view);
int resultCount = contactItems.Count(); // Always 0 if GAL, otherwise it works
Finally, I solved my problem with an extended property by using the SetExtendedProperty method. In this extended field, I just put an Id and that solved the problem.
But that does not explain why the search is not working with an email address... If someone knows the answer, I'm still interested :)
The new search looks like this:
ItemView view = new ItemView(nb);
view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties, _extendedPropDef);
SearchFilter f = new SearchFilter.IsEqualTo(_extendedPropDef, contact.Id);
FindItemsResults<Item> contactItems = _service.FindItems(folderId, f, view);
With this code, everything works as expected...

Can I get only the new Facebook comments since the last time I checked instead of all comments every time?

Right now I have an app that allows a user to schedule/post a Facebook post and then monitor the likes/comments. One of the problems I foresee is that currently I am pulling every single comment/like whether it's been processed or not. What I would like to do instead is be able to say 'Give me all the NEW comments since XYZdate/XYZcomment.' Is this currently possible?
var accessToken = existingUserNode.Attributes["accessToken"].Value;
var facebookAPIMgr = new FacebookWrapper.FacebookAPIManager();
var msg = new FacebookWrapper.FacebookMessage()
{
AccessToken = accessToken,
FacebookMessageId = facebookPost.FacebookMessageId
};
//Get Facebook Message Comments
// Need to find a way to limit this to only new comments/likes
var comments = facebookAPIMgr.RetrieveComments(msg);
You can do time-based pagination as part of your graph API query. If you keep a unix timestamp of when you polled things last, you can simply do https://graph.facebook.com/{whatever}?since={last run}.
This worked when I was working heavily with the Graph API earlier this year, and is still around on the documentation, but considering how much Facebook loves to change stuff without telling anyone you may still encounter problems. So just a warning, YMMV.

Categories

Resources