API reference

mail

Every export of @kitr/mail, @kitr/mail/provider, read from the published type definitions. The guide shows them in use.

@kitr/mail

address

function address(input: Recipient): Address;

Parse a recipient ('Ada <[email protected]>', quoted names included) into an Address, trimming the email.

createDiscardTransport

function createDiscardTransport(options?: {
  print?: boolean;
}): MailTransport & {
  count: number;
};

Accepts every message and sends nothing, printing only the recipients and subject (never the body, so reset links stay out of logs). Allowed in production: for a preview deployment or a demo that has no mail provider yet. Set MAIL_TRANSPORT=discard in the generated config to use it.

createLogTransport

function createLogTransport(options?: {
  print?: boolean;
}): MailTransport & {
  messages: Message[];
};

Keeps messages in memory (mailer.sent) and prints them unless print: false; the default outside production. Never cleared, so not for production.

createMailer

function createMailer(options?: CreateMailerOptions): Mailer;

Create a mailer without the provider, for scripts and tests. Uses the log transport when none is given.

createResendTransport

function createResendTransport(options: {
  apiKey: string;
  fetch?: typeof fetch;
}): MailTransport;

Sends through Resend's HTTP API with fetch. A non-2xx response throws Resend <status>: <body>.

createSmtpTransport

function createSmtpTransport(nodemailer: NodemailerLike | {
  default: NodemailerLike;
}, options: {
  host: string;
  port?: number;
  secure?: boolean;
  auth?: {
    user: string;
    pass: string;
  };
}): MailTransport;

SMTP through nodemailer (pnpm add nodemailer). Pass the module in so the bundler sees a real dependency: createSmtpTransport(nodemailer, { host, port, auth }).

defineMail

function defineMail<Props = Record<string, never>>(name: string, template: Omit<MailTemplate<Props>, 'name'>): MailTemplate<Props>;

Declare an email template. The type parameter is its props, so send() checks them; the name is its preview URL.

formatAddress

function formatAddress(a: Address): string;

Write an Address as a header value, quoting display names with commas or quotes so they stay one recipient.

htmlToText

function htmlToText(html: string): string;

A readable text version of an HTML body: links become text (url), block ends become line breaks. Used when a template has no text.

mailPreview

function mailPreview<S extends {
  h3: {
    get(path: string, handler: (event: any) => unknown): unknown;
  };
  app?: {
    config: {
      get(key: 'mail', fallback: MailConfig): MailConfig;
    };
  };
}>(server: S, templates: MailTemplate<any>[], options?: {
  path?: string;
  mailer?: Mailer;
}): S;

Serves every registered template at <previewPath>/<name> in development (the preview props, or ?prop=value from the query string), and an index listing them. The path comes from options.path, then previewPath in config/mail.ts (read from server.app when the server has one), then /_kitr/mail; previewPath: false mounts nothing.

useMailer

function useMailer(app: KitrApp): Mailer;

The mailer the provider bound in this app's container. Throws in the browser, where nothing is bound.

defineConfig

const defineConfig: <const C extends MailConfig>(config: C) => C;

Types config/mail.ts. Returns its argument unchanged.

Address

interface Address {
  /** The address itself, such as `[email protected]`. */
  email: string;
  /** The display name, such as `Ada Lovelace`. */
  name?: string;
}

A parsed email address, as every Message field holds it.

CreateMailerOptions

interface CreateMailerOptions extends MailConfig {
  /** Renders React to static HTML. Default: react-dom/server's renderToStaticMarkup. */
  renderHtml?: (element: ReactElement) => Promise<string> | string;
}

Options for createMailer: the config options plus how React is rendered.

MailConfig

interface MailConfig {
  /** Where messages go. Unset in production, the provider refuses to boot. */
  transport?: MailTransport;
  /** Default sender. */
  from?: Recipient;
  /**
   * Where `mailPreview()` serves templates (default `/_kitr/mail`; false mounts nothing). A
   * `path` passed to `mailPreview()` wins.
   */
  previewPath?: string | false;
}

