Contact Permission and Suppression
Lawful basis, channel permission, jurisdiction, purpose, global opt-outs, and complaint handling as one shared layer rather than a filter each campaign reimplements. Consent is one basis among several; suppression is a decision of your own.
The decision it encodes
May we contact this person, on this channel, for this purpose?
Someone unsubscribed six weeks ago and has just received a promotional email.
The unsubscribe was recorded correctly, in the sending platform, where the link in the footer pointed. The campaign was built in the warehouse from a query that joined the customer table to a segment. Neither system did anything wrong. Nobody wrote the sentence that says the second one has to ask the first.
That is the whole failure, and it is not rare. It is what happens by default whenever permission is a property of a tool rather than a property of the organization.
The decision it encodes
May we contact this person, on this channel, for this purpose?
Three qualifiers, and dropping any of them produces a check that passes when it should not. Permission for a service notification is not permission for a promotion. Permission by email is not permission by SMS. Permission last year, under a basis that has since been withdrawn, is not permission now.
Permission and suppression are different things
They get merged into one list, and merging them loses information the organization needs.
Permission is the point-in-time result of law, jurisdiction, purpose, channel rules, lawful basis, and the customer’s choices. Consent is one lawful basis among several; contract and legitimate interest are others, and which applies depends on the purpose and the place. Permission is granted and withdrawn partly by the customer and partly by the rules that bind you, and it is the thing a regulator asks about.
Suppression is a decision not to contact someone you are permitted to contact. Complaints, hard bounces, an open support ticket, a recent refund, a bereavement flag, a frequency cap already spent. Some are permanent, some expire, and all of them are yours to set.
They differ in who owns them, how they are reversed, and what happens when they are wrong. Contacting past a suppression is an embarrassment. Contacting past a withdrawn consent is a regulatory event.
The check returns a reason
A permission layer that answers yes or no is unauditable and undebuggable. The useful answer carries why.
| Field | What it is for |
|---|---|
| Decision | Allow or deny, for this person, channel, and purpose. |
| Reason code | Which rule decided it. The difference between a bug report and a shrug. |
| Lawful basis | Consent, contract, or legitimate interest, recorded per purpose. |
| Granted at, withdrawn at | Permission is a timeline. A point-in-time answer needs one. |
| Source | Where the signal came from, because a preference center and a footer link disagree eventually. |
| Expires at | Some bases lapse. A permission with no expiry is a claim nobody rechecks. |
The reason code is what turns “why did this person get this” from an investigation into a lookup, and it is also what makes the suppressed population analysable rather than missing.
Enforce it at the send, below everything
The check belongs at the last point before a message leaves, underneath every campaign, every policy, and every agent.
Putting it in the audience definition is not enough. Audiences are built in advance and someone opts out between the build and the send, which is the window in which the opt-out was most emphatic. Putting it in each campaign’s own logic guarantees that the fortieth campaign implements it slightly differently from the first.
Propagation time is a decision
An opt-out that reaches the warehouse in twenty-four hours and a campaign that builds its audience twelve hours before sending produce a window in which the organization is knowingly contacting people who have withdrawn.
Somebody has to name the acceptable window and design to it, which usually means the send-time check reads a fast path rather than the nightly table. The number is a business decision about risk. What is not optional is that the number is known, rather than being whatever the pipeline happens to do.
Suppression is also a measurement problem
Suppressed people are removed from campaigns and they are not removed from experiments. They were assigned, so they belong in the intention-to-treat comparison, and dropping them compares a permitted slice of treatment against the whole of control.
Because suppression correlates with prior engagement, and prior engagement predicts conversion, that drop is not a rounding error. Recording the reason code makes this tractable: the readout can report how much of each arm was suppressed and for what, which turns an invisible bias into a line in the output.
Maturity, honestly staged
Stage 1: one suppression list every campaign must read. Ends the worst class of incident. No purpose or channel logic yet.
Stage 2: channel and purpose in the check. Service and marketing are separated, so operational messages stop being blocked and promotions stop being sent under a service basis.
Stage 3: enforcement at send time, with reason codes. The check moves below every campaign, and every refusal is explainable.
Stage 4: point-in-time permission and reconciliation. A readout can answer what someone was permitted at assignment, and divergence between platforms gets caught by a job rather than by a customer.
Why permission has to be a timeline Technical
Storing a current flag answers today’s question and destroys yesterday’s. Six weeks after a campaign, a readout needs to know who was contactable at assignment, because that is the population the randomization applied to. If permission is a boolean that gets overwritten, the arms cannot be reconstructed and the suppressed share of each cannot be reported.
The same structure the customer state model uses for history works here: one row per permission event with a valid-from and valid-to, and the check is a lookup at a timestamp. That also makes the regulatory question answerable directly, since demonstrating a basis for a past contact is the same query the readout runs.
Context
Best suited for
Any program contacting people across more than one channel, or any deployment where a policy or agent chooses recipients and a refusal has to be enforced rather than requested.
Data requirements
- Permission events with a source, a purpose, a channel, and a timestamp, kept as history rather than as a flag
- Suppression events with reason codes and expiry, separated from consent
- A send-time path fast enough to read recent withdrawals, not only the nightly table
- Reconciliation between each channel platform and the permission layer, on a schedule
What changes by context
- B2C subscription
- Service and marketing messages both go to the same inbox under different bases, so purpose is the field that carries the weight. Getting it wrong blocks billing notices or ships promotions under a service basis, and the second is the serious one.
- Lifecycle-led
- Volume makes propagation time the binding risk. A twenty-four hour lag and a daily send cadence means every opt-out has one more message coming, at a scale where that is thousands of people a week.
- B2C ecommerce
- Preference centers and footer links tend to write to different systems, so the source field is what lets you tell which one a customer used and which one is out of date.
When it breaks down
- Channels operated entirely by a partner, where the permission state lives in their system and can only be reconciled after the fact.
- Programs where the audience is exported as a file and sent by another team, since nothing checks anything at send time.
- Jurisdictional variation deep enough that one rule set cannot express it, which needs the check to be per-region rather than global.