C# google contact api deleted contact - c#

currently I´m writing on a outlook plugin for syncing goolge contacts with outlook but I have to cover some special case:
When a contact gets deleted on google side, my application detects the missing contact and creates a new contact based on the contact info from the outlook one.
Is there a way to get an event or history from google that tells me a user deleted this contact(s)?
Edit 1:
Here is my code how I´m accessing the contacts (what is working FINE):
public GoogleAccessor()
{
var parameters = new OAuth2Parameters()
{
ClientId = CLIENTID,
ClientSecret = CLIENTSECRET,
RedirectUri = REDIRECTURI,
Scope = SCOPES
};
string url = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
//An own webbrowser for processing the access tokens
IAuthorizationCodeProvider authcodeProvider = new Presentation.BrowserAuthorizationCodeProvider(new Presentation.BrowserAuthentificatorVM());
parameters.AccessCode = authcodeProvider.GetAuthorizationCode(url);
if(parameters.AccessCode == null)
throw new GoogleOAuthException("AccesCode returned 'null' and failed!");
OAuthUtil.GetAccessToken(parameters);
this._contactsRequest = new ContactsRequest(new RequestSettings(APPLICATIONNAME, parameters) {AutoPaging = true});
}
public IList<IContact> GetAllMappedContacts()
{
Feed<Google.Contacts.Contact> f = _contactsRequest.GetContacts();
this._feedUri = new Uri(f.AtomFeed.Feed);
var photoList = new List<PhotoObject>();
foreach (var entry in f.Entries)
{
var photoObject = GetContactPhoto(entry);
if(photoObject != null)
photoList.Add(photoObject);
}
_googleMapper = new GoogleMapper(f.Entries);
return _googleMapper.MapToLocalContacts();;
}

The thing about syncing in general is that syncing is normally meant to work in one direction.
Source Data -> Data Flow -> Received Data.
In this instance, Outlook is your source data and Google is your received data. All information needs to come from your source. Since this is an Outlook add-in you are creating my suggestion would be to add a button to your add-in ribbon. You can call the button whatever ever you like (maybe "dontSyncButton"), but it's purpose is going to be Categorization of your contact.
Make it so that that when a contact is selected and then the button is clicked, the contact is given a special categorization (perhaps "Dont Sync").
Now give some logic to your code that executes the sync, and have that logic decide whether to sync the contact. Also, give some logic to tell the program to delete the contact out of Google for you if the contacts contains the special category. Semi-Pseudo Code below:
if(contact.Categories.ToString() == "Dont Sync")
{
//Don't Sync Contact
If(googleContact.Exists())
{
//Delete contact from Google if it exist
googleContact.Delete();
}
}
else
{
//Sync Contact
}
It would be nice if Outlook had many modifiable properties that weren't visible to users, but since it does not this is really one of the best options I can think of. I do this to sync contacts from a shared Outlook folder to personal ones and it has worked well so far.
Hope this helps!

Related

Remove user from folder permission using MS Graph

