postboi
v0.14.1
Published
<div align="center"> <img src="https://raw.githubusercontent.com/postboi-mail/postboi/refs/heads/main/static/logo.svg" alt="Postboi" width="250" />
Readme
I got ninety-nine problems, but mail ain't one
Postboi is a framework-agnostic email library optimised for SvelteKit. Works with a variety of email providers and turns your FormData into tidy HTML emails, with zero configuration.
📖 Full documentation: docs.postboi.email
Features
- 👨💻 Zero configuration - works out of the box with minimal setup
- 🔌 Provider-based - swap email providers without changing your code
- 📝 Smart FormData parsing - automatically converts FormData to HTML tables
- 🎯 Grouped fields - organize form fields with
fieldset→fieldsyntax - 📎 Attachments - attach files directly from form inputs or file objects
- 📮 Hosted forms - no backend? point any HTML form at a hosted endpoint and submissions land in your inbox, spam-checked
- 🎨 Bring your own templates -
bodytakes any HTML, and the optionalpostboi/maizzlehelper renders Maizzle templates straight into it - 📬 Webhooks - receive delivery events (delivered / opened / clicked / bounced) normalized across providers, signatures verified — including which client and device opened the mail
- 📈 Per-send tracking & one-click unsubscribe -
tracking: { opens, clicks }andunsubscribe_url(RFC 8058 headers) on any provider that supports them - ⏰ Schedule & cancel -
scheduled_atfor future sends,cancel(id)to call them off - 🍯 Invisible spam protection - a zero-config honeypot, plus invisible captcha — fully managed on the Postboi provider, or bring your own Turnstile key
- 🧩
<Captcha />component - one prop-free tag inside your own form, for Svelte, React, Vue and Astro —postboi syncbakes in the key - 🛡️ Type-safe - full TypeScript support with normalized error handling
Quick start
Run the CLI to choose a provider, input credentials, optionally set defaults.
bunx postboi initIt writes your provider, defaults, and non-secret options to a committed
postboi.config.ts, keeping only secrets (API keys) in your env file — so the best case is
a single env var:
// postboi.config.ts (committed)
import { config } from "postboi"
export default config({
provider: "resend",
default: { from: "[email protected]" },
})# .env (gitignored — secrets only)
RESEND_API_KEY=re_xxxxxxxxThen send from anywhere — no provider import, no constructor, config is picked up automatically:
import { mail } from "postboi"
await mail({ to: "[email protected]", subject: "Hi", body: "<p>Hello</p>" })On SvelteKit, a form action is a one-liner:
// +page.server.ts
import { mail } from "postboi/kit"
export const actions = { default: mail }| Topic | Docs |
| ---------------------------------------- | -------------------------------------------------------------------------- |
| Quick start — the CLI (postboi init) | docs.postboi.email/quick-start |
| Manual setup (no CLI) | docs.postboi.email/manual-setup |
| SvelteKit form actions | docs.postboi.email/sveltekit |
| FormData → HTML tables | docs.postboi.email/formdata |
| All providers & their options | docs.postboi.email/providers |
| Hooks, global config, retries, bulk send | docs.postboi.email/config |
| API reference | docs.postboi.email/api |
On runtimes without ambient env vars (e.g. Cloudflare Workers), construct the provider directly — see Providers.
Development
# install dependencies
bun install
# start dev server
bun run dev
# type checking
bun run check
# linting
bun run lint
# run tests
bun run test
# build library
bun run buildThe docs site is the SvelteKit app at the repo root — bun run dev serves it locally.
Contributing
PRs welcome! Especially for new email providers. Make sure you:
- Follow the existing code style (snake_case, no semicolons)
- Add tests for new features
- Run
bun run checkandbun run lintbefore pushing
Releasing
Maintainers: npm run release -- <patch|minor|major> publishes the library and
creates the GitHub release. See RELEASING.md for the full
process, including snapshotting the versioned docs.
