MemberJunction / MemberJunction/MJ

Communication: SendGridProvider should support customArgs, per-message tracking settings, and Headers passthrough

Open
#2,817 1 comment 0 reactions 1 assignee Claimed by @SDesai-BC View on GitHub
enhancement
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.