Reference link :
https://api.cpm.account.microsoft-int.com/swagger/#/
Situation :
- When a new Contact record in created in Microsoft dynamic CRM the email address should go to CPM system.
- When new Email is created/send we need to validate the To email address field in CPM system. If it is valid then bind the unsubscribe link in email body.
Challenges :
- Plugin does not support third party dll’s such as Newtonsoft.dll for json as the API request & response are in json format.
- Plugin does not support Microsoft.IdentityModel.Clients.ActiveDirectory.dll still it is a Microsoft dll as this dll is required for the API request . It throws an exception on runtime if we add a reference in project.
- Not able to figure out Resource in configuration as highlighted below in configuration image.
Requirements :
- On create of Contact record in CRM the contact email address push into CPM system and should check if the record is created from Portal.
- Email Address validation & bind unsubscribe link in email body.
Solution :
Since this dll throws an run time exception we used the Httpwebrequest method to get the Access Token by passing the below configuration as shown in screenshot:
1) Getting the Access Token
To connect to CPM system first we need to get the access token from the API https://login.microsoftonline.com/{TenantId}/oauth2/token. Below is the code to get the access token by using the HttpRequestMessage method.
string loginUrl = $"https://login.microsoftonline.com/{TenantId}/oauth2/token";
clientSecret = System.Uri.EscapeDataString(clientSecret);
HttpClient client = new HttpClient();
string postData = $"client_id={ClientId}&client_secret={clientSecret}&resource={Resource}&grant_type=client_credentials";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, loginUrl);
request.Content = new StringContent(postData);
request.Content.Headers.Remove("Content-Type");
request.Content.Headers.TryAddWithoutValidation("Content-Type", $"application/x-www-form-urlencoded");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var responseMessage = await client.SendAsync(request);
var jsonResponseString = await responseMessage.Content.ReadAsStringAsync();
var jsonContent = jsonResponseString.Deserialize<Dictionary<string, string>>();
accessToken = jsonContent["access_token"];
2) Pushing Contact email address to CPM system.
After getting the access token we can pass this access token to the CPM Api https://api.cpm.account.microsoft-int.com/api/EmailContacts that will push the contact email address to the CPM system.
API Request:
EmailContactPoint emailContactPoint = new EmailContactPoint()
{
email = targetEntity.GetAttributeValue<string>("emailaddress1"),
country = "US",
topicSettings = new List<ContactPointTopicSetting>(),
};
emailContactPoint.topicSettings.Add(new ContactPointTopicSetting
{
TopicId = new Guid("00000000-0000-0000-0000-000000000001"), //Topic ID for which this permission was collected
CultureName = CultureInfo.CurrentCulture.ToString(), //Specify a culture supported by the topic. E.g en-US, fr-FR, fr-CA etc. Communication with the user will be based on this culture;
LastSourceSetDate = DateTime.UtcNow, //The actual time at which this permission was collected. Could be in the past..
OriginalSource = "MSTAPlugin", //Name of this application that collected the consent. Saved for auditing purposes.
State = ContactPointTopicSettingState.OptInExplicit //The permission
});
//cpm api response
EmailContactPoint updatedContactPoint = cpmClient.PatchEmailContactPoint(emailContactPoint, config, accessToken).Result;
public async Task<EmailContactPoint> PatchEmailContactPoint(EmailContactPoint contactToPatch, PluginConfig config, string accessToken)
{
var reqMessage = new HttpRequestMessage(new HttpMethod("PATCH"), "api/EmailContacts");
reqMessage.Content = new StringContent(contactToPatch.Serialize());
reqMessage.Content.Headers.ContentType = new Headers.MediaTypeHeaderValue("application/json");
return await MakeRequestAndParseResponse<EmailContactPoint>(reqMessage, config, accessToken);
}
private async Task<T> MakeRequestAndParseResponse<T>(HttpRequestMessage reqMessage, PluginConfig config,string accessToken)
{
reqMessage.Headers.Authorization = new Headers.AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await httpClient.SendAsync(reqMessage);
await ValidateResponse(response);
if (typeof(T) != typeof(object))
{
string responseAsJson = await response.Content.ReadAsStringAsync();
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(responseAsJson)))
{
// Deserialization from JSON
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));
T responseObj = (T)deserializer.ReadObject(ms);
return responseObj;
}
}
else
{
return default(T);
}
}
API response:
{
"email": "nb@iotap.com",
"country": "US",
"topicSettings": [
{
"cultureName": "en-US",
"lastSourceSetDate": "2019-06-28T08:59:52.6750524Z",
"originalSource": "SampleCPMProject",
"state": "optInExplicit",
"topicId": "00000000-0000-0000-0000-000000000001",
"isVerified": true
}
]
}
3) Validating email address in CPM system and getting the unsubscribe link from the CPM system
API Request:
EmailContactabilitiesRequest request = new EmailContactabilitiesRequest()
{
TargetedTopicId = new Guid("00000000-0000-0000-0000-000000000001"), //Topic Id for which you want to contact customers
UnsubscribeUrlRequired = true,
ContactPoints = new List<string>(),
};
foreach (string emailAddress in emails)
{
request.ContactPoints.Add(emailAddress);
}
JarvisCPMClient cpmClient = new JarvisCPMClient();
//CPM api response
EmailContactabilitiesResponse result = cpmClient.GetEmailContactability(request, config, accessToken).Result;
public async Task<EmailContactabilitiesResponse> GetEmailContactability(EmailContactabilitiesRequest request, PluginConfig config, string accessToken)
{
var reqMessage = new HttpRequestMessage(HttpMethod.Post, "api/EmailContactabilities");
reqMessage.Content = new StringContent(request.Serialize());
reqMessage.Content.Headers.ContentType = new Headers.MediaTypeHeaderValue("application/json");
return await MakeRequestAndParseResponse<EmailContactabilitiesResponse>(reqMessage,config,accessToken);
}
private async Task<T> MakeRequestAndParseResponse<T>(HttpRequestMessage reqMessage, PluginConfig config,string accessToken)
{
reqMessage.Headers.Authorization = new Headers.AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await httpClient.SendAsync(reqMessage);
await ValidateResponse(response);
if (typeof(T) != typeof(object))
{
string responseAsJson = await response.Content.ReadAsStringAsync();
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(responseAsJson)))
{
// Deserialization from JSON
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));
T responseObj = (T)deserializer.ReadObject(ms);
return responseObj;
}
}
else
{
return default(T);
}
}
API response:
{
"contacts": [
{
"email": "nb@iotap.com",
"canContact": true,
"unsubscribeUrl": "https://account.microsoft-int.com/profile/unsubscribe?CTID=0&ECID=Lfqg2DXoxMShzmVTr72%2FKg%3D%3D&K=8fd6fc11-2f81-44ef-8886-aeb7bbca5862&CMID=null&D=637037931174166928&PID=18000&TID=00000000-0000-0000-0000-000000000001",
"cultureName": "en-US"
},
{
"email": "test@iotap.com",
"canContact": false,
"unsubscribeUrl": null,
"cultureName": null
}
],
"targetedTopicId": "00000000-0000-0000-0000-000000000001"
}
Conclusion :
If we want to implement webrequest in plugin then we can use HttpRequestMethod.
There is no need of Microsoft.IdentityModel.Clients.ActiveDirectory.dll as this dll throws an exception at runtime.