Skip to main content

Getting started

Manual setup

Skip the CLI and wire Postboi up by hand — install, set a provider, and send.


The Quick start CLI does all of this for you. Prefer to wire it up by hand? It’s three steps.

Install Postboi

bun add postboi 
bun add postboi 
npm install postboi 
npm install postboi 
pnpm add postboi 
pnpm add postboi 
yarn add postboi 
yarn add postboi 

Set your provider and credentials

Pick the provider and non-secret config in a committed [`postboi.config.ts`](/config); keep the secret(s) in your env file. Each provider reads its own credential env var — see [Providers](/providers) for the full list.
// postboi.config.ts  (commit this)
import { config } from 'postboi';

export default config({
	provider: 'resend',
	default: { from: 'no-reply@example.com' }
});
// postboi.config.ts  (commit this)
import { config } from 'postboi';

export default config({
	provider: 'resend',
	default: { from: 'no-reply@example.com' }
});
# .env  (gitignore this — secrets only)
RESEND_API_KEY=re_xxxxxxxx
# .env  (gitignore this — secrets only)
RESEND_API_KEY=re_xxxxxxxx

Send

No provider import, no constructor — credentials come from the environment.
import { mail } from 'postboi';

await mail({
	to: 'contact@example.com',
	subject: 'Hi',
	body: '<p>Hello</p>'
});
import { mail } from 'postboi';

await mail({
	to: 'contact@example.com',
	subject: 'Hi',
	body: '<p>Hello</p>'
});

What lives where

Postboi splits config along a single line: secrets in the environment, everything else in the committed config file. Both are read by mail() on every call.

Setting Home Notes
Provider (resend, mailgun, …) postboi.config.ts as provider
Defaults (from / to / cc / bcc / reply_to) postboi.config.ts as default: { … }
Non-secret provider options (Mailgun domain, SES region, SMTP host/port) postboi.config.ts as options: { … }
Secrets (API keys, tokens, passwords) env file / host secrets e.g. RESEND_API_KEY, MAILGUN_API_KEY

Everything in the config file can still be overridden by an env var — handy for per-environment values without editing committed config (see below). The override names are POSTBOI_PROVIDER, POSTBOI_FROM / POSTBOI_TO / …, and each provider’s own field vars (e.g. MAILGUN_DOMAIN). Env always wins.

Per-environment config

Two portable patterns, in order of preference.

1. Override the provider with an env var. Keep a safe default in the committed file and flip it on the host. This works on every runtime — Node, Bun, and edge — with no magic:

// postboi.config.ts — safe default for local dev
export default config({ provider: 'mock' }); // sends nothing locally
// postboi.config.ts — safe default for local dev
export default config({ provider: 'mock' }); // sends nothing locally
# production host env
POSTBOI_PROVIDER=resend
RESEND_API_KEY=re_xxxxxxxx
# production host env
POSTBOI_PROVIDER=resend
RESEND_API_KEY=re_xxxxxxxx

Local dev (nothing set) uses mock; production (env set) uses Resend. POSTBOI_PROVIDER always wins over the file.

2. Use SvelteKit’s dev flag in a hook. The config file is imported directly by Node, so it can’t read $app/environment. Configure from SvelteKit’s init hook instead, where the flag is available — it runs once at startup and works on every adapter, including Workers:

// src/hooks.server.ts
import type { ServerInit } from '@sveltejs/kit';
import { dev } from '$app/environment';
import { configure } from 'postboi';

export const init: ServerInit = () => {
	configure({ provider: dev ? 'mock' : 'resend' });
};
// src/hooks.server.ts
import type { ServerInit } from '@sveltejs/kit';
import { dev } from '$app/environment';
import { configure } from 'postboi';

export const init: ServerInit = () => {
	configure({ provider: dev ? 'mock' : 'resend' });
};

Avoid process.env.NODE_ENV in the config file — a self-hosted Node deploy that forgets to set it falls into the wrong branch silently. Prefer the two patterns above.

On SvelteKit

A contact-form action is a one-liner. See SvelteKit form actions.

// +page.server.ts
import { mail } from 'postboi/kit';

export const actions = { default: mail };
// +page.server.ts
import { mail } from 'postboi/kit';

export const actions = { default: mail };

On runtimes without ambient env vars (e.g. Cloudflare Workers), construct the provider directly — see Using a provider directly.