Email (Resend)
All transactional email in the system flows through one Netlify function:
send-email.js, which lives in studio-website. The admin has no email function
of its own — it calls this endpoint. Email is sent via Resend from
hello@sitecrate.ca.
The send-email function
Section titled “The send-email function”netlify/functions/send-email.js:
- Accepts a small request body:
{ type, token }(plus any type-specific flags). - Resolves the project from the DB by
tokenusing the service-role key. - Builds all recipients and content server-side — never from the request body. A forged body cannot redirect the email or inject content.
- Locks CORS to SiteCrate origins.
- Sends through Resend.
It requires SUPABASE_SERVICE_ROLE_KEY and the Supabase URL in the function env.
See Environments.
Email types
Section titled “Email types”| Type | Fired by | Trigger |
|---|---|---|
intake | studio-website intake form | New intake submitted (non-blocking) |
review | sitecrate-admin | Stage → review (requires preview_url) |
launch | sitecrate-admin | Stage → live |
feedback | studio-website status page | Client submits feedback |
approved | studio-website status page | Client approves their site |
The review guard
Section titled “The review guard”Who calls it
Section titled “Who calls it”| Caller | Types | Notes |
|---|---|---|
| studio-website intake | intake | Fired after create_intake returns the token; non-blocking |
| studio-website status page | feedback, approved | Fired after the matching RPC write |
| sitecrate-admin Detail panel | review, launch | Fired on stage transition; calls https://sitecrate.ca/.netlify/functions/send-email |
Email log (admin)
Section titled “Email log (admin)”The admin’s email-log.js function reads the last 20 Resend emails matching
a subject query. It exposes client email metadata, so it’s gated — any active
team member can call it, but only with a valid Bearer JWT verified against
user_roles. See sitecrate-admin.