Customer Insights: Get Email Delivery and Interaction Details of Journey
I got asked by a customer how to get the interaction details of the Journey. By default, in the Journey that is on the status of Going Live or Completed, we can click on the Delivery funnel button to see the drill-down of the information:

Delivery funnel information
Then, it will pop up the screen below:

Delivery and Interaction details
As you can see in the above screenshot, we can get the data on how much Sent - Delivered - Blocked - Delivery failed - etc for that specific Email action. Now, the question is how to pull this information whenever we need it without depending on the UI? For instance, if we want to pull this data into another system? That is what we learn in this short blog post!
Show me the code
Before we begin, I don't think this information is being shared anywhere in Microsoft documentation. So, there is a high chance it will change in the future!
And if you are wondering how I can get this information, it is because I inspect the network request-response to construct the code. And here is the code:
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace DataverseBenchmarkProject
{
public class GetMarketingEmailAnalytics
{
public void Execute(IOrganizationService service)
{
var journeyId = new Guid("1131d36e-fc8e-f011-b4cc-6045bd20d1fa");
var startDate = DateTime.UtcNow.AddDays(-10);
var endDate = DateTime.UtcNow;
var journey = GetJourney(service, journeyId);
if (journey == null) return;
var widgets = GetWidgets(journey, startDate, endDate).ToArray();
foreach (var widget in widgets)
{
var request = new OrganizationRequest("msdynmkt_ListWidgetDataCustomAction");
request["WidgetRequest"] = JsonConvert.SerializeObject(widget);
var response = service.Execute(request);
var widgetData = response["WidgetData"]?.ToString() ?? "";
if (string.IsNullOrEmpty(widgetData)) continue;
var data = GetData(widgetData);
foreach (var kvp in data)
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
}
Console.WriteLine("Completed");
}
private Dictionary<string, object> GetData(string widgetData)
{
var result = new Dictionary<string, object>();
// Load your JSON string into a JObject
var json = JObject.Parse(widgetData);
var data = json["data"] as JArray;
foreach (var item in data)
{
var cells = item["cells"] as JObject;
if (cells != null &&
cells["InteractionType"]?["value"] != null &&
cells["InteractionsCount"]?["value"] != null)
{
var interactionType = cells["InteractionType"]["value"].ToString();
var interactionsCount = cells["InteractionsCount"]["value"];
result[interactionType] = interactionsCount;
}
}
return result;
}
private IEnumerable<Widget> GetWidgets(Entity journey, DateTime startDate, DateTime endDate)
{
var journeyJson = journey.GetAttributeValue<string>("msdynmkt_journeyjson");
if (string.IsNullOrEmpty(journeyJson)) yield break;
var json = JObject.Parse(journeyJson);
// Navigate to the "actions" object
var actions = json["actions"] as JObject;
foreach (var action in actions.Properties())
{
var actionObj = action.Value as JObject;
if (actionObj?["type"]?.ToString() == "Email")
{
var id = actionObj["id"]?.ToString();
var contentId = actionObj["parameters"]?["contentId"]?.ToString();
yield return new Widget
{
Filter = new Filter
{
DateFrom = startDate.ToString("yyyy-MM-ddTHH:mm:ssZ"),
DateTo = endDate.ToString("yyyy-MM-ddTHH:mm:ssZ"),
Properties = new[]
{
new Properties { Name = "MessageId", Value = contentId },
new Properties { Name = "JourneyActionId", Value = id },
new Properties { Name = "CustomerJourneyId", Value = journey.Id.ToString() }
}
}
};
}
}
}
private Entity GetJourney(IOrganizationService service, Guid journeyId)
{
var query = new QueryExpression("msdynmkt_journey")
{
ColumnSet = new ColumnSet("msdynmkt_journeyjson"),
TopCount = 1,
};
query.Criteria.AddCondition("msdynmkt_journeyid", ConditionOperator.Equal, journeyId);
var result = service.RetrieveMultiple(query);
return result.Entities.FirstOrDefault();
}
public class Widget
{
public string WidgetId { get; set; } = "MessageEmailDeliveryInteractionsDualGrid";
public int Top { get; set; } = 50;
public string SkipToken { get; set; } = "";
public string LanguageId { get; set; } = "1033";
public int OffsetFromUtcInMinutes { get; set; } = 420;
public Filter Filter { get; set; } = new Filter();
public bool IsCustomLayout { get; set; } = false;
public bool AriaV2Enabled { get; set; } = false;
}
public class Filter
{
public string DateFrom { get; internal set; } = "";
public string DateTo { get; internal set; } = "";
public Properties[] Properties { get; set; } = [];
}
public class Properties
{
public string Name { get; set; }
public string Value { get; set; }
}
}
}
If you see in the above code, I created 3 main parameters:
- The JourneyId
- Start Date
- End Date
Basically, you can wrap this code into a Custom API, for example, if you want to automate it in Power Automate.
Based on what I observed, we need to get the msdynmkt_journey.msdynmkt_journeyjson as this property has the definition of the journey. Based on that value, we need to construct the Widget definition because we need to call the Marketing API called msdynmkt_ListWidgetDataCustomAction. Here is the sample of the full request for it:
{
"WidgetId": "MessageEmailDeliveryInteractionsDualGrid",
"Top": 50,
"SkipToken": "",
"LanguageId": "1033",
"OffsetFromUtcInMinutes": 480,
"Filter": {
"DateFrom": "2025-09-11T11:00:00.000Z",
"DateTo": "2025-09-13T02:02:00.000Z",
"Properties": [
{
"Name": "MessageId",
"Value": "622cb98b-f68e-f011-b4cc-00224858384e"
},
{
"Name": "JourneyActionId",
"Value": "779a8b28-a467-4220-ae1b-3892696c5010"
},
{
"Name": "CustomerJourneyId",
"Value": "1131d36e-fc8e-f011-b4cc-6045bd20d1fa"
}
]
},
"IsCustomLayout": false,
"AriaV2Enabled": false
}
Then, once we execute the msdynmkt_ListWidgetDataCustomAction, it will return some response properties:

