Operations & Internal Tools
Connect Supabase and Resend
Email that leaves your app once, from your own domain, with proof it arrived.
- Data flows
- 4 automated, two-way where safe
- Built with
- Supabase Postgres, Resend API, Supabase Auth SMTP
- Timeline
- Live in 3 to 5 business days from scope
- Owned by
- You. Accounts, credentials and code in your name.
In short
Connecting Supabase to Resend lets your app send reminders, alerts and sign-in emails from your own domain, and store what happened to each one. SBD runs this in production: a Supabase-backed operations tool sends a daily reminder digest through Resend, and another platform uses Resend as custom SMTP for Supabase Auth.
The workflows
What runs between Supabase and Resend.
Each line is one automated workflow. An event in one tool, the checks and mapping in between, the action in the other, and the person who hears about it.
-
Daily reminder digest per person
WhenThe daily scheduled job runs
Automation- Verify and validate
- Map and normalise
- Upsert by key
ThenGather every reminder due today and send one Resend digest per person, recording each send first
And- Audit log entry
- Alert if it fails or goes quiet
- Review queue if unsure
-
Invites and alerts from app events
WhenA row is inserted that needs an email, such as an invite
Automation- Verify and validate
- Map and normalise
- Upsert by key
ThenA database webhook or server action calls Resend with an idempotency key
And- Audit log entry
- Alert if it fails or goes quiet
- Review queue if unsure
-
Sign-in links from your own domain
WhenA user asks for a sign-in link
Automation- Verify and validate
- Map and normalise
- Upsert by key
ThenSupabase Auth sends it through Resend as custom SMTP, from your domain
And- Audit log entry
- Alert if it fails or goes quiet
- Review queue if unsure
-
Bounces and complaints stored back
WhenResend reports delivered, bounced or complained
Automation- Verify and validate
- Map and normalise
- Upsert by key
ThenVerify the webhook signature and store the event against the send in Supabase
And- Audit log entry
- Alert if it fails or goes quiet
- Review queue if unsure
Every record passes through the same stages
- 1Receive
Webhook or polling from the source tool, with a signed payload and a replay log.
- 2Validate
Required fields present, types right, record key found. Anything else goes to the review queue.
- 3Map
Fields translated to the destination schema. Enumerations, currencies and dates normalised.
- 4Upsert
Written against the record key, so a retry updates rather than duplicates.
- 5Confirm
Outcome logged. Alert if the count goes quiet. Reconciliation run nightly.
Read this first
Why the obvious route breaks.
A one-step Zap connects Supabase and Resend in an afternoon. This is what goes wrong once real volume and real edge cases arrive.
A retried job sends the email twice
Scheduled jobs get retried. Resend accepts an Idempotency-Key header, keeps it for 24 hours, and returns the original response for a repeat. Our reminder job also records every send under a unique key before sending, so a rerun after a failure cannot produce a second copy.
The built-in Supabase email is not for production
Supabase Auth’s default email service only delivers to members of the project team and is limited to 2 messages an hour. Supabase says it is not meant for production and that real users need custom SMTP. Resend is one of the providers it lists.
One read stops at 1,000 rows
The Supabase Data API returns at most 1,000 rows per request by default. A reminder job that reads its table once quietly skips everyone after row 1,000. Our job reads a page at a time and stops the run if any page fails, rather than reminding part of the list.
The rate limit is per team, not per key
Resend allows 10 requests a second per team by default, shared across every API key. A nightly run that sends one email per record can hit 429s. Sending one digest per person, as our reminder job does, keeps volume low and the inbox readable.
What it costs today
The gap, as the team feels it and as the engineer sees it.
In the team
- Reminders depend on someone remembering to send them
- Sign-in emails never reach real users
- People get the same reminder twice after a retry
- Nobody knows an email bounced
- A dozen separate emails a day instead of one list
Under the hood
- Default Supabase Auth email limited to the team, 2 an hour
- 1,000-row default cap on Data API reads
- 10 requests a second per Resend team
- Idempotency keys kept for 24 hours
- Webhook signatures need the raw body
What we wire up
The data flows.
- 01 When
The daily scheduled job runs
ThenGather every reminder due today and send one Resend digest per person, recording each send first
- 02 When
A row is inserted that needs an email, such as an invite
ThenA database webhook or server action calls Resend with an idempotency key
- 03 When
A user asks for a sign-in link
ThenSupabase Auth sends it through Resend as custom SMTP, from your domain
- 04 When
Resend reports delivered, bounced or complained
ThenVerify the webhook signature and store the event against the send in Supabase
Used for
- Daily reminder digest per person
- Invites and alerts from app events
- Sign-in links from your own domain
- Bounces and complaints stored back
- Supabase transactional email
- Resend custom SMTP for Supabase Auth
- Scheduled email from Postgres
- Idempotent reminder emails
- Email delivery tracking in Supabase
- Website form notifications
Built with
Data map
What becomes what, and what it is keyed on.
| In Supabase | In Resend | Matched on | Direction |
|---|---|---|---|
| Reminders due today, by assignee | One digest email per person | Assignee and date | one-way |
| Sent reminders ledger | Idempotency key on the send | Entity, reminder kind and due date | one-way |
| Auth sign-in and invite events | Email through Resend SMTP | User ID | one-way |
| Delivery events table | Delivered, bounced and complained webhooks | Resend email ID | one-way |
Field-level mapping is agreed in the blueprint and written into the runbook. Two-way rows carry loop protection so a write from the sync never re-triggers the sync.
In every build
What you get with the sync, whichever pair.
Under the hood
- Upserts keyed on the record
Every write is matched on the source ID. A retry or a re-fire updates the existing record instead of creating a second one.
- Retries with backoff
Rate limits and timeouts are retried with increasing delays, then parked for review, never dropped.
- Idempotent, loop-safe writes
Two-way flows carry a marker so a change written by the sync does not re-trigger the sync.
- Reconciliation
A nightly job compares counts and totals on both sides and lists any record that differs.
- Audit log
Every run records input, mapping result, action taken and who or what triggered it. Searchable by record.
- Error monitoring
Loud failures alert within minutes. Quiet ones are caught by an outcome count that alerts when it stops moving.
- Review queue
Records the sync is not sure about land in a screen a person can read, correct and release.
- Scoped credentials
One credential per connection, limited to the objects it needs, stored encrypted, in your account.
For the team
- Slack or email notifications
The alerts go to a named person, not a channel nobody reads. You choose Slack, email, WhatsApp or all three.
- A runbook
One document per integration: what it does, what each alert means, and what to do in the first ten minutes.
- Training
A live session with the people who will use the review queue, recorded for whoever joins later.
- Handover
Admin access, billing and code sit in accounts in your name from day one. If we leave, it keeps running.
- Sixty days of hypercare
The engineers who built it stay on call after go-live, fix what breaks and tune what the team asks for.
- A monthly report
Runs, records synced, exceptions handled, and what changed. Plain language, one page.
Security and your data
Where the data goes, and who holds the keys.
- Accounts
- Every platform account is created in your name. We work through managed access you can revoke.
- Credentials
- Stored encrypted in the orchestration layer. Scoped per connection. Rotated on handover.
- Data in transit
- TLS everywhere. Webhooks verified by signature before anything is processed.
- Data at rest
- Only what the sync needs. No copies of your customer data on our machines.
- AI steps
- Where an integration uses a model, it is through a business API that does not train on your data.
- Retention
- Run logs kept 90 days by default, adjustable. Payloads redacted of card and ID numbers.
- Agreements
- DPA and NDA on request. Regional rules covered in our privacy policy.
Keys and sensitive data
How API keys, tokens and personal data are handled.
- Keys live in a vault, never in code
API keys and tokens are stored in the orchestration layer's encrypted credential store or the platform's secret manager. None are written into workflows, repos, spreadsheets or chat.
- One credential per connection
Each integration gets its own key, scoped to the objects and actions it needs. A lead sync cannot read invoices. Revoking one key stops one thing.
- Service accounts, not personal logins
Connections use a dedicated service user in your account, so nothing breaks when a person leaves and nothing runs under someone's name.
- Two-factor on every account
Every platform account we set up has two-factor authentication on, with recovery codes handed to you, not kept by us.
- Rotation on handover and on request
Keys are rotated when the build is handed over, when anyone with access leaves, and at any time you ask.
- Secrets never reach the logs
Audit logs redact tokens, card numbers, government IDs and anything you flag as sensitive before a line is written.
- Webhooks verified before processing
Inbound calls are checked against the sending tool's signature. Unsigned or stale payloads are dropped and counted.
- Access you can see and revoke
Our access is through managed roles in your accounts. You can list it, limit it, and remove it in one click without touching the build.
Engineering decisions
Decided before the first workflow is written.
- Rate limits and backoff
Every API has a ceiling. Calls are batched, queued and retried with increasing delays so a busy hour does not become a failed one.
- Backfill and pagination
The first run has to load history, not just new events. Backfills page through the source in order, resume after interruption, and never double-write.
- Out-of-order and duplicate events
Webhooks arrive twice and out of sequence. Each event carries a version or timestamp, and older versions never overwrite newer state.
- Schema changes
A renamed field or a new dropdown value is the most common silent failure. Payloads are validated against a contract, and a mismatch stops the run and raises a flag.
- Time zones, currencies, units
Dates are stored in UTC and shown local. Money carries its currency. Quantities carry their unit. Conversions happen once, in the map step.
- Sandbox first
Builds run against sandbox or test accounts with seeded data before they touch production. Go-live is a switch, not a rewrite.
- Versioned and reversible
Workflows and code are version-controlled. A release can be rolled back in minutes without losing the records processed since.
- API deprecations watched
Tools retire API versions on a schedule. We track the dates for every connection in the runbook and upgrade before the cut-off.
- Cost per run known
Each workflow has a cost per execution, including any model calls, logged alongside the run. You see the bill before it arrives.
- Metrics, not just errors
Runs per hour, records in and out, exception rate and latency are charted. Trends show a problem before an alert does.
Proof
Where we have done this.
- Customer story
Internal operations tool replacing SmartSuite
The Supabase-backed operations tool sends a daily reminder digest through Resend, one email per person, with each send recorded so a retry never duplicates it.
Read the story - Customer story
AI outbound sales platform
Resend carries the platform’s own mail on a Supabase stack, including sign-in links through custom SMTP, invites, alerts and scheduled reports.
Read the story
The offer
Hire SBD to connect Supabase and Resend.
A fixed scope, agreed in a discovery call, and live in three to five business days. Accounts in your name. The engineers who built it on call for sixty days after.
- ScopeOne call to agree the flows, the fields and the owner. Written up the same day.
- Build4 workflows, the data map above, validation, upserts, retries and reconciliation.
- Go-liveSandbox first, then a switch. Day three to five from scope for most pairs; longer only if a tool needs approval, such as WhatsApp templates.
- HandoverRunbook, training session, alerts to a named owner, admin access and code in your accounts.
- AfterSixty days of hypercare, then a care plan or run it yourself.
Questions
What people ask about this pair.
Where should the scheduled job run?
Either works. Supabase Cron is built on pg_cron, can call an Edge Function over HTTP, and records each run in cron.job_run_details. Our reminder job runs on Vercel Cron next to the app. What matters is that the job is safe to run twice and alerts when it fails.
Do we need our own domain?
Yes. Resend sends from a domain you own and have verified, not a shared one. Setting it up is part of the build, and it is what lets reminders and sign-in links arrive from your name rather than a provider address.
How do we know an email arrived?
Resend sends webhooks for events such as email.delivered, email.bounced, email.complained and email.delivery_delayed. We verify the svix signature headers against the raw request body, then store the event against the send, so a bounce becomes a visible fix rather than a silent gap.
Does SBD use Resend itself?
Yes. The forms on this site deliver submissions to our inbox through Resend, and it is listed on our trust page as a subprocessor.
Related
-
Retool and Supabase
Screens in Retool, data in a Postgres database you own and can expose safely.
-
n8n and QuickBooks
Bookkeeping workflows you can read, own and rerun, posting to the QuickBooks file your accountant trusts.
-
HubSpot and Slack
Notifications people act on, rather than a channel that gets muted in week two.
- Solution
Operations
Every workflow we automate for this kind of team.
Supabase and Resend
Every reminder sent once, from your domain, with proof.
Scheduled digests, event emails and sign-in links from your Supabase app through Resend, with idempotent sends and delivery events stored back, built in three to five business days.
Start with a discovery call