Quantcast
Channel: Articles - Amey Holden | Anything But Code | Dynamics 365 Marketing & Power Platform
Viewing all articles
Browse latest Browse all 71

Trigger flow when a Marketing or Subscription List is updated

$
0
0

There is a bigger story around the Dynamics Marketing disarray between marketing permissions, consents and subscriptions that could make your mind melt. But that is for a later post. The main thing is that we need to be able to check the marketing permissions and consent are correctly synchronised with the customers subscriptions whenever they change, and vice versa!

This post will focus on how to trigger a flow when a Marketing or Subscription list is updated, understand what kind of update just happened, then get the GUIDs you need to do your next steps on checking consent and permissions. I used some inspiration and brain power along the way courtesy of Tip #1362: Trigger Power Automate on Associate / Disassociate and George Doubinski (which are kind of the same thing but lets not go into that right now).

WARNING: I use weird scary words like ‘Webhook’ and ‘HTTP Request’. You will need to install the almighty ‘Plugin Registration Tool’ but I promise to hold your hand on the way through so no one gets left behind.

What’s a subscription list in Dynamics 365?

I’m glad you asked - in Dynamics Marketing you have the ability to set up subscriptions which your customers (and potential customers) can sign up to. Behind the scenes they are simply ‘Marketing Lists’ with a space flag called ‘Is Subscription’ set to Yes.

1) It all starts with a flow

Unlike the chicken or the egg dilemma, in this case I can confidently say that the flow comes before the Webhook. Create a new ‘Instant’ flow with the trigger ‘When an HTTP request is received’, and a single ‘Compose’ action which pulls through the ‘Body’ from the HTTP Request.

Copy the HTTP POST URL, you will need it for step 3)

2) Install and connect to the ‘Plugin Registration Tool’

Download the latest SDK Tools Zip FIle -> https://xrmtoolscode.azureedge.net/sdk.zip. DO NOT SKIP THIS BIT -> After you download, right-click properties and unblock the file before you unzip it locally. Seriously, I checked, you really do need to do this or nothing works and you have to go cry in the corner for a while. Unzip the file and put it somewhere useful, or go rogue - leave it to get lost in the abyss of your Downloads folder so you can kick yourself later.

Create a new connection, make sure you select ‘Display list of available organisations’ and ‘Show Advanced’. Log in with your Dynamics/Microsoft 365 credentials and select the environment you are working in. Welcome to the inner cavern of the Plugin Registration Tool, don’t worry I feel as uncomfortable as you do right now.

2) Regsiter a ‘Webhook’ and some ‘Steps’

No seriously, I’m not even joking. Don’t forget to breathe. We need to breakdown the HTTP POST URL from step 1) into Webhook size chunks, prepare this first. Replace ‘&’ or ‘?’ with a new line and replace ‘%2F’ with ‘/’ and tadah!

Before

https://prod-07.australiasoutheast.logic.azure.com:443/workflows/abc123456789z/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=abcdefghi

After

Endpoint URL:

  • https://prod-07.australiasoutheast.logic.azure.com:443/workflows/abc123456789z/triggers/manual/paths/invoke

Keys:

  • api-version=2016-06-01

  • sp=/triggers/manual/run

  • sv=1.0

  • sig=abcdefghi

Register -> Register New Web Hook -> Use the values you just created above, to fill in the Endpoint URL and Keys. Change the Authentication to HttpQueryString - if you don’t do this now, it doesn’t work later, even if you change it, trust me I checked (twice) -> Save. Webhook - Registered!

Next up ‘Steps’, we need to add the following steps, these are the ‘Messages’

  • AddMember

  • Disassociate

  • RemoveMember

Right click on the Webhook you just created -> Register new Step -> Set Message e.g. ‘AddMember’ -> Set Execution Mode ‘Asynchronous -> don’t touch anything else and pretend you know what you are doing -> click Register New Step button

Repeat these stapes for all the three items above until your Webhook looks a little something like this —>

3) Check out your body

The body of the flow of course. Make sure your flow is turned ON and go add/remove some contacts from some marketing lists. Remember there are lots of ways to do this, the end result is the same (either the contact is added or removed) but the inputs that come from the Webhook trigger are completely different. Plus these steps are going to fire on any relevant AddMember/RemoveMember/Disassociate step - not just for the contact to marketing list relationship. Ugh. The good news is, we can totally deal with that in flow - yay!

4) Initialise your variables

I don’t really like using variables too much and prefer my good friend ‘Compose’ but things got a bit confusing without them. We will initiate the following string variables which are all values we will be getting out of the Webhook trigger ‘InputParameters’

  • ListId

  • ContactId

  • Relationship

  • MemberIds

  • RelatedEntities

  • Target

And if you want to be super snazzy (anal) put them all in parallel 🤓

5) Do you have a Parent Context?

Sometimes the ‘InputParameters’ that we need have a parent context, sometimes they don’t, but if they do - it’s very useful! Add a ‘Condition’ action to check if the ParentContext is blank or not, if it’s blank then we skip, if not then we go get dig for some hidden InputParameters!

triggerBody()?['ParentContext']

