Changelog

What has shipped

Real entries only — what shipped, and when. Nothing here is padding.

  1. API

    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.

  2. API

    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.

  3. API

    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.

  4. API

    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.

  5. API

    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.

  6. Dashboard

    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.

  7. API

    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.

  8. Deliverability

    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.

  9. API

    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.

  10. Delivery

    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.

  11. Delivery

    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.