We have a C# application that is using the Microsoft Graph API to display the contents of SharePoint folder to users in a Syncfusion FileManager control. We need to grant permissions to those folders for certain users in order that they can collaborate on files.
We can add specific users using the sharing invitation to add a permission (see https://learn.microsoft.com/en-us/graph/api/driveitem-invite?view=graph-rest-1.0&tabs=http). We also need to be able to remove a user from this permission without deleting the whole link (and therefore any other users using it). I cannot see a way of doing this!
I have also tried using CreateLink (see https://learn.microsoft.com/en-us/graph/api/driveitem-createlink?view=graph-rest-1.0&tabs=http) but get an ‘Invalid Request’ error when trying to ‘Grant’ permission to a user and therefore never get as far as trying to remove an individual user!. The code I am using to try and 'Grant' permission is as follows (the last line produces the error):
public object CreateSharingLink(string itemId, List<string> recipientList, List<string> roles)
{
if (itemId == null) return null;
var type = "edit";
var scope = "organization";
Permission p = GraphClient.Drives[documentLibrary.Id].Items[itemId].CreateLink(type, scope).Request().PostAsync().Result;
return GrantAccessToSharingLink(p.Link.WebUrl, recipientList, roles);
}
public object GrantAccessToSharingLink(string sharingUrl, List<string> recipientList, List<string> roles)
{
List<DriveRecipient> recipients = (recipientList.Select(r => new DriveRecipient { Email = r })).ToList();
string base64Value = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(sharingUrl));
string encodedUrl = "u!" + base64Value.TrimEnd('=').Replace('/', '_').Replace('+', '-');
return GraphClient.Shares[encodedUrl].Permission.Grant(roles, recipients).Request().PostAsync().Result;
}
Any assistance would be much appreciated.
A similar question was asked a while ago but without an answer. Remove GrantedTo user from Permission using Graph API
You can delete only not inherited permissions. Only sharing permissions that are not inherited can be deleted. Here's the related doc.

EWS Extended Properties between accounts

we have encountered a problem with recognizing and setting ExtendedProperties by EWS. Right now, we have the functionality to import emails, which can be done either manually by user or a separate service. There seems to be inconsistency with how Exchange searches through ExtendedProperties and how they are set.
To clarify, I have three mailboxes attached to Outlook application. One is mine and two are the test accounts, which are linked to my AD account. The test accounts contain emails which are imported by the automatic service(when a mail is sent to one of them, it is imported to our application and there is set and ExtendedProperty on the email, providing the information that the email was imported).
What is strange, on my side, in Outlook Add-in, on one account the emails are properly marked and on the other it is not happening as it should, despite that the mechanism is the same.
These are the codes of our add-in.
This is the code of retrieving emails:
private static IEnumerable<EmailMessage> GetEmails(Microsoft.Exchange.WebServices.Data.Folder folder, int pageSize, DateTime lastImport)
{
SearchFilter filter = PrepareFilter(lastImport);
List<Item> foundItems = new List<Item>();
Guid propertySetId = new Guid("F723C954-3F83-46AA-A783-FDEAC90AE512");
ExtendedPropertyDefinition registered = new ExtendedPropertyDefinition(propertySetId, "Registered", MapiPropertyType.Boolean);
ItemView view = new ItemView(pageSize);
view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties, registered);
foundItems = service.FindItems(folder.Id, filter, view).Items.ToList();
List<EmailMessage> results = new List<EmailMessage>();
foreach (EmailMessage message in foundItems)
{
results.Add(message);
}
return results;
}
private static SearchFilter PrepareFilter(DateTime lastImport)
{
Guid propertySetId = new Guid("F723C954-3F83-46AA-A783-FDEAC90AE512");
ExtendedPropertyDefinition Registered= new ExtendedPropertyDefinition(propertySetId, "Registered", MapiPropertyType.Boolean);
SearchFilter isRegistered = new SearchFilter.IsEqualTo(registered, true);
return isRegistered;
}
And this is the flag setting method written by my colleague:
public static bool SetExchangeRegistered(List<MailItem> mailsToRegister)
{
try
{
var service = new Exchange.ExchangeService(Exchange.ExchangeVersion.Exchange2010)
{
UseDefaultCredentials = true
};
var emailAddress = new Application().ActiveExplorer().Session.CurrentUser.AddressEntry.GetExchangeUser().PrimarySmtpAddress;
service.AutodiscoverUrl(emailAddress);
foreach (var mail in mailsToRegister)
{
string itemId = ConvertHexEntryIdToEwsId(service, mail.EntryID, emailAddress);
Exchange.EmailMessage message = Exchange.EmailMessage.Bind(service, new Exchange.ItemId(itemId));
bool propertyRegisteredExists =
message.ExtendedProperties.FirstOrDefault(x => x.PropertyDefinition.Name == "Registered") != null;
if (!propertyRegisteredExists)
{
Guid propertySetId = new Guid("F723C954-3F83-46AA-A783-FDEAC90AE512");
Exchange.ExtendedPropertyDefinition registered =
new Exchange.ExtendedPropertyDefinition(propertySetId, "Re", Exchange.MapiPropertyType.Boolean);
message.SetExtendedProperty(registered, true);
}
else
{
message.ExtendedProperties.First(x => x.PropertyDefinition.Name == "Registered").Value = true;
}
message.Update(Exchange.ConflictResolutionMode.AlwaysOverwrite);
}
}
catch (Exception ex)
{
grmtAddInBase.Logger.Trace(string.Format("Registered update failed: {0}", ex.Message));
return false;
}
grmtAddInBase.Logger.Trace("Email property 'Registered' updated successfully");
return true;
}
Generally, the method above seems to be identical in control flow to the method which is implemented in the separate service, and it seems that it actually does set the ExtendedProperty of the email correctly.
Another clue, which, to be honest, leaves me clueless, is that even when I tried to get all the emails greedily, load it and then separate the correct ones by their ExtendedProperty which we set... The problem then is that for some emails(i.e. inside one of the mailboxes which are treated by the autoimport service) it sees the Properties correctly and for the rest(i.e. my own mailbox) it doesn't even load and ExtProps, which means that it probably does not see them at all.
I have also tried to use DefaultExtendedPropertySet.PublicStrings, but then it didn't work at all.
I am a little bit puzzled and nobody in close proximity or EWS docs/MS Forums could provide the answer. I am aware that there may be no help, I am aware of the possibility that we are just hopelessly stupid and made some mistake which we cannot find.
After a while, the emails on Exchange mailboxes are just copies - that would be reasonable reason why we cannot access the ExtendedProperties of the email that we received, when it's "flag" was set by another user. But, maybe there is a way to synchronize those properties between those mailboxes? Because there are some alternatives already that we will discuss, but it would be nice if at least part of the current solution could be reused.

