MemberJunction / MemberJunction/MJ
Communication: no unsubscribe/suppression capability anywhere in the framework
- Dominant language
- TSQL
- Stars
- 29
- Forks
- 6
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 308
Description
## What's missing
The Communication subsystem has zero unsubscribe/suppression support — no suppression entity, no pre-send check, no way to emit a `List-Unsubscribe` header, and the SendGrid provider *actively disables* SendGrid's hosted subscription-tracking footer (the one zero-effort unsubscribe mechanism). Recipients have no way to get onto a suppression list through anything MJ sends.
Nuance for accuracy: SendGrid's *account-level* suppression lists (bounces, spam reports, prior global unsubscribes) still apply server-side regardless. The hole is the consumer-facing half: no opt-out affordance in the messages, and no framework-level suppression honored at send time.
This is a CAN-SPAM/GDPR posture issue for every MJ consumer that sends anything marketing-shaped. (Found while building CDP's voice-invite emails, where batch/CSV sending makes volume one click away.)
## Proposed shape
Two parts, both framework-level:
1. **`List-Unsubscribe` / `List-Unsubscribe-Post` support** — falls out of Headers passthrough in MemberJunction/MJ#2817 (headers must pass verbatim, not `X-` prefixed).
2. **A suppression entity + engine check** — e.g. `Communication Suppressions` keyed by recipient address + channel (+ optional scope), consulted in the send path before dispatch; suppressed recipients reported per-row as `Suppressed` (needs the result-code field from MemberJunction/MJ#2818) rather than silently dropped or thrown. Plus a documented way for an unsubscribe landing endpoint to write suppression rows.
## Acceptance criteria
- [ ] A new suppression entity exists with CodeGen artifacts and a documented write path
- [ ] Engine consults suppressions pre-dispatch; suppressed rows return a distinct per-row result, batch continues
- [ ] Callers can emit a working `List-Unsubscribe` header through the engine
- [ ] Suppression check failures fail safe (configurable: block-on-unknown vs send-on-unknown) and are logged
## Blocked by
- MemberJunction/MJ#2817 (Headers passthrough for the header half)
- MemberJunction/MJ#2818 (result code for per-row Suppressed reporting)
Contributor guide
Assessment
This issue has not been assessed yet.