Email

Custom Email Adapter

Build a custom VitNode email adapter for any third-party provider like Postmark, AWS SES, or Mailgun.

You can connect any transactional email service (e.g. Postmark, AWS SES, SendGrid, Mailgun) by implementing the EmailApiPlugin interface. VitNode handles template rendering, i18n localization, and recipient resolution; your adapter just sends the email.

The EmailApiPlugin Interface

The adapter contract consists of a single sendEmail method:

export interface EmailApiPlugin {
  sendEmail: (args: {
    to: string
    subject: string
    html: string
    text: string
    metadata: { title: string; shortTitle?: string }
    replyTo?: string
  }) => Promise<void>
}

Quick start: Implementing an Adapter

1. Create the Adapter Factory

apps/api/src/lib/email/postmark-adapter.ts
import type { EmailApiPlugin } from "@vitnode/core/api/models/email"

export const PostmarkEmailAdapter = ({
  serverToken,
  from,
}: {
  serverToken: string
  from: string
}): EmailApiPlugin => ({
  sendEmail: async ({ to, subject, html, text, metadata }) => {
    const res = await fetch("https://api.postmarkapp.com/email", {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        "X-Postmark-Server-Token": serverToken,
      },
      body: JSON.stringify({
        From: `${metadata.shortTitle ?? metadata.title} <${from}>`,
        To: to,
        Subject: subject,
        HtmlBody: html,
        TextBody: text,
      }),
    })

    if (!res.ok) throw new Error(`Postmark error: ${res.statusText}`)
  },
})

2. Register in API Configuration

Attach the adapter to vitNodeApiConfig in apps/api/src/vitnode.api.config.ts:

apps/api/src/vitnode.api.config.ts
import { buildApiConfig } from "@vitnode/core/vitnode.config"
import { PostmarkEmailAdapter } from "./lib/email/postmark-adapter"

export const vitNodeApiConfig = buildApiConfig({
  email: {
    adapter: PostmarkEmailAdapter({
      serverToken: process.env.POSTMARK_SERVER_TOKEN!,
      from: "notifications@yourdomain.com",
    }),
  },
})

sendEmail Arguments

Prop

Type

Learn More