Find out how to include a link to the record (Record URL) when sending an email from Dynamics 365/CDS using flow

When sending a notification email to users that involves a review of a Dynamics 365/CDS record , it is always handy to include a direct link to the record itself within the notification email, so that the user can open the record directly from the email instead of doing a search in the system, etc.

We can previously do this easily in Dynamics 365 classic workflow as there is a Record Url (Dynamic) property for each entity which can be used to include a direct link to a Dynamics 365/CDS record when sending an email to the users. And that will allow the users to open the record directly from within the email itself by clicking on the link. However now, with the introduction of the model-driven apps concept and the format changes in Unified Interface, the Record Url (Dynamic) is no longer working like before as it is lacking the "appid" query string parameter.

There are still a few ways to provide a link to a record in an email by building a custom code solution or using string manipulation third-party custom workflow library such as Ultimate Workflow Toolkit. But since Microsoft recommends using automated flow instead of background workflows, I will tackle this using automated flow in this post.

In this blog post, you will learn how to achieve the following using the automated flow from Power Automate.
  • retrieve the Environment Variable
  • create an email record in Dynamics 365/CDS and populate activity parties and email body
  • compose Record Url with specific model-driven app GUID
  • send email from Dynamics 365/CDS
The Use Case: Send an email notification to the Account owner when the Account is created or reassigned so that the Account owner can review the data.



To build an automated flow to achieve the above requirement, we need to do the steps listed down below (all CDS steps in the following sample are from the Common Data Service (current environment) connector).
  1. When an Account record is created or Owner is updated
  2. Get a User record for Account Owner
  3. Compose Environment Hostname
  4. List Environment Variable Value records with App Id
  5. If there is no App Id configured in Environment Variable
  6. Terminate if no App Id is Configured
  7. Parse JSON to get Default Value
  8. Compose App Id Environment Variable
  9. Create a new Email record
  10.  Perform a bound action to Send Email

1. When an Account record is created or Owner is updated


The flow’s trigger is when the Account is created or reassigned, so we will use the CDS (current environment) trigger with Create or Update trigger condition. The Filtering attribute is set to "ownerid" here so that the flow will only run when the "Owner" field value is changed (it will ignore changes made to other fields).

2. Get a User record for Account Owner


This optional step is just to get the name of the owner so we can personalise the notification email. Getting the lookup field display name without additional query is one feature that I miss in the classic workflow. It is recommended to populate the "Select Query" with the schema name of the fields which are going to be used. It may not have a lot of impact on performance for "Get record" action but it is noticeably faster to retrieve the necessary columns only for "List records" especially if you are dealing with a lot of records. As an additional benefit, the list of dynamic content will only show those records instead of showing all fields from that entity.


3. Compose Environment Hostname


This step is to compose the variable for the hostname of the current Dynamics 365/CDS environment. (e.g. contoso.crm.dynamics.com). To build the record URL without hardcoding the environment hostname, uriHost function is used to get the hostname of the OData URL.

The trick here is to get the URL from "OData Id" of one of the CDS connector actions. If the "OData Id" property of CDS connector trigger step is used, it returns an empty value.

Another thing to take note is to update the "OData Id" property in the expression after choosing from the dynamic content. When the "OData Id" property is selected from the dynamic content after entering uriHost() in the expression bar, it populates as
 uriHost(outputs('Get_an_User_record_for_Approver')?['body/@odata']?['id'])  
which is not a valid property "['body/@odata']?['id']" and returns an empty data.
The expression needs to be changed as below "['body/@odata.id']" to make it work.
 uriHost(outputs('Get_a_User_record_for_Account_Owner')?['body/@odata.id'])  


4. List Environment Variable Value records with App Id

🛈 Tip

Instead of using Environment Variables, you can also use the "List record" action on "Model-driven apps" entity to lookup the AppID of the app by filtering with the uniquename of the app. That is the easier and preferred way of getting an AppID. You can find more details in this post by Thomas Peschat and this post by Sara Lagerquist.

One of the main challenges to build a record URL is the "appid" which is the GUID of the model-driven app, and that is because the GUID is different for different environments. To overcome this, the environment variable is used to store the GUID of the main model-driven app.


The environment has two values
1. Default Value (stored in the Environment Variable Definition)
2. Current Value (stored in the Environment Variable Value)


Both values from related entities can be retrieved in one List Records CDS action by using the following FetchXML.

 <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' >  
  <entity name='environmentvariabledefinition' >  
   <attribute name='environmentvariabledefinitionid' />  
   <attribute name='defaultvalue' />  
   <filter type='and' >  
    <condition attribute='schemaname' operator='eq' value='lzw_PowerPlatformPlaygroundAppId' />  
   </filter>  
   <link-entity name='environmentvariablevalue' from='environmentvariabledefinitionid' to='environmentvariabledefinitionid' link-type='outer' alias='environmentvariablevalue' >  
    <attribute name='value' />  
   </link-entity>  
  </entity>  
 </fetch>  

Read Sara Lagerquist's blog post to learn more on how to Retrieve Related Data in Power Automate using the FetchXML.

5. If there is no App Id configured in Environment Variable


This control step is to check the number of records returned from the List Records step. This is the complete expression.
 length(outputs('List_Environment_Variable_Value_records_with_App_Id')?['body/value'])  

6. Terminate if no App Id is Configured

If there is no record found (i.e. no Environment Variable configured with for the model-driven app GUID with the specified schema name), the flow will be terminated with a status Failed. To increase the readability of the flow, the guard condition is used to terminate the flow for "no" condition without nested actions in the "yes" condition. Read Jonas Rapp's blog post to learn more about how to Avoid nested conditionals in Microsoft Flow by using Guard Conditions.

7. Parse JSON to get Default Value


The first record of the output from List Records step is used to parse the JSON output data and get the value of the related entity.

 first(outputs('List_Environment_Variable_Value_records_with_App_Id')?['body/value'])  

8. Compose App Id Environment Variable


This step will retrieve the App Id from the parse JSON output. The logic is to get the current value and if the current value is empty, get the default value.

 if(empty(body('Parse_JSON_to_get_Default_Value')?['environmentvariablevalue.value']), body('Parse_JSON_to_get_Default_Value')?['defaultvalue'], body('Parse_JSON_to_get_Default_Value')?['environmentvariablevalue.value'])  

9. Create a new Email record

Instead of sending an email from flow using "Send an email" action from Office 365 Outlook Connector, an email record will be created in Dynamics 365/CDS and sent from there. One of the benefits of sending an email within Dynamics 365/CDS  is that you will be able to see the email record against the related record (regarding) and see the history from the Timeline. It is also quite handy for the organisations with on-premise exchange to send an email without workaround HTTP request action.


The first step of sending an email from Dynamics 365/CDS is to create a new email record. Set the email recipient as one of the Activity Party lookup value. (read my other blog post to learn more about how to Set Lookup Field Value). Set the "Regarding" lookup value in the corresponding entity field.
The description (email body) field need to be populated with HTML text. Make sure to add <br /> tags for the line breaks.
A record URL is built in the following format.

 https://<<EnvironmentHostname>>/main.aspx?appid=<<AppIdEnvironmentVariable>>&pagetype=entityrecord&etn=task&id=<<RecordGuid>>  

10. Perform a bound action to Send Email


This final step is to send out the created email from step #9 above using "Perform a bound action". The IssueSend attribute needs to be set to "Yes" to send out the email from the system. If the value is "No", the email will only be marked as Sent and won’t be sent out from the system.

Summary

By using the "Perform a bound action" from Common Data Service (current environment) connector and Environment Variable, we can build an automatic flow which sends an email from Dynamics 365/CDS with a Record URL and fill the gap of not having the Record URL (Dynamic) like in the classic workflow.


You can download the above sample flow from my GitHub repository via this link.

Comments

  1. Hi Linn,

    Some really good info here. Do you know if its possible to create the Email record without the CRM:0001021 reference suffix in the Subject field?

    Thanks

    ReplyDelete
    Replies
    1. Yes. You can simply uncheck the "Use tracking token" under System Settings > Email tab
      https://carldesouza.com/dynamics-crm-email-tracking-token/

      Delete
  2. Where do we find "Create a new e-mail record"? I don't see it in Premium actions or elsewhere. I like the idea of sending from within Dynamics, so the message is trackable in the timeline.

    An important part is including the url in the message... your method, above, looks rather involved. Is that really the easiest way to get the url??

    ReplyDelete
    Replies
    1. There is no separate action for "Create a new e-mail record" in flow.
      You just need to choose "Common Data Service (current environment)" and "Create a new record" action from it.
      https://docs.microsoft.com/en-us/connectors/commondataserviceforapps/#create-a-new-record

      Yes, getting the record URL is relatively simple. Just follow my blog post and if you have any issue, please let a comment or DM me in Twitter.

      Delete
  3. Thank You very much for this...

    ReplyDelete
  4. Thanks for this I try it out with Opportunity, but I get the Error message "Unable to process template language expressions in action 'Compose_Environment_Hostname' inputs at line '1' and column '29693': 'The provided parameters for template language function 'uriHost' are not valid.

    I'm Using the Commondata Service connection and only one Adminuser to verify the Flow.
    Any Idea?

    Thanks

    ReplyDelete
    Replies
    1. I think I've seen similar error message but I don't quite remember where. I guess I had that error when I tried to test my flow with previous run data after adding a new action step with a new connector which hasn't been authorised.

      Which step of your flow are you getting that error?

      Delete

Post a comment

Popular Posts

[Power Automate] How to Set Lookup Field Value in Common Data Service (current environment) Flow Connector

[Power Apps] Using Common Data Service's Lookup Data Type Field in Canvas App

Get the Lookup Display Name and Option Set Value Label in a Single Query Using a CDS (Current Environment) Connector FormattedValue Property

[Power Automate] List Records - Use Expand Query to Retrieve Related Data in flow

Send Email from Dynamics 365/CDS with Attachment from Notes Using Flow

How to Set Lookup Fields with Null Value from Dynamic Content in CDS (current environment) Connector

Move Attachment from File Field of CDS to SharePoint in Power Automate (Part 1 of 3)

Getting the Lookup Attribute of the Parent Record in Power Apps Canvas App Development with Common Data Service (CDS)

Access Flow Run History within a Record in Dynamics 365/CDS