Email with Resend
Configure Better Auth and contact email delivery through Resend on Cloudflare Workers.
Transactional email is Integrated with Resend. Verification, password reset,
and contact messages share sendEmail() and React Email templates. A newsletter
template is included only as an asset; there is no newsletter user flow.
Included flow
| Flow | Call site | Template | Recipient |
|---|---|---|---|
| Email verification | src/lib/auth.ts | verify-email.tsx | New user |
| Password reset | src/lib/auth.ts | forgot-password.tsx | User requesting reset |
| Contact form | src/routes/api/contact.ts | contact-message.tsx | websiteConfig.mail.supportEmail |
| Newsletter | Not wired | subscribe-newsletter.tsx | None |
src/lib/email/index.ts lazily constructs the Resend client when sendEmail()
is first called. This request-time initialization is important on Workers,
where server secrets are not safe to capture during top-level module evaluation.
The Resend SDK sends through its HTTP API, which fits the Worker runtime.
Shared email-layout.tsx and email-button.tsx provide the React Email shell
and call-to-action. The shipped subjects and templates are English; UI
internationalization does not automatically localize email.
subscribe-newsletter.tsx is only a reusable template. The template has no
subscription endpoint, subscriber table, confirmation, preference center, or
unsubscribe flow.
Setup
Create a Resend key
For local development, add the server-only value to .env:
RESEND_API_KEY=re_your_keyFor production, store it as a Worker secret:
pnpm wrangler secret put RESEND_API_KEYDo not turn it into a VITE_* variable or commit it to wrangler.jsonc.
Verify the sending domain
Add the DNS records requested by Resend and wait for domain verification. Configure SPF, DKIM, and DMARC according to your delivery policy.
Set sender and support addresses
Update src/config/website-config.ts:
mail: {
provider: "resend",
fromEmail: "Example <noreply@mail.example.com>",
supportEmail: "support@example.com",
}fromEmail must be allowed by the verified Resend domain. supportEmail
receives contact submissions.
Local behavior and errors
Without a valid key, sendEmail() catches the provider failure and returns
{ success: false, error }; no message is delivered. This lets the application
boot for local UI/database work, but email-dependent verification and reset
cannot be fully tested.
The current auth callbacks await sendEmail() without inspecting its structured
result. The contact route also does not propagate a returned provider error, so
it can report request success even when Resend rejected delivery. Before relying
on email for a critical workflow, log a safe failure identifier and either
propagate, retry, or queue the failure according to product policy.
The contact route Zod-validates name, email, subject, and message length, but it is public. Add rate limiting, spam/abuse controls, and observability before launch.
Customize templates
Edit files under src/lib/email/templates and keep the shared layout neutral
enough for all transactional messages. Replace the hard-coded SoarStarter
footer and current-year behavior when rebranding.
For localized mail, pass an explicit locale from the triggering flow and select the corresponding subject/template copy. Do not infer it from browser state in a delayed job. Store the user's chosen locale when reliable email localization matters.
Verify
- Register a user and receive a verification message with a working production-origin link.
- Request a password reset and complete it through the received link.
- Submit the contact form and confirm the configured support inbox receives it.
- Invalid contact payloads fail validation; spam controls reject abusive traffic.
- Missing/invalid API keys produce visible server-side diagnostics without leaking message bodies or secrets.
- Resend dashboard events, bounces, and complaints are monitored.
Production notes
Respect provider sender and rate limits. Add retry/queue semantics for critical mail, idempotency where repeated callbacks are possible, and alerts for sustained delivery failures. Avoid logging recipient data or message bodies. Keep auth URLs on the deployed origin and rotate the Worker secret through Wrangler.