The options in config/mail.ts.

Mailer

interface Mailer {
  /** Render, check and send one message; resolves with its id and transport name. */
  send<P>(template: MailTemplate<P>, props: P, options: SendOptions): Promise<SentMail>;
  /** The rendered message without sending it, for tests and previews. */
  render<P>(template: MailTemplate<P>, props: P, options?: Partial<SendOptions>): Promise<Message>;
  /** The transport messages go through. */
  readonly transport: MailTransport;
  /** Messages the log transport kept, newest last. Empty with other transports. */
  readonly sent: readonly Message[];
}

The service the provider binds as mailer: renders templates and sends them through the transport.

MailTemplate

interface MailTemplate<Props> {
  /** Identifies the template in previews (`/_kitr/mail/<name>`). */
  name: string;
  /** The subject line, or a function of the props that returns it. */
  subject: string | ((props: Props) => string);
  /** The body as React. Plain components, or React Email's <Html>, <Button> and friends. */
  render: (props: Props) => ReactElement;
  /** A text alternative; derived from the HTML when left out. */
  text?: (props: Props) => string;
  /** Props the development preview renders with. */
  preview?: Props;
}

An email template made by defineMail: a name, a subject and a React body, typed by its props.

MailTransport

interface MailTransport {
  /** Reported as `SentMail.transport`. */
  name: string;
  /** Deliver a finished message; throw on failure. Resolve with the provider's id when it has one. */
  send(message: Message): Promise<{
    id?: string;
  }>;
}

Where messages go: the log, Resend and SMTP transports, or your own object with these two members.

Message

interface Message {
  /** The sender. */
  from: Address;
  /** The recipients; never empty once sent. */
  to: Address[];
  /** Carbon-copy recipients. */
  cc?: Address[];
  /** Blind carbon-copy recipients. */
  bcc?: Address[];
  /** Where replies go. */
  replyTo?: Address;
  /** The subject line. */
  subject: string;
  /** The full HTML document. */
  html: string;
  /** The plain-text version: the template's `text`, or derived from the HTML. */
  text: string;
  /** Extra headers, such as `List-Unsubscribe`. */
  headers?: Record<string, string>;
  /** Attached files; `content` is a string or bytes. */
  attachments?: Array<{
    filename: string;
    content: string | Uint8Array;
    contentType?: string;
  }>;
}

A rendered, checked message, as transports receive it and mailer.sent keeps it.

NodemailerLike

interface NodemailerLike {
  /** nodemailer's `createTransport`, called once on the first send. */
  createTransport(options: unknown): {
    sendMail(message: Record<string, unknown>): Promise<{
      messageId?: string;
    }>;
  };
}

The part of nodemailer the SMTP transport uses; pass the module itself.

SendOptions

interface SendOptions {
  /** One recipient or a list. Required. */
  to: Recipient | Recipient[];
  /** Carbon-copy recipients. */
  cc?: Recipient | Recipient[];
  /** Blind carbon-copy recipients. */
  bcc?: Recipient | Recipient[];
  /** Overrides `from` in `config/mail.ts` for this message. */
  from?: Recipient;
  /** Where replies go. */
  replyTo?: Recipient;
  /** Extra headers. Names must be tokens; values may not contain line breaks. */
  headers?: Record<string, string>;
  /** Files to attach: `{ filename, content, contentType? }`. */
  attachments?: Message['attachments'];
}

The third argument of mailer.send(): recipients, sender overrides, headers and attachments.

SentMail

interface SentMail {
  /** The transport's message id, or a random UUID when it returned none. */
  id: string;
  /** The name of the transport that sent it. */
  transport: string;
}

What mailer.send() resolves with.

Recipient

type Recipient = string | Address;

An address in any accepted form: '[email protected]', 'Ada <[email protected]>' or an Address.

@kitr/mail/provider

mailProvider

const mailProvider: import("@kitr/core").KitrProvider;

Binds mailer from config/mail.ts; the log transport outside production unless one is set.