guide · resend email api
How should a product team implement the Resend email API safely?
Implement the Resend email API behind a trusted server worker, not in browser or mobile code. Verify the exact sending domain, create a sending-only API key restricted to that domain where practical, persist an approved outbound job, and pass a stable `Idempotency-Key` to `POST /emails`. Store the returned email ID, verify webhook signatures before parsing, process events idempotently, and suppress unsafe recipients. Keep API acceptance, provider sending, receiving-server delivery, and inbox placement as separate states.
Define the product operation before the provider request
Start with a narrow application operation such as account verification, a receipt, a security alert, or a notification the recipient requested. The public product endpoint should authorize the caller, tenant, message class, sender identity, recipients, and template before any Resend payload exists. Do not let a browser submit arbitrary `from`, `to`, HTML, or provider options while holding a reusable credential. Create a durable internal outbound record containing an application event key, tenant, template revision, approved sender, recipient set, and current state. A worker can translate that record into the provider request. This boundary keeps API keys and untrusted message content away from clients, makes duplicate prevention testable, and allows the product to change providers without rewriting every business workflow. Separate transactional and consent-dependent messages in the internal model so preferences, suppressions, and incident decisions remain explicit.
Verify the exact domain used in the From address
Add a domain you control in Resend and publish the DNS records shown for that domain. Verify the actual organizational domain or subdomain used in the visible From address rather than assuming that an unrelated parent identity covers it. Review existing SPF and DMARC policy before changing DNS, and never create a second SPF record for the same hostname. Use a purpose-specific sending subdomain when isolation, ownership, or migration requirements justify it. After the dashboard reports verification, inspect a received test message to confirm the visible From address, DKIM signing identity, return path, authentication results, and reply behavior. Provider verification proves that a configured identity met the provider setup check. It does not prove recipient consent, receiving-server acceptance, inbox placement, or good reputation. Preserve DNS ownership and change history outside the provider dashboard so rotation and rollback remain possible.
Create a least-privilege API key for each workload
Resend documents API keys with access levels and optional domain restriction. A sending worker should use a key limited to sending access and, when the architecture permits, to the one domain that workload owns. Keep management, domain, webhook, and account administration under separate authority. Create separate keys for development, staging, and production so a lower environment cannot send with production identity or consume its limits. Store each secret directly in a managed secret store, expose it only to the server process that needs it, and pass it as Bearer authorization over HTTPS. Do not copy the key into source control, build artifacts, logs, templates, analytics, tickets, or prompts. Rotation should be rehearsed: create an equivalently scoped replacement, update the worker, verify controlled traffic and event correlation, then revoke the old key. Alert on unexpected authentication and authorization failures because they can signal expiry, revocation, scope drift, or secret exposure.
Make one durable job and one idempotent send attempt
Reserve the internal outbound job before calling Resend. Derive an idempotency value from a stable product fact such as tenant, operation type, and immutable application event ID, not from a random retry attempt. Send that value in the `Idempotency-Key` header. Resend currently documents that these keys prevent duplicate email requests, expire after 24 hours, and can contain at most 256 characters. That provider window is helpful but is not a complete product-level duplicate guarantee. Keep a uniqueness constraint on the internal event key for longer business workflows, serialize workers that can claim the same job, and store the provider email ID returned by a successful request. If a network timeout makes acceptance ambiguous, hold the job in an unknown state and reconcile it against provider logs or events before resending. Reusing one stable key for the same logical operation is safer than generating a fresh key for every transport retry.
Construct and validate the email request deliberately
The Resend send-email endpoint accepts a From address, recipients, subject, and message content, with documented options such as text, HTML, React-rendered content, templates, Cc, Bcc, reply-to, headers, attachments, tags, and scheduled delivery. Expose only the subset the product needs. Validate address syntax and tenant ownership, cap recipient and attachment counts below provider limits, reject newline injection in headers, and build MIME-related content through maintained libraries or trusted provider fields. Do not place credentials, sensitive personal data, or unrestricted customer input in tags or headers. Store a template revision and sanitized variables rather than logging full content. An internal adapter should return a narrow result such as accepted provider ID or classified failure, not leak provider response details into business code. This makes it possible to update provider-specific field names, SDK versions, or request limits without changing the product event contract.
Classify API responses and usage limits before retrying
Treat the HTTP response as one observation in the workflow. A successful send response returns an email identifier that should be stored with the internal job, but it does not establish destination acceptance or inbox placement. Correct validation, authentication, domain, permission, and payload errors instead of retrying them blindly. Resend documents API request limits and returns rate-limit and quota headers, including fields describing remaining capacity, reset timing, and retry delay; a 429 response should wait for the documented interval with added jitter. Retry transport failures and eligible server errors with exponential backoff, a finite attempt count, and the same logical idempotency key while its documented window applies. Ambiguous failures require reconciliation because the provider might have accepted the email even when the client did not receive the response. Alert when repeated failures cluster by domain, template, key, or tenant, but keep credentials, full content, and unnecessary recipient data out of operational logs.
Authenticate webhook requests before processing events
Configure a dedicated HTTPS webhook endpoint and retain the exact raw request body. Resend documents webhook signing through Svix-compatible headers and signing secrets. Verify the webhook ID, timestamp, and signature over the unmodified payload before JSON parsing or re-serialization, and use the official verification flow or a maintained compatible library. Reject invalid or stale requests, cap request size, and keep the signing secret separate from the sending key. After authentication, durably store or enqueue the event before acknowledging it so a process crash does not silently discard delivery evidence. Delivery systems can retry and duplicate webhooks, so use the event identifier as a deduplication key and make state transitions monotonic. A later or duplicate event must not overwrite a more informative terminal result merely because it arrived last. Record verification failures and event lag as operational signals without persisting raw message content beyond the necessary retention period.
Model provider events without overstating delivery
Resend publishes named email event types including sent, delivered, delivery delayed, bounced, complained, failed, opened, and clicked. Map those provider names into an internal state model with the original event type, provider email ID, event ID, timestamp, recipient scope, and available diagnostic data. A sent event describes provider progress. A delivered event reports delivery according to Resend’s documented event semantics, but SMTP success at a receiving system still does not reveal the recipient’s final folder. Opens and clicks are engagement observations, not delivery proof, and privacy technology can affect them. Bounces, complaints, and permanent failures should update recipient-safety state before the next send decision. Keep provider event history append-only and derive the user-facing status from explicit rules. This preserves evidence for support and avoids unsafe retries after responsibility has transferred or a recipient has supplied a negative signal.
Test failure and recovery paths with controlled recipients
Use a non-production key, a controlled verified subdomain, and mailboxes owned by the team. Test text and HTML content, reply-to behavior, attachment limits, stable idempotency keys, and stored provider identifiers. Submit the same logical job twice and confirm the application and provider controls do not create an unintended duplicate. Exercise invalid payload, wrong domain, revoked key, insufficient permission, rate limit, transport timeout, bounce, complaint, delivery delay, duplicated webhook, modified signature body, stale webhook timestamp, and signing-secret rotation. Confirm that event intake is durable before acknowledgement and that recipient safety blocks a later job. Test DNS rotation and provider removal without deleting unrelated records. Dashboards should cover send failures, latency, webhook verification failures, event lag, bounces, complaints, and reconciliation queues. Review current Resend documentation and account settings at launch because quotas, limits, event fields, and available permissions can change independently of deployed application code.
Compare published API capabilities before migrating
SendHQ publishes an OpenAPI 3.1 contract for its workspace-scoped email API, including verified-domain sending, inbound email, hosted templates, delivery events, and suppressions. Before migrating an integration, compare request bodies, authentication, idempotency, returned identifiers, error shapes, webhooks, domain rules, and suppression behavior, then validate them with field-level tests. Do not assume compatibility from similar endpoint names.
Frequently asked questions
What endpoint sends an email through Resend?
Resend documents `POST https://api.resend.com/emails` with Bearer authorization. Call it only from trusted server code after authorizing the product operation, sender domain, recipients, and content.
How should a Resend API key be scoped?
Use a sending-access key and restrict it to the workload’s domain when the documented controls fit the architecture. Keep production, non-production, and administrative authority on separate secret-managed credentials.
Does a successful Resend API response prove delivery?
No. It records provider acceptance and returns an email identifier. Later authenticated events can report provider progress and receiving-system delivery, while inbox placement remains a separate receiver-side classification.
How does Resend idempotency prevent duplicate emails?
Send one stable `Idempotency-Key` for the same logical request. Resend currently retains keys for 24 hours with a 256-character maximum, so keep a longer-lived internal uniqueness constraint as well.
How should Resend webhook signatures be verified?
Retain the exact raw request body and verify the documented Svix-compatible webhook ID, timestamp, and signature headers before parsing. Reject invalid or stale input, then durably enqueue authenticated events before acknowledging them.
Can SendHQ replace Resend?
Compare the published API contracts and run field-level integration tests before treating SendHQ and Resend as compatible.
Sources
- Resend Send Email API — Resend
- Resend API Keys — Resend
- Resend Domains — Resend
- Resend Idempotency Keys — Resend
- Resend Usage Limits — Resend
- Resend Webhooks — Resend
- Verify Resend Webhook Requests — Resend
- Resend Webhook Event Types — Resend
- RFC 5321: Simple Mail Transfer Protocol — RFC Editor
- SendHQ OpenAPI Contract — SendHQ