Mailchimp Unsubscribe and Bounce Writeback to CRM
When a Mailchimp unsubscribe, bounce, or complaint webhook fires, the flow updates the matching Dataverse contact's consent and contactability flags, suppresses them from future sends, and logs the event. Posts hard-bounce spikes to a Teams marketing channel. Keeps the CRM's consent state accurate and compliant.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
This flow keeps a CRM's email-consent state accurate by mirroring Mailchimp suppression events into Dataverse. On a schedule it reads the Mailchimp audience, finds members who have unsubscribed (status unsubscribed) or hard-bounced / been cleaned (status cleaned), writes those members' consent and contactability state onto a CRM contact record, appends an immutable audit-log row for each event, and posts a Teams alert to the marketing channel when hard bounces spike past a configurable threshold.
Why it matters: Emailing unsubscribed or invalid addresses is a compliance and deliverability risk. Mirroring Mailchimp opt-outs and bounces back into the CRM keeps consent state correct everywhere, automatically.
As-built note (connector-first): The Mailchimp connector has no unsubscribe / bounce / complaint trigger (its only triggers are OnMemberSubscribed and OnCreateList). The original idea described a webhook; per the connector-first rule this build uses the supported pattern instead — a built-in Recurrence trigger plus GetListMembers, detecting consent changes from each member's status field. Going live requires only authorizing the three connections and setting the environment variable values.
Use Case
Marketing and operations teams want Mailchimp opt-outs and bounces reflected on the matching CRM contact immediately and automatically, with an audit trail for compliance and a heads-up when deliverability suddenly degrades (a hard-bounce spike often signals a bad import or a domain/reputation problem).
Flow Architecture
Recurrence
Recurrence (built-in)Polls the Mailchimp audience hourly (no native unsub/bounce trigger exists).
Initialize_CorrelationId
Initialize Variable (String)@guid() — run-unique trace ID stamped on every record and alert.
Initialize_MailchimpListId
Initialize Variable (String)Mailchimp audience ID from flowlibs_MailchimpListId.
Initialize_TeamsGroupId
Initialize Variable (String)Teams team ID from flowlibs_TeamsGroupId.
Initialize_TeamsChannelId
Initialize Variable (String)Teams channel ID from flowlibs_TeamsChannelId.
Initialize_BounceSpikeThreshold
Initialize Variable (Integer)Configurable: hard bounces per run that trigger a Teams alert (default 5).
Initialize_HardBounceCount
Initialize Variable (Integer)Running count of hard bounces this run (starts 0).
Initialize_SuppressedCount
Initialize Variable (Integer)Running count of contacts written back this run (starts 0).
Get_List_Members
Mailchimp — GetListMembersReads audience members and their current status.
Filter_Suppressed_Members
Query (Filter array)Keeps only status = unsubscribed or cleaned.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_MailchimpListId | String | REPLACE_WITH_MAILCHIMP_LIST_ID | Mailchimp audience (list) ID to monitor |
| flowlibs_TeamsGroupId | String | REPLACE_WITH_TEAMS_GROUP_ID | Teams team (group) ID for the spike alert |
| flowlibs_TeamsChannelId | String | REPLACE_WITH_TEAMS_CHANNEL_ID | Teams channel ID for the spike alert |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Mailchimp | shared_mailchimp | GetListMembers |
| Microsoft Dataverse | shared_commondataserviceforapps | ListRecords CreateRecord UpdateRecord |
| Microsoft Teams | shared_teams | PostMessageToConversation |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Cadence
- Change the Recurrence frequency/interval to poll more or less often (hourly by default).
- Spike threshold
- Edit varBounceSpikeThreshold to tune when the Teams alert fires.
- Resubscribe handling
- Add a branch that re-enables contactability when a member returns to subscribed.
- Soft vs hard
- Mailchimp cleaned is hard/undeliverable; extend the filter and event mapping if you import soft-bounce data from the Reports API.
- Map to a real CRM contact
- Point Find_Existing_Contact/Update_Existing_Contact at your production contact table and consent columns instead of the demo flowlibs_crmcontactconsent table.
- Sunset policy
- Retire chronically-bouncing addresses by querying the Consent Event Log for repeat Hard Bounce rows.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Suppression filter (Query where)
Keeps only unsubscribed or cleaned members.
EXPR.02Event type (Compose)
Maps Mailchimp status to an event type.
EXPR.03Contact lookup ($filter)
OData filter to find the consent row by email.
EXPR.04Existing-contact test
True when a matching contact already exists.
EXPR.05Update record id
GUID of the existing consent row to update.
EXPR.06Contact display name
Builds the display name from FNAME/LNAME merge fields.
EXPR.07Hard-bounce test
True for cleaned (hard-bounce/undeliverable) members.
EXPR.08Spike test
Fires the Teams alert when hard bounces reach the threshold.
Customize & download
Generate a ready-to-import copy of this solution with your environment-variable values baked in — available on Base, Pro, or Team.
Upgrade to customize
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.