Skip to content

feat: add --dry-run to emails batch and broadcasts send - #399

Open
Abhinav-2002 wants to merge 1 commit into
resend:mainfrom
Abhinav-2002:main
Open

Abhinav-2002 wants to merge 1 commit into
resend:mainfrom
Abhinav-2002:main

Conversation

@Abhinav-2002

@Abhinav-2002 Abhinav-2002 commented Oct 3, 2026 •

Copy link
Copy Markdown

See discussion: #398

Closes the gap noted in the README:

likely next candidates are emails batch (large JSON files) and
broadcasts send (confirm id + schedule before delivery).

What changed

resend emails batch --file ./emails.json --dry-run

Parses and validates the JSON array, normalises snake_case field aliases
(scheduled_at → scheduledAt, reply_to → replyTo, topic_id → topicId),
and renders any --react-email template. Note: rendering a --react-email template
uses esbuild to bundle and run the .tsx file, which means it executes local code
even during a dry-run.

The command then prints:

{ "dryRun": true, "request": [ ... ] }

No API key required (and it skips verifying key permissions). All existing validation (bad JSON, missing file, attachments
in batch, per-entry type checks) still runs before bail-out — you get the same
error codes as a real send. Note: passing an empty array [] now fails with
invalid_format to enforce non-empty batches during the dry-run, which also applies
to live runs.

resend broadcasts send <id> --dry-run

Echoes back the provided broadcast ID (using the interactive picker if omitted),
then prints:

{ "dryRun": true, "request": { "id": "...", "scheduledAt": "..." } }

No API key required, so the ID is not verified against the API. scheduledAt is
omitted when not set.

Output format

{ "dryRun": true, "request": ... } — identical to emails send --dry-run and
broadcasts create --dry-run.

Testing

Automated (8 new tests, 0 regressions):

emails batch --dry-run:

  • No SDK call made
  • Works without an API key
  • Empty array [] properly errors with invalid_format
  • snake_case aliases normalised in printed output
  • --react-email renders into request[n].html without sending

broadcasts send --dry-run:

  • No SDK call made
  • scheduledAt appears in request when --scheduled-at is set; absent when not
  • Works without an API key

Pre-existing failures on table.test.ts / spinner.test.ts (Windows terminal
encoding: ASCII fallback + vs Unicode ┌, v vs ✔) are unrelated to this
change — they fail on clean main too.

Manual:

# batch dry-run with delivered@resend.dev / bounced@resend.dev — nothing sent
node dist/cli.cjs emails batch --file ./emails.json --dry-run

# broadcasts send dry-run with fake ID — nothing sent
node dist/cli.cjs broadcasts send fake-id-1234 --scheduled-at "in 2 hours" --dry-run

# no API key — still works
unset RESEND_API_KEY
node dist/cli.cjs emails batch --file ./emails.json --dry-run   # exit 0
node dist/cli.cjs broadcasts send fake-id --dry-run             # exit 0

# bad input — clear errors
node dist/cli.cjs emails batch --file broken.json --dry-run
# => {"error":{"message":"File content is not valid JSON.","code":"invalid_json"}}

Note on AI assistance

I used an AI coding assistant (Antigravity) to help write this. I read every changed
line, ran the full test suite, and verified all the manual behaviour above myself.
The design decisions (where to bail, what to output, how to handle react-email) are
ones I can explain.


Summary by cubic

Adds --dry-run to emails batch and broadcasts send so complex payloads can be validated and inspected before a high-impact send.

  • Prints { "dryRun": true, "request": ... } without calling the API, matching emails send and broadcasts create, and skips the API key and permission check.
  • All existing validation and error codes still apply; --react-email templates are rendered during dry-run, which executes the local .tsx code.
  • Empty batch arrays now fail with invalid_format during dry-run, and this also applies to live sends.
  • broadcasts send --dry-run echoes the given ID (or prompts for it interactively) along with any scheduledAt.

Written for commit f3630d6. Summary will update on new commits.

Review in cubic

@github-actions github-actions Bot added the linear-synced PR has been synced to Linear label Oct 3, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

linear-synced PR has been synced to Linear

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant