Skip to content

Configuration

sarmakska edited this page Jun 7, 2026 · 3 revisions

Configuration

Two required variables, the rest optional. All are read from the environment, and .env.example lists them.

Required

RESEND_API_KEY

Resend API key. Sign up at resend.com; the free tier ships 3,000 emails per month.

NOTIFY_EMAIL

Where every webhook email lands. Comma-separate for several recipients:

NOTIFY_EMAIL=alice@team.com,bob@team.com

Optional: sender

FROM_EMAIL

Default: webhooks@onresend.dev

In production, use your own verified domain. The default sender is fine for testing but flagged as spam by some receivers. Verify a domain in Resend, Domains, Add, then add the DNS records they show.

Optional: HMAC verification

WEBHOOK_SECRET

If set, every request must include a valid HMAC signature. The verifier picks the scheme from the :source segment, so /hooks/stripe uses the Stripe profile, /hooks/github the GitHub profile, and so on. Generate a secret:

openssl rand -hex 32

When unset, signature verification is disabled. See HMAC-Verification for the per-provider detail.

Optional: dead-letter replay

WEBHOOK_REPLAY_TOKEN

If set, enables POST /dead-letter/:id/replay behind this bearer token, which re-enqueues a stored failure for another delivery attempt. While unset the endpoint returns 404, so a public deployment cannot be probed. Generate one the same way as the HMAC secret:

openssl rand -hex 32

See Retry-and-Dead-Letter for the full replay flow.

Optional: fan-out

SLACK_WEBHOOK_URL

If set, every delivered event is also posted to Slack as a Block Kit message. Get one from Slack, Apps, Incoming Webhooks, Add to channel.

TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID

Both must be set for Telegram fan-out to activate. Create a bot with @BotFather to get the token, and resolve your chat id (for example via @userinfobot). See Fan-Out.

Optional: retry and dead-letter

RETRY_MAX_ATTEMPTS

Default: 5. Delivery attempts before a job is dead-lettered.

RETRY_BASE_DELAY_MS

Default: 500. The base backoff delay, doubled each attempt.

RETRY_MAX_DELAY_MS

Default: 30000. The backoff cap.

DEAD_LETTER_FILE

Default: ./data/dead-letter.jsonl. Path for the dead-letter JSON Lines file. Mount a volume here in production so failures survive a redeploy. See Retry-and-Dead-Letter.

Optional: server

PORT

Default: 3000. The port Express listens on.

Limits and tuning

  • Body size. 1MB. Raise the bodyLimit passed to createApp in src/app.js if a source sends more.
  • Recipients. NOTIFY_EMAIL accepts a comma-separated list, passed straight to Resend.
  • Resend rate limits. The free tier caps the send rate. The retry queue absorbs short rate-limit spikes via backoff; sustained excess needs a higher Resend plan or several instances.

Clone this wiki locally