Email Service
Configure Resend to enable sign-up verification and password reset emails
Email Service
EasyStarter uses Resend as its email delivery provider. Two system emails are built in out of the box:
| Email type | When it is sent |
|---|---|
| Sign-up verification | After registration — the user must click the link to activate their account |
| Forgot password | When the user requests a password reset — sends a reset link |
Sign up for Resend and get an API Key
Official docs: Resend API Keys
- Go to resend.com and create an account
- After logging in, open the API Keys page
- Click Create API Key
- Give the key a name, e.g.
easystarter-production - Set permission to Sending access (sending permission is all that is needed)
- Click Add to finish
- Copy the generated API Key — it is only shown once, save it immediately
The copied value is your RESEND_API_KEY. It starts with re_, for example:
re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxVerify your sender domain
Resend requires a verified domain before you can send emails in production.
Official docs: Resend Domains
- Log in to Resend and go to the Domains page
- Click Add Domain
- Enter your domain, e.g.
yourdomain.com - Resend will provide a set of DNS records (TXT, MX, DMARC, etc.)
- Add these records in your DNS provider (e.g. Cloudflare)
- Back in Resend, click Verify DNS Records and wait for verification to pass
Once verified, the sender address will take the form noreply@yourdomain.com (the local part is configurable).
Testing: On Resend's free plan you can send emails to your own registered email address without a verified domain — useful for local testing.
Set RESEND_API_KEY
RESEND_API_KEY must be added to two environment variable files:
Local development (apps/server/.dev.vars):
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxProduction deployment (apps/server/.env.production):
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.env.production is used to bulk-push secrets to Cloudflare Workers via pnpm run secrets:bulk:production. It does not participate in the build directly.
Configure the sender address
The sender address is defined inside the common block in packages/app-config/src/app-config.ts:
common: {
app: {
name: "your-app-name", // Display name shown in the From field — change to your product name
// ...
},
email: {
provider: "resend",
from: {
localPart: "noreply", // local part of the address (before @)
domain: "yourdomain.com", // domain verified in Resend
},
},
// ...
},The resulting From field in the sent email is automatically composed from these two fields:
your-app-name <noreply@yourdomain.com>your-app-name→ taken fromcommon.app.name— update this to your own product namenoreply@yourdomain.com→ built by joiningemail.from.localPart+@+email.from.domain
Make sure
domainmatches the domain you have verified in Resend, otherwise sending will fail.
Built-in email templates
EasyStarter uses React Email to render email templates. The template source files are located at:
apps/server/src/emails/templates/
├── sign-up-verify-email.tsx # Sign-up verification email
└── forgot-password-email.tsx # Forgot password emailAll email content is i18n-aware and will automatically switch language based on the user's request locale.
To customise the email design or copy, simply edit the corresponding .tsx template file.
Extending to other email providers
EasyStarter's email layer is built around the EmailProvider interface. Plugging in any provider (e.g. SendGrid, Postmark, Mailgun) takes four steps.
Step 1: Register the provider key
Suppose using SendGrid as an example. Add the new provider key to SUPPORTED_EMAIL_PROVIDERS in packages/app-config/src/types.ts:
export const SUPPORTED_EMAIL_PROVIDERS = ["resend", "sendgrid"] as const;Step 2: Implement the provider
Create a new file in apps/server/src/emails/providers/ that implements the EmailProvider interface:
import type { EmailProvider, SendEmailParams } from "../types";
export function createSendGridEmailProvider(): EmailProvider {
return {
key: "sendgrid",
async send({ from, to, subject, html, text }: SendEmailParams) {
// Call the SendGrid SDK to send the email
},
};
}Step 3: Register it in the email providers map
Add the new provider to the providers map in apps/server/src/emails/index.ts:
import { createSendGridEmailProvider } from "./providers/sendgrid";
const providers: Record<EmailProviderKey, EmailProvider> = {
resend: createResendEmailProvider({ defaultFrom }),
sendgrid: createSendGridEmailProvider(),
};Step 4: Switch the configuration
Update email.provider in packages/app-config/src/app-config.ts to the new provider key:
email: {
provider: "sendgrid", // switch to the new provider
from: {
localPart: "noreply",
domain: "yourdomain.com",
},
},Once done, all built-in send functions (sendVerificationEmail, sendResetPasswordEmail) will automatically route through the new provider — no changes to business logic required.