Skip to content

Pace only shared-mailbox sends; review a new account's first large own-ESP broadcast - #123

Merged
clbotdev merged 8 commits into
mainfrom
own-esp-pacing
Oct 22, 2026
Merged

clbotdev merged 8 commits into
mainfrom
own-esp-pacing

Conversation

@clbotdev

@clbotdev clbotdev commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Closes #122. Closes #50 (merged in via #124).

What

  • reserveSend applies new-account hourly pacing only to outbound messages through a shared mailbox (delivery_source_type = organization), and counts only those sends against the hourly budget. broadcastPacing reports pacing only for such broadcasts.
  • Through the team's own ESP, a new organization's first broadcast to FIRST_BROADCAST_REVIEW_RECIPIENTS (default 1000) or more contacts is held once: startSequence raises an abuse flag of the new kind broadcast, emails the owners and returns 400 broadcast_held_for_review. After an operator releases it (abuse.ts release), it and later broadcasts start normally. Exempt and established organizations and self-hosted installs are never held.
  • Migration 0024 widens abuse_flags_kind_check to include broadcast.
  • Docs (acceptable use), REST/MCP descriptions, web error message, .env.example and operator CLI help updated.

Not changed

The plan's new-account marketing ramp (advanceMarketingRamp, 200/day at first on fair-use plans) still applies to every source; see the open question in #122.

Tests

  • Shared-mailbox sends hit marketing_hourly_pacing at 17/hour; own-ESP sends don't.
  • First large own-ESP broadcast held once (no duplicate flags), released via CLI, later ones start; small, shared-mailbox, established and self-hosted cases not held.

Also in this PR

  • One review per new account: a released large-import review (Alert admins on large contact imports for review (hosted) #74) also covers the first large own-ESP broadcast, so someone moving from beehiiv is reviewed once, not twice. The import-hold message says so.
  • The ESP's own tracking is turned off where SendLit already tracks, via a provider capability (ownTrackingOffHeaders): SendGrid X-SMTPAPI clicktrack/opentrack filters, X-Mailgun-Track-Clicks/Opens: no, X-PM-TrackOpens: false / X-PM-TrackLinks: None. This covers broadcasts, sequences, test sends, and transactional emails for whichever of opens and clicks SendLit tracks. Resend and SES have no per-message switch; the docs say how to turn it off there.
  • Fix found while smoke testing: nodemailer MIME-encoded the long X-SMTPAPI JSON, which SendGrid can't parse. sendMail now sends that header unencoded.
  • Self-hosting docs: a new self-hosting/sending-safeguards page covers which safeguards apply on self-hosted vs Cloud, test-send and auto-pause settings, and the ESP tracking switches. The README and both .env.example files are updated.

Smoke tested on the stack

  • New account, 1,000-contact import: import_under_review. After release, the first broadcast held with broadcast_held_for_review (before the one-review change). After release it started and reported no pacing.
  • With the one-review change: after the import was released, the first large broadcast started directly with no new flag.
  • The SendGrid-provider test email carries the raw X-SMTPAPI filters header.

…irst large own-ESP broadcast

New-account pacing applied to every marketing send of a hosted
organization, including sends through the team's own ESP, whose
reputation and limits are the team's. Pacing now applies only to sends
through a shared mailbox. Through the team's own ESP, a new account's
first broadcast to FIRST_BROADCAST_REVIEW_RECIPIENTS (1000) or more
contacts is held once for operator review (abuse flag kind broadcast).

Closes #122
A team can put open, click, unsubscribe and view-in-browser links on its
own subdomain. The domain is verified by its CNAME and an HTTPS probe,
rechecked hourly while pending and daily once verified, and falls back to
the API host after three failed daily checks. Retired domains keep being
served so links in sent emails keep working. On a tracking domain only
the tracking routes answer; /tls/ask lets an on-demand TLS proxy issue
certificates for teams' domains. REST, MCP, dashboard card and docs
included. The domain authentication dialog now names the bounce
(Return-Path) domain in its SPF section.

Closes #50
rajat1saxena and others added 6 commits October 22, 2026 14:01
- A released large-import review also covers the account's first large
  own-ESP broadcast, so a new account is reviewed once, not twice.
- Broadcasts, sequences, test sends and tracked transactional emails ask
  SendGrid (X-SMTPAPI filters), Mailgun and Postmark not to track opens
  and clicks SendLit already tracks, via a provider capability.
- Self-hosting docs: which safeguards apply where, test-send and
  auto-pause settings, and the ESP tracking switches.
# Conflicts:
#	apps/api/.env.example
#	apps/api/src/automation/process-ongoing-sequence.ts
#	apps/api/src/mail/worker.ts
#	apps/api/src/sequences/test-send.ts
#	apps/docs/content/docs/self-hosting/meta.json
Nodemailer MIME-encoded the long JSON header, which SendGrid can't parse,
so the tracking-off filters would have been ignored. Found in a smoke test.
@clbotdev
clbotdev merged commit 128547c into main Oct 22, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants