X Enterprises

fastify-xemail

Fastify email plugin via Postmark (migration target) or SendGrid (legacy). Transactional, template, attachment, and bulk sending through one fastify.xEmail decorator.

fastify-xemail

Fastify 5 plugin for email via Postmark or SendGrid (legacy). Decorate your server with fastify.xEmail and send transactional, template, attachment, and bulk emails through one API. SendGrid additionally supports address validation and Marketing contacts/lists.

Migration note: SendGrid support is legacy. New integrations should use provider: 'postmark'. Existing SendGrid registrations keep working unchanged (default remains 'sendgrid').

1.3.0. Postmark provider (provider: 'postmark') for send / sendTemplate / sendWithAttachments / sendBulk / sendPersonalizedBulk; provider option ('sendgrid' | 'postmark', default 'sendgrid'); messageStream extra option for Postmark; SendGrid-only methods (validate, contacts, lists) throw under postmark. SHA 4561c766.

Installation

```bash
npm install @xenterprises/fastify-xemail fastify@5

fastify@^5.0.0 is a peer dependency. TypeScript declarations ship with the package.

Quick Start (Postmark)

import Fastify from "fastify";
import xEmail from "@xenterprises/fastify-xemail";

const fastify = Fastify();

await fastify.register(xEmail, {
  provider: "postmark",
  apiKey: process.env.POSTMARK_SERVER_TOKEN,
  fromEmail: "noreply@example.com",
  fromName: "My App",
});

fastify.post("/welcome", async (request) => {
  return fastify.xEmail.send(
    request.body.email,
    "Welcome!",
    "<h1>Welcome!</h1><p>Thanks for signing up.</p>"
  );
});

await fastify.listen({ port: 3000 });

Legacy SendGrid registration (default provider) omits provider or sets provider: 'sendgrid' and passes SENDGRID_API_KEY / SENDGRID_FROM_EMAIL.

The plugin reads no environment variables. Your app reads process.env.POSTMARK_SERVER_TOKEN (or the SendGrid vars) and passes values into register().

Providers

ProviderStatusSending methodsvalidate, contacts, lists
postmarkMigration targetsend, sendTemplate, sendWithAttachments, sendBulk, sendPersonalizedBulkThrow [xEmail] '<method>()' is not supported by provider 'postmark'.
sendgridLegacy (default)All sending methodsFully supported

Postmark has no equivalents for email validation or contact/list management, so those methods exist on the decorator under Postmark but throw.

Options

NameTypeDefaultRequiredDescription
provider'sendgrid' | 'postmark''sendgrid'NoEmail provider. sendgrid is legacy; postmark is the migration target.
apiKeystring-YesPostmark server API token, or SendGrid API key (Mail Send; Marketing APIs for contact/list methods).
fromEmailstring-YesVerified sender email address.
fromNamestring-NoSender display name.
activebooleantrueNoSet false to skip plugin registration entirely (no decorator is added).

Invalid options fail fast at registration, e.g.:

xemail: option `apiKey` must be a string, e.g. `app.register(xEmail, { apiKey: 'SG.your-api-key' })`

Methods

Sending

Under Postmark, extraOptions on send/sendTemplate accepts replyTo, cc, bcc, headers, and messageStream (mapped to Postmark PascalCase fields).

Validation (SendGrid only)

  • validate - Validate an email address using the SendGrid Email Validation API. Throws under provider: 'postmark'.

Contacts (SendGrid only)

Lists (SendGrid only)

Error Reference

Startup Errors

ErrorCause
xemail: option `apiKey` must be a string, e.g. `app.register(xEmail, { apiKey: 'SG.your-api-key' })` Missing or non-string apiKey at registration.
xemail: option `fromEmail` must be a string, e.g. `app.register(xEmail, { apiKey: 'SG.your-api-key', fromEmail: 'noreply@example.com' })` Missing or non-string fromEmail at registration.
xemail: option `fromName` must be a string, e.g. `app.register(xEmail, { apiKey: 'SG.your-api-key', fromEmail: 'noreply@example.com', fromName: 'My App' })` fromName provided but not a string.
xemail: option `active` must be a booleanactive provided but not a boolean.
xemail: option `provider` must be 'sendgrid' or 'postmark'Invalid provider at registration.

Runtime Errors

All runtime errors are thrown with the [xEmail] prefix. See each method page for the specific error messages. Under provider: 'postmark', SendGrid-only methods throw [xEmail] '<method>()' is not supported by provider 'postmark'.

Environment Variables

The plugin never reads process.env. These variables are a consumer-side convention: your application reads them and passes the values into app.register(xEmail, { ... }). Nothing here is "required" by the plugin itself - only the apiKey and fromEmail options are required (see Options above).

VariableMaps to optionDescription
POSTMARK_SERVER_TOKENapiKeyPostmark server API token (when provider: 'postmark').
SENDGRID_API_KEYapiKeySendGrid API key with Mail Send and Marketing permissions (legacy).
SENDGRID_FROM_EMAILfromEmailVerified sender email address (legacy SendGrid convention).
SENDGRID_FROM_NAMEfromName (optional)Sender display name.

How It Works

The plugin validates registration options and selects a provider module: src/providers/postmark.js or src/providers/sendgrid.js. SendGrid uses @sendgrid/mail (transactional) and @sendgrid/client (Marketing and Validation REST APIs). Postmark uses the postmark package ServerClient. Both decorate the Fastify instance with fastify.xEmail. SendGrid-only methods remain on the decorator under Postmark but throw. Errors are caught, logged via fastify.log.error (credentials are never logged), and re-thrown with a [xEmail] prefix. validate() returns a soft error result instead of throwing (SendGrid only). Setting active: false skips registration entirely.

AI Context

package: "@xenterprises/fastify-xemail"
version: 1.3.0
type: fastify-plugin
use-when: Transactional email via Postmark (preferred) or SendGrid (legacy); templates, bulk, attachments; SendGrid-only validate/contacts/lists
decorator: fastify.xEmail
methods: send, sendTemplate, sendWithAttachments, sendBulk, sendPersonalizedBulk, validate (SendGrid), contacts (add/search/delete, SendGrid), lists (create/get/delete, SendGrid)
opts: provider (sendgrid|postmark, default sendgrid), apiKey, fromEmail, fromName, active; extraOptions.messageStream (Postmark)
env: POSTMARK_SERVER_TOKEN, SENDGRID_API_KEY, SENDGRID_FROM_EMAIL, SENDGRID_FROM_NAME (optional) - consumer-set only
Copyright © 2026