Multiple recipients: to arrays, cc and bcc
POST /v1/emails now takes to as an address or an array, plus cc and bcc arrays — up to 50 distinct recipients across the three. A single recipient answers exactly as before; more than one returns an emails array naming every recipient with its own id and status.
Every recipient is one email. A message to one To, two Cc and one Bcc counts as four against your allowance, because each is a separate delivery to a separate mail server. Each also gets its own delivery record and its own bounce handling, so a bounce names the address that bounced and suppresses only that one.
A suppressed recipient is skipped, named in the response and not charged; the other recipients still go. Every other refusal — quota, an unverified domain, a bad address — refuses the whole call and nothing is sent to anybody. With an idempotencyKey, each copy keys on the recipient address rather than its position, so a retry with the list reordered still deduplicates. @posthaste/sdk is at 0.3.0.
Suppression refusals carry their reason
A 422 suppressed now returns address and reason alongside the message, so an integration can tell a stale hard bounce apart from a complaint it must never retry.
Scheduled sending
POST /v1/emails accepts scheduledAt to send later, up to a horizon set by your plan, and DELETE /v1/emails/:id/schedule calls it off any time before it releases.
Suppression, domain verification and your allowance are all checked again on the day the mail actually leaves, not the day you scheduled it.
Attachments
POST /v1/emails accepts an attachments array — up to 10 files, 10 MiB combined once decoded. Inline images work through disposition and cid.
Read them back with GET /v1/messages/:id/attachments/:attachmentId, which never serves an active content type from our origin.
SMTP submission
Point an existing app at smtp.posthastemail.dev on 587 or 465 and send with an API key as the password. Mail arriving this way goes through the same accept path, suppression checks and delivery records as the HTTP API.
The dashboard
Domains and their DNS checks, messages and their full SMTP conversation, suppressions, webhook endpoints, API keys, usage and billing — all in the browser.
Sign-in is a session cookie with two-factor, passkeys and sign-in with Google.
The TypeScript SDK
@posthaste/sdk is the official client for Node and TypeScript, with zero runtime dependencies.
It carries webhook signature verification over raw bytes, retries that will never duplicate a send, and auto-pagination that loops on hasMore.
The warmup governor
Accounts start at 200 messages a day and climb as their sending stays clean. Going over returns 429 with a Retry-After, and GET /v1/me reports your limit and how much of it you have used.
Signed webhooks
Events are pushed as they happen, signed with a timestamped HMAC over the raw body so a captured request cannot be replayed.
Failed deliveries retry on a backoff with a stable idempotency key across attempts.
Bounce handling
Every message goes out with a unique return path, so a bounce is attributed to the exact send rather than guessed at from the recipient address.
Permanent failures suppress the address immediately; temporary ones never do.
Sending on our own infrastructure
API to a Postgres-backed queue, to our own MTA, to the recipient’s mail server over an encrypted connection, with the SMTP conversation kept.
Messages are DKIM-signed per domain at the transport layer, so the signature covers the exact bytes that go on the wire.