mail

Write emails as React components, send them through your provider, and preview them in development.

BackendServerBuilt onReact Email

What it is

@kitr/mail sends email from React components. defineMail pairs a component with a subject; the mailer renders HTML and plain text, checks every address and sends through a transport. A preview page shows each template in development.

Runs on the server only. To send without making a request wait, send from a job.

Install

kitr add mail

First time? Run npm i -g @kitr/kitr once. Inside a project, the global kitr runs your project's own version.

Adds @kitr/mail, its provider, config/mail.ts, an example template and the preview page. Adds server first if missing. Every change.

Quick start

Generate a template with kitr make:mail order-shipped:

// server/mail/order_shipped.tsx
import { defineMail } from '@kitr/mail'

export const orderShippedMail = defineMail<{ firstName: string; orderId: string }>('order_shipped', {
  subject: ({ orderId }) => `Order ${orderId} has shipped`,
  preview: { firstName: 'Ada', orderId: '1042' },
  render: ({ firstName, orderId }) => (
    <html lang="en">
      <body>
        <h1>Your order is on its way</h1>
        <p>Hi {firstName}, order {orderId} left our warehouse today.</p>
        <a href={`https://app.acme.com/orders/${orderId}`}>Track your order</a>
      </body>
    </html>
  ),
})

Send it from a controller:

// server/controllers/orders_controller.ts
import type { HttpContext } from '@kitr/api'
import { useMailer } from '@kitr/mail'
import { orderShippedMail } from '#server/mail/order_shipped'

export default class OrdersController {
  async ship({ app, params }: HttpContext<{ id: string }>) {
    return useMailer(app).send(orderShippedMail, { firstName: 'Ada', orderId: params.id }, { to: 'Ada Lovelace <[email protected]>' })
    // => { id: 'log-1', transport: 'log' }
  }
}

In development, with no RESEND_API_KEY, the server prints the message instead of sending it:

[@kitr/mail] to Ada Lovelace <[email protected]>: Order 1042 has shipped
Your order is on its way
Hi Ada, order 1042 left our warehouse today.
Track your order (https://app.acme.com/orders/1042)

The props are typed from the template, so leaving out orderId is a type error. Set RESEND_API_KEY and the same call sends a real email. Next in the guide: Send your first email.

Built on

Built on Role
React Email Components for email layouts (Html, Button, Section and the rest) that render to HTML every client can show.
Resend The built-in API transport.
Nodemailer The built-in SMTP transport.

kitr adds defineMail, address validation, plain-text rendering, attachments, a log transport for development and tests, a discard transport for deployments without a provider, the preview page and a MailTransport interface.

Problems it solves

Further reading