MemberJunction / MemberJunction/MJ
Communication: SendGridProvider should support customArgs, per-message tracking settings, and Headers passthrough
- Dominant language
- TSQL
- Stars
- 29
- Forks
- 6
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 323
Description
## What to build
Let callers pass per-message `CustomArgs` and tracking toggles through the Communication framework to SendGrid, and fix the disabled `Headers` passthrough.
Today the SendGrid provider maps only `to/from {email,name}`, cc/bcc, subject, and bodies onto the outbound payload. There is no way to set:
- **`customArgs`** — needed for first-party event attribution (e.g. stamping a domain record ID on the message so webhook events can be correlated),
- **`trackingSettings`** (`clickTracking` / `openTracking` / `subscriptionTracking`) — without an explicit disable, the SendGrid *account default* applies, which typically rewrites every link in the email. Consumers doing their own first-party link tracking get their URLs clobbered,
- **`Headers`** — the passthrough exists but is commented out ("needs SG testing"), and the dormant code would mangle header names with an `X-` prefix, which breaks standardized headers like `List-Unsubscribe`.
Real-world consequence: CDP (BlueCypress) has two production email features (voice conversation summary emails, voice invite emails) that bypass the Communication Engine entirely and call `@sendgrid/mail` directly — the bypass reason documented in their code is exactly this gap.
## Proposed shape
1. Add optional fields to `Message` in `packages/Communication/base-types` (publishes as `@memberjunction/communication-types`):
- `CustomArgs?: Record`
- `TrackingSettings?: { clickTracking?: boolean; openTracking?: boolean; subscriptionTracking?: boolean }`
Both engine entry points propagate new `Message` fields for free via the copy-constructors (`new Message(message)` in `Engine.SendMessages`, `new ProcessedMessageServer(message)` in `SendSingleMessage`), so this is additive and back-compat-safe (absent = current behavior, i.e. account defaults).
2. Map them in `SendGridProvider.SendSingleMessage` onto the SDK payload.
3. Re-enable `Headers` passthrough without the `X-` prefix mangle (verbatim header names), so callers can emit `List-Unsubscribe` / `List-Unsubscribe-Post`.
Maintainer call: if SendGrid-specific concepts shouldn't live on the provider-neutral `Message`, a generic provider-options bag works equally well for the consumers above.
## Acceptance criteria
- [ ] A message sent through CommunicationEngine with `CustomArgs` set arrives at SendGrid with those `custom_args` (webhook events echo them back)
- [ ] Per-message tracking toggles reach the SendGrid payload; absent toggles preserve current behavior
- [ ] `Headers` pass through verbatim (no `X-` prefixing); a `List-Unsubscribe` header survives to the delivered message
- [ ] Existing SendGridProvider tests pass; new tests cover the three mappings
- [ ] No behavior change for messages that set none of the new fields
## Blocked by
None - can start immediately
Contributor guide
Assessment
This issue has not been assessed yet.