Node.js SDK
Send email with Fastify
Use Parcel Wing from Fastify routes, plugins, and typed handlers while keeping API keys server-side.
Install the SDK
The official SDK is published as @parcelwing/node.
Terminal
npm install @parcelwing/node
Plugin
Register the Parcel Wing client once as a Fastify plugin so routes can reuse the same SDK instance.
src/plugins/parcelwing.ts
import fp from "fastify-plugin";import { ParcelWing } from "@parcelwing/node";export default fp(async (fastify) => {const parcelWing = new ParcelWing({apiKey: process.env.PARCEL_WING_API_KEY!,});fastify.decorate("parcelWing", parcelWing);});declare module "fastify" {interface FastifyInstance {parcelWing: ParcelWing;}}
Route
Use the decorated SDK client inside a typed route handler and return structured errors when Parcel Wing rejects the request.
src/server.ts
import Fastify from "fastify";import { ParcelWingError } from "@parcelwing/node";import parcelWingPlugin from "./plugins/parcelwing";const fastify = Fastify({ logger: true });await fastify.register(parcelWingPlugin);fastify.post<{ Body: { email: string; firstName?: string } }>("/send-welcome",async (request, reply) => {try {const [message] = await fastify.parcelWing.emails.send({from: "Acme <[email protected]>",to: request.body.email,template_alias: "welcome_email",template_params: {first_name: request.body.firstName ?? "friend",},});return { id: message?.id };} catch (error) {if (error instanceof ParcelWingError) {return reply.status(error.status).send({code: error.code,requestId: error.requestId,});}request.log.error(error);return reply.status(500).send({ error: "Unexpected error" });}},);await fastify.listen({ port: Number(process.env.PORT ?? 3000), host: "0.0.0.0" });
Production notes
- Keep
PARCEL_WING_API_KEYin server-only environment variables. - Validate public request bodies with your preferred Fastify schema before sending.
- Log
requestIdfromParcelWingErrorfor easier support and debugging.