Skip to main content
Reference File 040

API reference

The provider surface, SendOptions, the Email type, and common constructor options.

Looking for the HTTP endpoints instead, for managing lists, domains, webhooks, and members over curl? That’s the REST API.

Provider class

Every provider exposes the same surface:

import Resend from 'postboi/resend'

const mail = new Resend({
	api_key: string, // see Providers for credential option names
	default?: { from?, to?, cc?, bcc?, reply_to? }
})

await mail.send(options: SendOptions): Promise<SendResponse>
await mail.cancel(id: string): Promise<{ id: string }> // scheduled sends (see Scheduling)
mail.is_error(error: unknown): error is PostboiError

See Providers for each provider’s credential option names. The zero-config equivalents are mail() and cancel() from the package root.

Postboi provider methods

The Postboi provider adds account methods on top of the common surface:

import { mail } from 'postboi' // reads POSTBOI_TOKEN

// messages
await mail.messages.get(id) // status + content (see The Postboi provider)
await mail.messages.reschedule(id, when) // Date | ISO string | Duration (see Scheduling)

// lists & broadcasts (see The Postboi provider)
await mail.lists.all()
await mail.lists.create(name, { confirmation? }) // names are unique per account (409 name_taken)
await mail.lists.get(name_or_id) // includes recipients + confirmation settings
await mail.lists.update(name_or_id, { name?, confirmation? })
await mail.lists.rename(name_or_id, name) // shorthand for lists.update
await mail.lists.delete(name_or_id)
await mail.recipients.add(name_or_id, recipients, { status? }) // upserts — see The Postboi provider
await mail.recipients.set_status(name_or_id, email, status)
await mail.recipients.remove(name_or_id, email)
await mail.lists.broadcast(name_or_id, { from?, reply_to?, subject, body?, text?, scheduled_at? })

// notifications (see The Postboi provider)
await mail.notifications.all(name_or_id)
await mail.notifications.create(name_or_id, { recipients, from?, subject?, body?, schedule })
await mail.notifications.update(name_or_id, id, changes) // partial
await mail.notifications.delete(name_or_id, id)

// suppressions (see The Postboi provider)
await mail.suppressions.all()
await mail.suppressions.add(email)
await mail.suppressions.remove(email)

// forms & scheduled exports (see Forms)
await mail.forms.all() // what `form:` is typed to
await mail.exports.download({ filter?, format?, columns?, fields? }) // the file now: { filename, type, bytes, text() }
await mail.exports.all()
await mail.exports.get(id)
await mail.exports.create({ name, recipients, from?, filter?, format?, columns?, fields?, window?, schedule })
await mail.exports.update(id, changes) // partial; { paused: true } pauses
await mail.exports.run(id) // the file goes within a minute
await mail.exports.delete(id)

SendOptions

interface SendOptions {
	to?: Email | Email[]
	from?: Email
	reply_to?: Email | Email[]
	cc?: Email | Email[]
	bcc?: Email | Email[]
	subject?: string // default: "Mail sent from website"
	body: string | FormData
	text?: string
	formatter?:
		| {
				fieldset?: ((label: string) => string) | null | false
				name?: ((label: string) => string) | null | false
		  }
		| null
		| false
	attachments?: File | File[]
	idempotency_key?: string
	headers?: Record<string, string>
	unsubscribe_url?: string // sets RFC 8058 List-Unsubscribe headers (see Tracking & unsubscribe)
	tags?: string[]
	scheduled_at?: Date | string | Duration // see Scheduling
	tracking?: { opens?: boolean; clicks?: boolean } // see Tracking & unsubscribe
	captcha?: {
		honeypot?: string | false // honeypot field name (default "_honey"), false disables
		turnstile?: { secret_key?: string } | boolean // default: on when TURNSTILE_SECRET_KEY is set
	}
}

body accepts a string of HTML, a FormData object, or a promise resolving to either, so you can pass a template renderer’s output straight through; see Email templates. formatter controls how grouped-field labels are rendered. headers and tags are forwarded to each provider’s native concept. See Custom headers & tags. captcha adjusts the built-in spam protection for a single send.

Common constructor options

Every provider also accepts these, on top of its own credentials:

{
	// field defaults applied when a send omits them; to/cc/bcc accept a string or array
	default?: { from?, to?, cc?, bcc?, reply_to? }
	timeout?: number // per-request timeout in ms (default 30000)
	retries?: number // retries on 429/5xx and network errors (default 0)
	retry_delay?: number // base backoff in ms, doubles each attempt (default 500)
	auto_text?: boolean // derive a plain-text body from the HTML (default true)
	hooks?: Hooks // see Hooks
	captcha?: CaptchaOptions // see Spam protection
}

See Errors & retries for retry behaviour, Hooks for the hooks shape, and Spam protection for captcha.

Email type

type Email =
	| string // plain address or "Name <address>"
	| { address: string; name?: string }

All accepted address formats:

'user@example.com'
{ address: 'user@example.com', name: 'User Name' }
'User Name <user@example.com>'
['user1@example.com', 'user2@example.com']

PostboiError

The normalised error thrown by every provider. See Errors & retries for usage.

interface PostboiError {
	provider: string // e.g. "resend"
	status?: number // HTTP status, when applicable
	code?: string // provider-specific code, when available
	message: string // normalised message
	raw: unknown // the original provider payload
}

postboi/webhooks

Receive delivery events, normalized across providers. See Webhooks.

import { receive, handshake, mock_event, mock_request, parse_user_agent } from 'postboi/webhooks'

await receive(request: Request, options?: {
	provider?: ProviderKey | WhatsappProviderKey | WebhookAdapter // default: as mail(); a WhatsApp-only project falls through to its WhatsApp provider
	secret?: string // default: <PROVIDER>_WEBHOOK_SECRET
	verify_token?: string // Meta's endpoint handshake; default: <PROVIDER>_WEBHOOK_VERIFY_TOKEN
	verify?: boolean // false skips verification (explicit opt-out)
}): Promise<WebhookEvent[]>

// The GET Meta makes before subscribing an endpoint — the challenge to echo, or
// undefined for a request that isn't one. webhook() calls it for you.
await handshake(request: Request, options?: ReceiveOptions): Promise<string | undefined>

On SvelteKit, webhook(handler, options?) from postboi/kit wraps receive as a ready-made +server.ts request handler.