Within the ParentContext you will see there are multiple objects, each with a different ‘key’ - the key name determines which variable we will set. In this sample you can see ‘Target’, ‘Relationship’ and ‘Related Entities’ - these will help us to determine if the activity is related to the thing we want - Marketing Lists and Contacts. And if so, we need those lovely GUID’s to then act accordingly later on . So now ‘all you need to do’ is set the variables to these values…

Add an ‘Apply to Each’ control. Then inside there, add a ‘Switch’ control. Set the inputs as per below. We do this so we can go through every object, find out what the key is called, and grab the useful piece of info we want from there.

Select an output from previous step: triggerBody()?['ParentContext/InputParameters']

On: items('Apply_to_each_2')?['key']

Now we need to add multiple ‘Cases’ to the switch for each possible key, then tell it what variable we want to set and which attribute from the object we want to use.

As an example the image shows the ‘Target’ case, add a case for each of the following

  • ListId

    • Set variable ListId

      • items('Apply_to_each_2')?['value']

  • EntityId

    • Set variable ContactId

      • items('Apply_to_each_2')?['value']

  • Relationship

    • Set variable - Set variable Relationship

      • items('Apply_to_each_2')?['value/SchemaName']

  • MemberIds

    • Set variable MemberIds

      • items('Apply_to_each_2')?['value']

  • RelatedEntities

    • Set variable RelatedEntities

      • first(items('Apply_to_each_2')?['value'])?['LogicalName']

  • Target

    • Set variable Target

      • items('Apply_to_each_2')?['value/LogicalName']

6) Then the Input Parameters

We need to repeat a very similar set of logic (with a few additions') to cover the situations when there is no ParentContext, but also to provide additional information that cannot be gained from the ParentContext even when it exists. Outisde of the ‘ParentContextNull condiiton, add another ‘Apply to Each’ control. Then inside there, add a ‘Switch’ control. Set the inputs as per below.

Select an output from previous step: triggerBody()?['InputParameters']

On: items('Apply_to_each')?['key']

Again we will add multiple ‘Cases’ to the switch for each possible key, then tell it what variable we want to set and which attribute from the object we want to use. Notice that in this sate of cases, we sometimes set more than one variable per case.

As an example the image shows the ‘RelatedEntities’ case, add a case for each of the following

  • ListId

    • Set variable ListId

      • items('Apply_to_each')?['value']

  • EntityId

    • Set variable ContactId

      • items('Apply_to_each')?['value']

  • Relationship

    • Set variable - Set variable Relationship

      • items('Apply_to_each')?['value/SchemaName']

  • MemberIds

    • Set variable MemberIds

      • items('Apply_to_each')?['value']

  • RelatedEntities

    • Set variable RelatedEntities

      • first(items('Apply_to_each’)?['value'])?['LogicalName']

    • Set variable ListId

      • first(items('Apply_to_each')?['value'])?['Id']

  • Target

    • Set variable Target

      • items('Apply_to_each_2')?['value/LogicalName']

    • Set variable MemberIds

      • items('Apply_to_each')?['value/Id']

6) Check yourself before you wreck yourself

This is a good checkpoint to add a ‘Compose’ step, add all your variables to it (or copy-pasta from below) and run a few tests to check that they are getting populated with the right values and the flow is running smoothly.

Message: @{triggerBody()?['MessageName']}
ListId: @{variables('ListId')}
ContactId: @{variables('ContactID')}
Relationship: @{variables('Relationship')}
MemberIds: @{variables('MemberIds')}
RelatedEntities: @{variables('RelatedEntities')}
Target: @{variables('Target')}

7) Was a Marketing or Subscription List updated?

Finally, we need to check if actually we even care about this transaction - is this related to a Contact being added or removed from a Marketing /Subscription List?

Add a Condition control and using the variables you have populated from above we are going to check if the ListID has been populated (not null)

If it is false, cancel the flow (Terminate action with status cancel)

If it is true, using a ‘Get Row’ action, table name - marketing list, row ID - the ListId you set earlier, select columns - msdyncrm_issubscription,listname (optional but tidy 😊)

This is the bit I wanted to know all along, and it feeds nicely into my next post on Marketing Consent and Preferences because I only want to update them when subscriptions are changed.

Add a Condition control and check that the list you just ‘got’ above is in fact a ‘subscription’ list, i.e. outputs('GetMarketingList')?['body/msdyncrm_issubscription'] is true

If it is false, cancel the flow (Terminate action with status cancel)

Now what?

Two final useful pieces of info to help you on your way:

1) To find out what happened to cause the Webhook signal use this:

triggerBody()?['MessageName']

This will be one of the Plugin Step names you defined:

  • AddMember (contact(s) added to list)

  • Disassociate (contact(s) removed from list)

  • RemoveMember (contact(s) removed from list)

2) Sometimes MemberIds is populated and wrapped in [‘ContactGuid1ContactGuid2‘], some times ContactId is populated and sometimes its both with the same ContactID 🤯

What’s next? Well that depends on why you wanted to trigger the flow when a marketing list was updated in the first place… so, either go forth and conquer or stay tuned for my next post on updating the Marketing Preferences and Consents in response to a subscription list update.

triggerBody()?['MessageName']

if(contains(variables('MemberIds'),variables('ContactID')),variables('MemberIds'),concat(variables('ContactID'),variables('MemberIds')))

Viewing all articles
Browse latest Browse all 71

Latest Images

Trending Articles





Latest Images