Consent and suppression ledger — proof of rules, control of exposure
Consent and suppression ledger
Every comms decision is provable and every exposure is controlled: subscribe/unsubscribe/bounce/complaint events write to a suppression ledger that is enforced at send time, with an audit trail for every change. This is the operational form of consent-first marketing law (Spam Act 2003) — the ledger IS the proof.
Problem it solves
- Marketing law requires consent evidence, working unsubscribe, and no further contact after opt-out; bounces/complaints damage sender reputation and violate provider policies. Without a ledger, "we think they opted out" is not proof, and exposure (sending to suppressed addresses) is invisible until the provider suspends you.
Shape
- Subscriber lifecycle (
core/marketing.go):Subscriberecords email + source + actor, reactivates status, and clears a prior unsubscribe-suppression;Unsubscribewrites suppression;DeleteSubscriberremoves the record but does NOT opt out (opt-out is a separate, stronger act). - Suppression ledger: entries keyed by address with reason (
unsubscribe, hard bounce, complaint); checked at intake validation AND re-checked in the worker before send; campaigns reportrecipients/skippedso exposure is measured per send. - Bounce triage, three detection paths normalised to one
BounceEvent: provider webhook (SES/SNS bounce/complaint/delivery/reject), DSN/bounce email parsed from return-path (action: failed, status codes), worker failure (synchronous provider rejection). Hard vs soft classification: only hard bounces + complaints suppress. - Undeliverability webhooks: subscribers (customer systems) are notified on terminal failure — exposure events propagate to the systems that own the customer relationship.
- Audit on everything: subscribe, unsubscribe, delete, campaign, bounce, suppression change — actor + timestamp + payload.
Rules
- Suppression is enforced twice (intake + worker) — see
kb:comms-provider-registry-seam. - Only hard bounces and complaints suppress; soft/transient failures retry with backoff, never suppress.
- Re-subscribe clears unsubscribe-suppression explicitly and auditably — consent is revocable and re-grantable, both recorded.
- Unsubscribe ≠ delete: deletion removes the record, opt-out suppresses the address. Never conflate them.
- Every campaign reports skipped counts — exposure is a metric, not a surprise.
- Unsubscribe links/mechanisms are mandatory in every marketing send (Spam Act); the ledger proves compliance after the fact.
Anti-patterns
- Sending to a list without checking suppression at send time.
- Suppressing on soft bounces (you lose reachable customers).
- Deleting subscribers instead of suppressing them (opt-out evidence destroyed).
- No audit trail — "we had consent" becomes unprovable in a dispute.
- Complaints ignored — they are both legal evidence and provider-reputation risk.
Sources
- factory/user-channels/core/marketing.go (Subscribe/Unsubscribe/DeleteSubscriber, campaigns)
- factory/user-channels/core/bounce.go, core/unsubscribe.go, core/service.go
- factory/user-channels/REQUIREMENTS.md (§2.4 bounce detection, §2.5 inbound)
- knowledge-base/regulations/spam-act-2003.md, industry/marketing.md