Resend newsletter provider — authorized extension to the published MailCheap source

This adapter adds EMAIL_PROVIDER=resend for trusted, self-hosted installations.
The original UI, rendering, actions, queue, tracking, consent checks, account
controls and unsubscribe links are retained. No dependencies were added or upgraded.
The default provider selection remains unchanged; select Resend explicitly.

Configuration

  MAILCHEAP_CLOUD=                  (self-hosted mode)
  EMAIL_PROVIDER=resend
  RESEND_API_KEY=                   (Resend full-access key, for domains and sends)
  EMAIL_FROM=                       (platform emails, on a verified domain)
  RESEND_WEBHOOK_SECRET=            (dedicated endpoint's signing secret)
  RESEND_SEND_RATE_PER_SECOND=1     (optional; 1/s is the default)

Select the newsletter's sender in Settings separately from EMAIL_FROM. Add its
domain on Domains; an existing domain in the same Resend team is adopted without
changing DNS, receiving, tracking, or other domain settings. New domains are created
with Resend's default send.<domain> return path. Check now starts verification on
unverified domains; refresh again after Resend has checked DNS.

Resend has no SES-style tenant API. MailCheap retains account ownership, pauses and
local suppressions; Resend reputation, quotas, keys and provider suppressions belong
to the shared Resend team. This adapter refuses MailCheap Cloud mode. Only trusted
users should be allowed into this self-hosted installation. Use a dedicated Resend
team when provider-level isolation from other applications is needed.

The upstream admin sending-capacity panel reports unavailable for Resend: its
SES/PostShiba quota contract is not supported. Sending still uses the configured
Resend rate, and the original email statistics remain available. No other provider
is queried and no quota is invented.

Removing a domain or account from MailCheap does not delete the domain in Resend:
other applications may use it. Delete unused domains explicitly in Resend after
checking all consumers. Existing SES/PostShiba deletion behavior is unchanged.

Webhook and sending

Create a dedicated Resend webhook at the deployed APP_URL/api/webhooks/resend with:
  email.sent
  email.delivered
  email.delivery_delayed
  email.bounced
  email.complained
  email.failed
  email.suppressed

Store its own whsec_ signing secret in RESEND_WEBHOOK_SECRET. Keep other applications'
webhooks intact. The endpoint checks the raw body's Svix HMAC, signed event id and
timestamp (five-minute tolerance), then requires MailCheap tags, a persisted Resend
send attempt, matching account/message IDs and the exact saved recipient. Untagged
sign-in emails and other applications' events are ignored. Retry deliveries are
safe; temporary handler failures return HTTP 500 so Resend can retry.

MailCheap's existing pixel and redirect links track engagement. This handler ignores
Resend open/click events. Use MailCheap's existing double opt-in and unsubscribe
flows; this adapter uses the email API, not Resend Broadcasts or a separate contact
database.

Every newsletter send has a stable Idempotency-Key based on the saved account and
message IDs. Its first attempt is recorded before the API call. Resend retains keys
for 24 hours, so retries stop after 23 hours to avoid a duplicate after expiry. An
expired uncertain send requires checking Resend's email log before creating a new
send. Rate limits and temporary failures use the existing queue retry mechanism;
quota, credentials and domain failures pause with the provider's reason. No retry
uses a new key to bypass a conflict.

Keep SENDING_ENABLED=false until the public app, queue and webhook are working.
The adapter refuses newsletter sending without a webhook secret. Its presence alone
does not prove that the public endpoint is reachable: verify delivery before launch.
Platform sign-in emails use the original Resend integration independently of this
switch.

QStash is still required for campaign/background jobs. Production credentials come
from the Upstash console, and APP_URL must be publicly reachable. The official local
QStash development server is suitable for development only; its jobs are in memory.
Image uploads still require the original Vercel Blob or S3/CDN configuration.

Validation

  npm ci
  MONGOD_PATH=/path/to/mongod npm test
  npm run lint
  npm run build
  npm run dev

Tests in tests/resend.test.mjs run the real campaign action and send-batch handler
against an isolated MongoDB with mocked external HTTP. They test persistence,
domain adoption, ownership, idempotency, retry expiry, unsubscribe/feedback headers,
signature rejection, scoped suppressions and duplicate events. They do not send
real emails or prove inbox placement.

Reference contracts
  https://resend.com/docs/api-reference/emails/send-email
  https://resend.com/docs/api-reference/domains/get-domain
  https://resend.com/docs/api-reference/errors
  https://resend.com/docs/api-reference/rate-limit
  https://resend.com/docs/webhooks/verify-webhooks-requests
  https://resend.com/docs/webhooks/emails/bounced
  https://resend.com/docs/webhooks/emails/suppressed
  https://docs.svix.com/receiving/verifying-payloads/how-manual
