In-app notifications vs external notifications

In-app notifications vs external notifications

In-app notifications have been a great addition to the Platform and highly usable by providing notifications to the end users within their Model-driven app, but not always will the user “notice” these and different ways of notifications can be used.

There is nothing new is this post as far as the notifications that can be implemented using Power Automate, but in this post, we have created a generic type of child flow that can be triggered and support three different type of notifications (In-app, Microsoft Outlook and Microsoft Teams using Adaptive cards).

In addition to using these notifications, we wanted to allow the system to store the notifications that are being created within the system, regardless of the output. As notifications can be associated with multiple records, we created a Polymorphic Lookup for the related record, something similar to the Regarding that is available on Notes or Activities. We added a Lookup field to the Notification called Contact Id and another field called Regarding Id.

For the Polymorphic Lookup field we used the Polymorphic Lookup Manager from XrmToolBox. As appnotification is a virtual table, you need to make sure that The tricky part with adding the Polymorphic Lookup on a virtual table is that the Cascading behavior should be set to None for each of the behaviors as shown in the image below.

The In order to do this, we implement this capture of notifications, we created a Notification History table that contains these data elements (similar to the ones that exist in the appnotification table). The basic table structure is shown below.

Column Name (Display)Data TypePurpose
TitleSingle Line of Text (256)Title of the Notification
ContactLookupThe Contact that is associated with the Notification
RegardingPolymorphic LookupThe record that the notification is about. This can bel Lead, Opportunity, Incident or a custom table
Sent ToLookupThe System User that the notification was sent to
BodySingle Line of Text (500)The Body of the Notification (Copied from Body of AppNotification)

In order to run this process, we create a single child flow. The flow would execute from other flows when a notification needs to be created. The child flow would have a manual trigger and would accept multiple parameters such as the Title, Body, Client Id, Regarding Object Type, Regarding Object Id, the User receiving the notification and the type of notification (which allows selection of one or more types). The type of notification is a text field set up as Multi-select list of options containing the values of “Dataverse” (for In-App Notifications), “Outlook” and “Teams”.

The next step include a Compose of the Target Url for the Internal Notification (this is part of the data element in the AppNotification table). This is a concatenation of the entity type pulled from the Regarding Object Type and the Regarding Object Id. You will notice the logic for opportunities, as the singular mode is Opportunity and needs to be trimmed. There was a reasoning behind doing this in the actual implementation, but can be removed based on the logic that you are trying to implement and only use the value for the trigger body if needed.

concat(
	'?pagetype=entityrecord&etn=', 
	if(equals(triggerBody()['text_3'], 'opportunities'), 
           'opportunity', substring(triggerBody()['text_3'], 0, lastIndexOf(triggerBody()['text_3'], 's'))), 
	'&id=', triggerBody()['text_4']
)

The image below shows the previous step as well as the next three steps, which are explained below.

Next, we want to get the Email Address of the User Id that is going to receive the notification. For that purpose we call the System User table in Dataverse and get the Internal Email Address.

We then compose the full target email so that we can trigger this from Microsoft Outlook or Microsoft Teams. The full email address is similar to the above, but contains some additional lines to get the target url and the app id. The app id is retrieved from an environment variable.

concat(
	'https://', 
	uriHost(outputs('Get_User_Email_Address_by_User_ID')?['body/@odata.id']), 
	'/main.aspx?appid=', 
	parameters('Desktop App Id (xyz_DesktopAppId)'), 
	'&pagetype=entityrecord&etn=', 
	if(equals(triggerBody()['text_3'], 'opportunities'), 
           'opportunity', substring(triggerBody()['text_3'], 0, lastIndexOf(triggerBody()['text_3'], 's'))), 
	'&id=', triggerBody()['text_4']
)

We then create the Dataverse Notification History table. This creates a historical record that allows us to have a record of any previously created notifications created from within the system. All notification are associated with the Contact record (in this case called Client).

Finally we call as switch statement to determine which notification options were selected. We use an Apply to Each on the Notification Type and then the Switch runs on the Notification Type Item. The image below shows the switch statement.

In the Dataverse case, we create a new In App Notification record, and generate the Data element dynamically. In the Outlook case we send an email to the recipient and include a link to the Dataverse record, and in Teams we send an Adaptive card with a link to the Dataverse record as well

The image below shows the final results.

I am working on a follow up of this to trigger external notifications from the creation of the In-App notification. These will be already in the new year. In the meantime, Happy New Year everyone.