Firebase data - error converting value

I have posted question regarding firebase two days ago:
Android Firebase - add authenticated user into database
I got help that I needed and that solved first problem. But now I have a new problem. I was googling for quite some time, there are some posts about this issue but nothing solved my problem. I din't want to spam the previous question so I posted a new one.
When I try reading inserted data from the firebase database I get this error:
Newtonsoft.Json.JsonSerializationException: Error converting value
"test#user.com" to type 'carServiceApp.My_Classes.Account'. Path
'email', line 1, position 24.
Here is the code:
private async Task LoadData()
{
FirebaseUser users = FirebaseAuth.GetInstance(loginActivity.app).CurrentUser;
id = users.Uid;
var firebase = new FirebaseClient(loginActivity.FirebaseURL);
var items = await firebase.Child("users").Child(id).OnceAsync<Account>();
foreach (var item in items)
{
Account user = new Account();
user.uid = item.Object.uid;
user.name = item.Object.name;
user.lastName = item.Object.lastName;
user.phone = item.Object.phone;
user.email = item.Object.email;
userInput_ime.Text = user.name;
userInput_prezime.Text = user.lastName;
userInput_broj.Text = user.phone;
userInput_email.Text = user.email;
}
}
This is firebase data:
-users
-jwAP2dYNzJeiF3QlmEIEQoruUkO2
email: "test#user.com"
lastName: "user"
name: "test"
phone: "12421"
uid: "jwAP2dYNzJeiF3QlmEIEQoruUkO2"
Interesting thing is that when I try reading data with this:
var items = await firebase.Child("users").OnceAsync<Account>();
This works fine (I get last inserted user) . But when I add 'uid' node, then I get error. I was trying to solve this for quite some time but I just can't figure it out. I guess that there is no problem with the account class because it works in the case without uid node but doesn't work when another child() method is added.
Other information (Account class code and the way of storing that data into the database) you can see in the link at the top.
Note: I tried adding constructor in Account class but that doesn't help.
Ok, so I didn't exactly find a solution for this problem nor do I really understand why was this happening but I have found a workaround. I believe it's not ideal solution and that it does not fix existing problem. Or maybe it was problem with me not understanding firebase logic but here is what I came up with.
So, considering that it was all working fine if I didn't specify that uid node it was obvious there was some problem with class and data in firebase, matching problem I guess. Anyway, I decided to have that last uid node so I can have specific user selected and also to have the same data in firebase as it was in case where it was all working. So, this is how I have inserted data into firebase:
var item = firebase.Child("users").Child(id).PostAsync<Account>(user);
This created users node and child node. And PostAsync method created one more node with random key.
So when I tried reading with this:
var data = await firebase.Child("users").Child(id).OnceAsync<Account>();
It worked without problem. Now firebase data looks like this:
users
JPKdQbwcXbhBatZ2ihBNLRauhV83
-LCXyLpvdfQ448KOPKUp
email: "spider#man.com"
lastName: "man"
name: "spider"
phone: "14412"
uid: "JPKdQbwcXbhBatZ2ihBNLRauhV83"
There is a bit of redundancy, I basically have two ID's, but I don't understand how to create my class so I can get that data any other way so I made it this way. It works fine.
If anyone has better solution, I will gladly change it. Cheers
This was suppose to be a comment, but this is just suppose to be an addition for anyone that needs help with this issue.
I know that this answer has been out there for a while but this still seems to be a running structural quirk with Firebase and the usage of their rules. I ran into this issue with a complex structure that looked kind of like this
-Orders
-9876trfghji (User ID)
-0
BusnID: "ty890oihg"
Name: "Some Name"
AddOns: Object
ItemData: Object(containing other objects)
UserID: "9876trfghji"
Note: In this case as well as the case with cordas, you will see that both of the final objects has a UserID or uid.
I also was running into the issue of class de-serialization of the object without having the actual User ID in the objects data when it was being sent back to the device.
The reason that you have a “redundant” usage of the user id is for a security measure with the Firebase rules. The first UserID with the structure above you are able to control the access to the information based off of the users id without having to have an extra validation clause in the rules. Currently as of this post the the rule below would protect the data based on the User ID.
“Orders” : {
"$uid":{
".read":"auth != null",
".write":"auth.uid == $uid"
}
}
this allows the user with only the authorized user id to write content but anyone that has valid credentials can view the data.
The second User ID has to be placed in the object because without it you would not be able to do a standard cast to the object because your object would not have all of the data it would need to create the object. Regardless of if you are using a package like GoogleGson or Newtonsoft.Json the object still isn't full.
There is how ever a work around for this problem besides re-entering the User ID into the object. With the object that I have above I decided to just re-enter the User ID in my personal code to save the time and hassle of manual creation.
Using the Firebase.Database NuGet package you can manually create the object. Here is an example of the object in cordas problem
public static void GetUser_Firebase(User user, FirebaseApp app)
{
FirebaseDatabase database = FirebaseDatabase.GetInstance(app);
DatabaseReference reference = database.GetReference($"/users/{user.UserID}");
//"Using for getting firebase information", $"/users/{user.UserID}"
reference.AddListenerForSingleValueEvent(new UserInfo_DataValue());
}
class UserInfo_DataValue : Java.Lang.Object, IValueEventListener
{
private string ID;
public UserInfo_DataValue(string uid)
{
this.ID = uid;
}
public void OnCancelled(DatabaseError error)
{
//"Failed To Get User Information For User "
}
public void OnDataChange(DataSnapshot snapshot)
{
Dictionary<string, string> Map = new Dictionary<string, string>();
var items = snapshot.Children?.ToEnumerable<DataSnapshot>(); // using Linq
foreach(DataSnapshot item in items)
{
try
{
Map.Add(item.Key, item.Value.ToString()); // item.value is a Java.Lang.Object
}
catch(Exception ex)
{
//"EXCEPTION WITH DICTIONARY MAP"
}
}
User toReturn = new User();
toReturn.UserID this.ID;
foreach (var item in Map)
{
switch (item.Key)
{
case "email":
toReturn.email = item.Value;
break;
case "lastName":
toReturn.lastName = item.Value;
break;
case "name":
toReturn.name = item.Value;
break;
case "phone":
toReturn.phone = item.Value;
break;
}
}
}
}
Update
There is something that I would like to mention that I left out when I was writing this and that is the usage of Firebase.Database NuGet package with the Gson NuGet package and the Newtonsoft.Json Library
If you decide to use the FIrebase.Database library just know that you will be working very close with the Java.Lang and the Java.Util libraries. Objects like Java.Lang.Object can be very difficult and time consuming to write the code needed to de-serialize the data, but don't fear Gson is here!
The Gson package if you allow it can take a large load of work off of your hands for class de-serialization if you allow it. Gson is a library that will allow you to do Java.Lang.Obj to json string de-serialization. I know it seems weird, hand it an object get back a string sounds counter intuitive I know but just bear with me.
Here is an example of how to us the Gson Library with the object in cordas problem.
public static void Get_User(User user, FirebaseApp app)
{
FirebaseDatabase database = FirebaseDatabase.GetInstance(app);
DatabaseReference reference = database.GetReference($"Users/{user.UserID}");
reference.AddListenerForSingleValueEvent(new User_DataValue(user, app));
//$"Trying to make call for user orders Users/{user.UserID}");
}
class User_DataValue : Java.Lang.Object, IValueEventListener
{
private User User;
private FirebaseApp app;
public UserOrderID_Init_DataValue(User user, FirebaseApp app)
{
this.User = user;
this.app = app;
}
public void OnCancelled(DatabaseError error)
{
//$"Failed To Get User Orders {error.Message}");
}
public void OnDataChange(DataSnapshot snapshot)
{
//"Data received for user orders");
var gson = new GsonBuilder().SetPrettyPrinting().Create();
var json = gson.ToJson(snapshot.Value); // Gson extention method obj -> string
Formatted_Output("Data received for user order json ", json);
User user = JsonConvert.DeserializeObject<User>(json); //Newtonsoft.Json extention method string -> object
//now the user is a fully populated object with very little work
}
For anyone that might run into this in the future I hope that this helps

QuickBooks Online API: Newly created customer has status of deleted

I am running into an issue where items I am creating are being set to deleted and not showing up in QBO.
Here is my code:
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(
accessToken, accessTokenSecret, GetApiConsumerKey(), GetApiConsumerKeySecret());
ServiceContext context = new ServiceContext(GetApiAppToken(),
realmID, IntuitServicesType.QBO, oauthValidator);
context.IppConfiguration.BaseUrl.Qbo = "https://sandbox-quickbooks.api.intuit.com/";
context.IppConfiguration.Message.Request.SerializationFormat = SerializationFormat.Json;
context.IppConfiguration.Message.Response.SerializationFormat = SerializationFormat.Json;
DataService dataService = new DataService(context);
Customer customer = new Customer();
customer.Active = true;
customer.GivenName = "Test";
customer.DisplayName = "Test";
customer.WebAddr = new WebSiteAddress();
customer.WebAddr.URI = "http://www.google.com";
customer = dataService.Add<Customer>(customer);
if (customer.status == EntityStatusEnum.Deleted)
{
// Gets to here every time.
}
Can anyone see what might be going wrong here that causes every created entity to be deleted? I also can't find them using search in the QBO UI.
EDIT
As requested, I am adding the JSON data being sent/recieved:
{// Sent JSON
"GivenName":"Martin",
"FamilyName":"Noreke",
"DisplayName":"Martin Noreke",
"WebAddr":{"URI":"http://www.google.com"}
}
{// Received JSON
"Customer":{
"Taxable":true,
"Job":false,
"BillWithParent":false,
"Balance":0,
"BalanceWithJobs":0,
"CurrencyRef":{"value":"USD","name":"United States Dollar"},
"PreferredDeliveryMethod":"Print",
"domain":"QBO",
"sparse":false,
"Id":"68",
"SyncToken":"0",
"MetaData":{"CreateTime":"2015-07-19T08:25:22-07:00","LastUpdatedTime":"2015-07-19T08:25:22-07:00"},
"GivenName":"Martin",
"FamilyName":"Noreke",
"FullyQualifiedName":"Martin Noreke",
"DisplayName":"Martin Noreke",
"PrintOnCheckName":"Martin Noreke",
"Active":true,
"WebAddr":{"URI":"http://www.google.com"},
"DefaultTaxCodeRef":{"value":"2"}},
"time":"2015-07-19T08:25:22.958-07:00"
}
From the JSON, it appears to be creating the customer correctly. However, I am not able to locate it in the sandbox account I am connecting to.
This is where I get to post the self deprecating story about how I wasn't paying attention.
While working with the API, I somehow created a second company. Even when clicking on the first company, Intuit remembers your last company and takes you straight there.
Using the gear menu to switch companies allowed me to get to the right company so that I could see my created data.
I feel quite silly right now... :/

CRM 2011 update incident when email arrives

In CRM when emails arrive and have the tracking token in them they automatically set the regarding field to be the incident (or whatever they relate to)
Unfortunately the Record wall isn't updated with this info so even if you are following the case nothing alerts you to the new activity.
I want to write a plugin on email or incident (or both) that updates the record wall and creates a task to follow up on that email with in 3 days.
I'm looking at the SDK and I can't see what the appropriate event in the pipe line would be to work out when an email is/has its regarding field set on arrival in the CRM.
The CRM email creation life-cycle is not well described in the documentation. [shakes fist]
Extra things that are bothering me
I can't seem to include a reference to get a strongly typed Email, Post or Case (driving me crazy)
Testing this is really hard (harder than it should be)
EDIT Here is my current code
namespace Assembly.Plugins
{
using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
/// <summary>
/// PostEmailDeliverIncoming Plugin.
/// </summary>
public class PostEmailDeliverIncoming : Plugin
{
/// <summary>
/// Initializes a new instance of the <see cref="PostEmailDeliverIncoming"/> class.
/// </summary>
public PostEmailDeliverIncoming()
: base(typeof(PostEmailDeliverIncoming))
{
RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(40, "DeliverIncoming", "email", ExecutePostEmailDeliverIncoming));
// Note : you can register for more events here if this plugin is not specific to an individual entity and message combination.
// You may also need to update your RegisterFile.crmregister plug-in registration file to reflect any change.
}
protected void ExecutePostEmailDeliverIncoming(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService = localContext.TracingService;
// Obtain the execution context from the service provider.
IPluginExecutionContext context = localContext.PluginExecutionContext;
// Obtain the organization service reference.
var service = localContext.OrganizationService;
// The InputParameters collection contains all the data passed in the message request.
if (!context.InputParameters.Contains("Target") || !(context.InputParameters["Target"] is Entity))
return;
// Obtain the target entity from the input parmameters.
var target = (Entity)context.InputParameters["Target"];
// Verify that the target entity represents an account.
// If not, this plug-in was not registered correctly.
if (target.LogicalName != "email")
return;
if((string)target["direction"] != "Incoming")
return;
if (target["regardingobjectid"] == null)
return;
try
{
// if its not a case I don't care
var incident = service.Retrieve("incident", (Guid)target["regardingobjectid"], new ColumnSet(true));
if (incident == null)
return;
var post = new Entity("post");
post["regardingobjectid"] = target["regardingobjectid"];
post["source"]=new OptionSetValue(0);
post["text"] = String.Format("a new email has arrived.");
// Create the task in Microsoft Dynamics CRM.
tracingService.Trace("FollowupPlugin: Creating the post.");
service.Create(post);
// Create a task activity to follow up with the account customer in 7 days.
var followup = new Entity("task");
followup["subject"] = "Follow up incoming email.";
followup["description"] = "An email arrived that was assigned to a case please follow it up.";
followup["scheduledstart"] = DateTime.Now.AddDays(3);
followup["scheduledend"] = DateTime.Now.AddDays(3);
followup["category"] = context.PrimaryEntityName;
// Refer to the email in the task activity.
if (context.OutputParameters.Contains("id"))
{
var regardingobjectid = new Guid(context.OutputParameters["id"].ToString());
followup["regardingobjectid"] = new EntityReference("email", regardingobjectid);
}
// Create the task in Microsoft Dynamics CRM.
tracingService.Trace("FollowupPlugin: Creating the task activity.");
service.Create(followup);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in the FollupupPlugin plug-in.", ex);
}
catch (Exception ex)
{
tracingService.Trace("FollowupPlugin: {0}", ex.ToString());
throw;
}
}
}
}
I've just been fighting with this exact same issue and came across this post. I thought I'd post the solution for you (if you still need it) and anyone else who comes across the issue in the future.
Here's the solution I arrived at:
- Using the Plugin Registration Tool register a New Image on the appropriate step( Stage = "40", MessageName = "DeliverIncoming")
- Set the New Image to be a Post Image
- In your plugin fetch the Post Image's entity ID:
Guid emailID = context.PostEntityImages["PostImage"].Id;
Entity emailFromRetrieve = localContext.OrganizationService.Retrieve(
"email",
emailID,
new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
Email email = emailFromRetrieve.ToEntity<Email>();
if (email.RegardingObjectId == null)
{
return;
}
var regardingObject = email.RegardingObjectId;
Hope this helps!
I'm actually working on a very similar plugin at the moment. Mine creates a custom entity upon arrival of an email addressed to a certain email address. It also associates the incoming email with that new record via the Regarding field. I've added a Pre-Operation step on Create of Email and it works great, including incoming email from the router.
What I'm not sure of is when CRM fills in the Regarding field. You might look at Post-Operation and see if it is set there?
One interesting caveat regarding the Regarding field (haha!): Unlike single lookup fields, the Regarding object's name is actually stored in the ActivityPointer table, so when you update the Regarding field, be sure to set the Name on the EntityReference. If you don't, the Regarding lookup will still have a clickable icon but there won't be any text. I do it like this:
email.RegardingObjectId = [yourentity].ToEntityReference();
email.RegardingObjectId.Name = email.Subject;
Hope that helps!
I ended up doing this in a workflow on the email entity
Steps
Create new workflow, I called it 'incoming email workflow'
Scope is Organisation
Choose Email as the entity and check 'Record field changes'
Add a step that checks Regarding (Case):Case Contains Data
if true:
Add a step that creates a Post
Edit the properties in the Post
Text : This case has had {Direction(E-mail)} email activity from {From(E-mail)}
Source : Auto Post
Regarding : {Regarding(E-mail)}
Add a step that creates a Task
Edit the properties in the Task
Subject : Follow up {Subject(E-mail)}
Regarding : {Regarding(E-mail)}
Try to use the following code:
if ((bool)entity["directioncode"] == false)
Instead of your code:
if((string)target["direction"] != "Incoming")

Categories

Resources