Skip to content

Email

TSKit sends transactional emails using React Email for templates and Resend as the default delivery provider. The email driver is swappable - SendGrid is also supported.

Resend is the default provider.

  1. Create a Resend account.
  2. Go to API Keys and create a new key.
  3. Add it to your .env:
Terminal window
EMAIL_PROVIDER=resend
EMAIL_FROM=onboarding@resend.dev
RESEND_API_KEY=re_...

For development, you can use the default onboarding@resend.dev sender address. For production, you need to verify your own domain under Domains in the Resend dashboard and update EMAIL_FROM to an address on that domain.

To use SendGrid instead of Resend:

  1. Create a SendGrid account.
  2. Go to Settings > API Keys and create a key with “Mail Send” permissions.
  3. Verify a sender identity under Settings > Sender Authentication. SendGrid requires either a verified single sender or domain authentication before it will deliver emails.
  4. Add it to your .env:
Terminal window
EMAIL_PROVIDER=sendgrid
EMAIL_FROM=you@your-domain.com
SENDGRID_API_KEY=SG....

The email system follows the same config-driver-facade pattern as storage and payment:

  1. config/mail.ts defines email channels with provider and credentials.
  2. core/drivers/email/ implements the EmailDriver interface for each provider.
  3. lib/facades/mailer.ts provides the mailer facade that loads templates, renders them, and sends.

Use the mailer.send() function. The template name is the file name without the extension:

await mailer.send('verify-email', 'user@example.com', {
name: 'Jane',
url: 'https://app.example.com/verify?token=abc',
})

The function is type-safe. TypeScript knows which props each template expects based on the type map in emails/index.ts.

TSKit ships with six email templates:

TemplateWhen it’s sent
verify-emailAfter signup, to verify the email address
reset-passwordWhen a user requests a password reset
password-changedAfter a password is changed
subscription-createdAfter a new subscription is created
payment-failedWhen a payment fails
team-invitationWhen a user is invited to a team

Each template file in src/emails/ exports two things: a subject function that returns the email subject line, and a default React component for the email body.

Run the React Email dev server to preview templates in your browser:

Terminal window
bun run email:dev

This starts a preview server on port 3001 where you can see each template rendered with sample data.

See the Adding an Email Template reference for step-by-step instructions.

To add a provider beyond Resend and SendGrid, implement the EmailDriver interface in core/drivers/email/ and register it in the driver factory. See the Adding a Driver reference for the general pattern.

FilePurpose
lib/facades/mailer.tsMailer facade (template loading, rendering, sending)
config/mail.tsEmail channel config (provider, credentials)
core/drivers/email/resend.tsResend driver
core/drivers/email/sendgrid.tsSendGrid driver
core/drivers/email/types.tsEmailDriver interface
emails/index.tsTemplate registry and type map
emails/*.tsxIndividual email templates