Managing Preferences, Consent and Subscriptions with Dynamics 365 Realtime Marketing

**IMPORTANT UPDATE FEBRUARY 2024**

The below solution uses msdynmkt_contactpointconsent2 but due to changes in the product to support business units and multi-brand consent compliance profiles a new table has been created called msdynmkt_contactpointconsent4 you will need to amend the below solution to work in alignment with the new table and data requirements

https://learn.microsoft.com/en-us/dynamics365/customer-insights/journeys/real-time-marketing-email-text-consent

If your custom workflows write to the msdynmkt_contactpointconsent2 or msdynmkt_contactpointconsent3 consent tables, any writes to these tables automatically have data synced to the msdynmkt_contactpointconsent4 table after a delay (potentially 24 hours or longer). The data sync will continue until June 1, 2024. After that date, you'll need to have moved all workflows that write contact point consent records to target the msdynmkt_contactpointconsent4 table.

Following on from my previous blog post on how to trigger a flow when a marketing or subscription list is updated, this post will show you how to automate the update of contacts consent and marketing permissions so that it aligns with the subscription changes made.

TLDR: don’t unnecessarily block marketing emails - hide all the Realtime marketing consent stuff and automatically update both the Marketing Allow/Do Not Allow and the Contact Point Consent records when a customer updates their ‘Outbound’ subscriptions.

Why do we need this?

Dynamics 365 Marketing is in it’s transition from Outbound Marketing (childhood) to Realtime Marketing (adulthood), right now we are riding the rollercoaster of adolescence. Whilst exciting new features and enhancements are landing on a monthly basis, a few things aren’t quite there yet (growing pains and mood swings). The safe option is always available - stay with Outbound Marketing until Realtime Marketing has become more matured and established but where is the fun in that? One particular (and very important) feature that’s going through a big transition in Dynamics 365 Marketing was previously known as ‘Marketing Permissions’ but now referred to as ‘Consent’. It gets even more complicated if we start layering in SMS consent or any other marketing channels, so lets stick with email for now.

Outbound Marketing Permissions Customer consent is stored per Contact record ‘Record based’

Realtime Marketing Consent Customer consent is stored per email address or phone number ‘Contact-point based’

Ideally you would use one or the other. With all my customers I apply the rule of ‘Realtime first’ so if we can use Realtime marketing to achieve the desired outcome - we will. The current Realtime Marketing Consent page is an eyesore and cannot be customised (except the text wordings), there is also no way to support subscriptions. The Outbound Marketing Subscription centre is full customisable for you to style according to your brand, you can use it to manage subscriptions ad also for users to update their data if you so desire. I know which one I would choose.

“Use outbound subscription centers in real-time journeys”

Yes it’s a thing - you CAN have your cake and eat it (kind of), this article shows how to set it up nicely and a seriously recommend you do it. However, it doesn’t take into account the need to synchronise consent changes across the consent models. If a contact has Marketing Emails to allow and active subscriptions, their email can still be blocked if they also don’t have their ‘consent points’ set to allow - it’s good that its erring on the side of caution (don’t send without full consent) but absolutely crushing that you are missing out on potential new customers who have given you their consent to be marketed to.

The solution (according to Amey - for now)

  • Step 1 - implement this so that you can act when a subscription for a customer is updated

  • Step 2 - hide everything Realtime consent based from the forms (yes it’s pretty but it’s not ready for the world yet) - NOTE: hide don’t delete, its easier to get back later - future you will be grateful.

  • Step 3 - get your good friend Power Automate to synchronise a customers subscription/marketing preferences into their contact point consent. We will need two flows - one that is triggered as a child flow after a subscription is updated, and another child flow that is triggered when this action is complete. It could be wrapped into a single flow but the separation means I could use the flows independently of each other for other pieces of automation.

After Subscription Updated - Set Bulk Email Permissions

Welcome to Step 3 - image of the complete flow end to end can be found here -> After Subscription Updated - Set Bulk Email Permissions

Manually trigger a flow

First we need to make sure that the marketing permission aligns to the customer subscriptions. This will be run as an ‘Instant’ child flow, triggered from your ‘Subscription List Updated’ flow. Honestly, if you want to be able to manage subscriptions in Dynamics 365 Marketing well, you need this anyway (separate monologue pending). Add two string inputs - one for ‘MarketingListId’ and another for ‘MemberId’.

Initialize an integer variable

This will be used to count the number of subscriptions the contact has, so we can update the marketing email permissions accordingly. Why count? Because a subscription list is a special type of marketing list, not all marketing list memberships equate to a subscription.

Find out what Marketing Lists the Contact belongs to

The Contact to Marketing relationship is one of those pesky many to many (N:N) things, plus it can be Lead or Contact based so kind of polymorphic too - its not so easy to directly find out what subscriptions a contact has, first we need to find out what Marketing List Memberships they have using a ‘List Rows’ actions on the ‘Marketing List Members’ table.

_entityid_value eq _YOUR_MemberID_VARIABLE

The Contact might not belong to any Marketing Lists at all

Add a Condition action which will filter to check if the ‘ListMarketingMemberships’ search returned any results - if not we can assume they need to be unsubscribed. In the ‘No’ pathway add a compose action which simply sets the value to ‘true’. Why true you ask? We just said there were NO subscriptions and they are unsubscribed. Because the ‘Do Not Allow Bulk Marketing’ field is the most confusing double negative backwards logic I have seen in my life.

true = Do Not Allow (Marketing Emails)

false = Allow (Marketing Emails)

empty(body('ListMarketingListMemberships')?['value'])

Any Subscriptions to report Madame?

In the ‘Yes’ pathway of your condition we know that the Contact has at least one Marketing List membership - but we don’t know if that’s a subscription list or not.

Using a ‘List rows’ action we can loop through each Marketing List the contact is a member of and check if its of type ‘Subscription’.

Add an ‘Increment Variable action inside this loop which adds one to our ‘NumberOfSubscriptions’ variable every time a subscription list is found.

//FILTER
msdyncrm_issubscription eq true and listid eq MARKETING_LIST_VALUE

//INCREMENT
if(empty(body('ListContactsSubscriptions')?['value']),0,1)

One or more subscriptions?

Outside of the ‘Apply to each’ loop, but still inside the ‘Yes’ pathway on the condition we can add another Condition action to check to see if the ‘NumberOfSubscriptions’ variable is greater than or equal to 1, if ‘Yes’ their Marketing Permission is Allow (aka false), otherwise Marketing Permission is Do Not Allow (aka true). Set the value accordingly in each branch using a compose action.

Update Contact ‘Do Not Allow Bulk Email’ with the outcome

Combine all three possible outcomes into a single ‘Compose’ step, onle one of them will have been set, the other two will be blank. Using ‘Update a row’ set the Contact ‘Do Not Allow Bulk Email’ field to true or false.

Respond back to the flow that triggered this to let it know you are done using a ‘HTTP Response’ action.

We need to come back here later to call the subsequent child flow (grand child flow?) but we need to create it first

Sync Bulk Email Permissions to Consent Records

Now that the Bulk Email Permission is correct, lets align the consent records accordingly. This will be run as an ‘Instant’ child flow, it will take two inputs - the contact email address and whether they have ‘Allow’ or ‘Do Not Allow’ for their marketing email consent. Admittedly this is not the most efficient flow I have ever built and could easily be chopped down to less actions but at the time this set up was really handy for debugging and getting things to work smoothly.

Image of the complete flow end to end can be found here -> Sync Bulk Email Permissions to Consent Records

NOTE: you need to have a Dynamics Marketing sandbox or full license installed where you build this, the flow will not run successfully in a ‘solution only’ marketing instance - trust me I tried it.

Manually trigger a flow

Start this instant flow with the same ‘Manually trigger a flow’ trigger as last time, add two string inputs - one for ‘EmailAddress’ and another for ‘BulkEmail’.

Two integer variables walk into a bar

Initialize two integer variables for ‘ConsentStatus’ and ‘Reason’.

Find any existing consent records

Add a ‘List rows’ action with the Table name ‘Contact Point Consents’ - you might be lucky enough to see you have three (yes 3) tables showing all called the same thing… don’t ask. Choose one then switch to ‘Peek Code’ and keep trying different ones until you see ‘msdynmkt_contactpointconsent2s’ under entityName. Since this consent is contact point specific we search by email address of the contact rather than the contact itself.

msdynmkt_contactpointvalue eq '_YOUR_EMAILADDRESSS_INPUT'

Why have one Contact Point Consent table when you can have three!?

SWITCH! (Hey! Hey!)

Using your integer variables from earlier, add a Switch statement and set the corresponding integer values for the Consent Status and Reason on the Contact Point Consent record based on whether the response for Marketing Permissions was Allow or Do Not Allow. No Default case here because if it’s not Allow or Do Not Allow then something else has gone very wrong.

Update existing consent

Add a condition action to check if any consent records were found already existing for that email address. If yes - go and update them. Add an ‘Update rows’ action to loop through each consent record (the apply to each will create itself for you) and use the variables you set earlier to update the records. You can add whatever you want to the ‘Who requested the change’ box - but it’s useful to know where this update came from.

empty(body('ListConsentRecords')?['value'])

Create an email contact point consent record

Add a ‘Create record’ action and again you need to choose the Contact Point Consent table that has a logical name of ‘msdynmkt_contactpointconsent2s‘. Pay attention to the values you are inputting, it gets very upset if you get them wrong!

Create a tracking contact point consent record

Very similar to the action above but just be careful about which fields you are setting the value on. The Type is always email but the Consent Type Value and UI based status input changes.

Mission Flow - over and out

Respond back to the flow that triggered this to let it know you are done using a ‘HTTP Response’ action.

Call the grandchild!

Last but not least… we have to tie it all together. GO to the first flow you created ‘After Subscription Updated - Set Bulk Email Permissions’ and add a final step to call the second flow as a child. Be sure to send the Bulk Email output as the word version (Allow/Do Not Allow) rather than true/false mostly because it is confusing but also because your switch statement is looking for the human words too.

outputs('GetContactOData')?['body/donotbulkemail@OData.Community.Display.V1.FormattedValue']

And with consent - they all lived happily ever after

If you actually made it this far I will be surprised and impressed - I can’t say this is my most thrilling or ‘sexy’ post but this stuff is important to get right, and expensive if you don’t. This is my best attempt at a visual summary, ENJOY!

Previous
Previous

Mapping Option Sets/Choice Labels from Dynamics 365 Marketing Form Submissions to Custom Tables with Power Automate

Next
Next

Trigger flow when a Marketing or Subscription List is updated