msdynmkt_ListWidgetDataCustomAction response
All the data that we need is stored in the "WidgetData" and here is the format of it:
{
"data": [
{
"recordId": "DeliveryMenuItem",
"parentRecordId": null,
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Delivery",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "DeliveryMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Sent",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "41357",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailSentDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "DeliveryMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Delivered",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "40245",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailDeliveredDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "DeliveryMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Blocked",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "3571",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailBlockedDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "DeliveryMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Delivery failed",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "1113",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailDeliveryFailedDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": "InteractionsMenuItem",
"parentRecordId": null,
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Interactions",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "InteractionsMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Unique opens",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "4470",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailOpenedUniqueDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "InteractionsMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Total opens",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "5118",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailOpenedDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "InteractionsMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Unique clicks",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "9",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailClickedUniqueDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "InteractionsMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Total clicks",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "53",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailClickedDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "InteractionsMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Marked as spam",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "0",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailMarkedSpamDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
},
{
"recordId": null,
"parentRecordId": "InteractionsMenuItem",
"color": null,
"cells": {
"InteractionType": {
"recordId": "",
"value": "Unsubscribed",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"InteractionsCount": {
"recordId": "",
"value": "3",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
},
"widgetId": {
"recordId": "",
"value": "MessageEmailUnsubscribedDetailsList",
"cellType": null,
"valueWidgetCellData": null,
"additionalProperties": null
}
},
"metadata": null
}
],
"skipToken": null
}
Based on the above sample, I only take the pair of InteractionType.value and InteractionsCount.value.
Demo
Here is the result of the code above!

Demo
Based on the snippet above, you can create a Custom API/Azure Functions to get the data and push it to other source systems if necessary!
Hope you learn something and happy CRM-ing!
Leave a comment
Your comment is sent privately to the author and isn't published on the site.