Email delivery tracking

Record whether the beta access-code email was accepted, delivered or bounced, and connect the Brevo or Resend delivery webhook.

This page lets you see whether the access-code email sent when you approve a beta request reached the requester, and connect your email provider so that status keeps updating after the send.

What is recorded

Approving a request on the Admin page (Requests tab) generates an access code and emails it. Spectrace records one row per send: the provider (Brevo or Resend), the provider's message id, the recipient address and a status. A send the provider's API refused is stored as Not sent with the error, so the table shows it without waiting for anything else.

From there the provider's delivery webhook (a request the provider sends to Spectrace each time something happens to the email) advances the status by message id. Positive states only move forward; negative states are final and keep the provider's reason.

StatusMeaningBrevo eventsResend events
SentThe provider accepted the messagerequestemail.sent
DelayedThe provider is retryingdeferred, soft_bounceemail.delivery_delayed
DeliveredThe receiving mail server accepted itdeliveredemail.delivered
OpenedThe recipient opened or clicked it (only when the provider tracks opens)opened, unique_opened, clickemail.opened, email.clicked
BouncedThe address rejected it or does not existhard_bounce, invalid_emailemail.bounced
BlockedThe provider refused to send, for example a suppressed addressblockedemail.suppressed
Marked as spamThe recipient reported itspamemail.complained
Not sentThe send failederroremail.failed

The Admin requests table shows the status in the Code email column with the time of the last event and, for failures, the provider's reason. A request approved before tracking existed shows No record. When the webhook secret for the configured provider is not set, a notice above the table says statuses stop at Sent.

Events for emails Spectrace does not track (invites, digests, password resets) are acknowledged and ignored.

Connect Brevo

Brevo does not sign webhook deliveries, so the endpoint checks a shared secret. Brevo attaches custom headers and bearer auth only to webhooks created through its API, so create the webhook with a request rather than in the Brevo dashboard.

  1. Set the secret

    Generate a long random string (for example openssl rand -hex 32) and set it as BREVO_WEBHOOK_SECRET on your deployment, then redeploy. While it is unset, the endpoint rejects every delivery.

  2. Create the transactional webhook

    Replace <app-url> with your NEXT_PUBLIC_APP_URL and <secret> with the value from the previous step. The events names here are the API's spelling; the payloads Spectrace receives use the names in the table above (hardBounce arrives as hard_bounce). Leave batched off: Spectrace expects one event per delivery.

    bash
    curl -X POST https://api.brevo.com/v3/webhooks \
      -H "api-key: $BREVO_API_KEY" \
      -H "content-type: application/json" \
      -d '{
        "type": "transactional",
        "description": "Spectrace email delivery tracking",
        "url": "<app-url>/api/webhooks/email/brevo",
        "events": ["request", "delivered", "deferred", "softBounce", "hardBounce", "invalid", "blocked", "spam", "opened", "click"],
        "batched": false,
        "auth": { "type": "bearer", "token": "<secret>" }
      }'

    An x-webhook-secret header carrying the same value also works: pass "headers": [{ "key": "x-webhook-secret", "value": "<secret>" }] instead of auth.

  3. Check the first event

    Approve a request. Within a minute the Code email column moves from Sent to Delivered (or to a failure state with a reason). A rejected delivery is logged on the server as [brevo webhook] rejected: ... with the reason and never the secret.

Connect Resend

Resend signs every delivery (Svix), so the endpoint verifies the signature with the webhook's signing secret.

  1. Add the webhook in Resend

    In the Resend dashboard, open Webhooks and add an endpoint with the URL <app-url>/api/webhooks/email/resend. Select the email events: email.sent, email.delivered, email.delivery_delayed, email.bounced, email.suppressed, email.complained and email.failed, plus email.opened and email.clicked if you track opens.

  2. Set the signing secret

    Copy the webhook's signing secret (it starts with whsec_) and set it as RESEND_WEBHOOK_SECRET on your deployment, then redeploy. While it is unset, the endpoint rejects every delivery.

Limits

  • Only the beta access-code email is recorded. Other transactional emails are sent but not tracked.
  • There is no resend action yet. A bounced code is visible, but the fix is to correct the address and approve a fresh request.
  • Delivery records are kept until an account with the recipient's email address is deleted; see Data retention and deletion.