Skip to content
Journal

Building the email API I wanted but couldn't buy

poststack is the developer-first email API I built after a year stitching three vendors together. The case for one product — transactional, marketing, and inbound — instead of three.

6 min read#poststack#email-api#transactional-email#developer-tools

In late 2024 I was building a side project that needed three things from its email layer. It needed to send transactional mail — receipts, password resets, the usual. It needed to send the occasional marketing broadcast — a newsletter, a launch announcement. And it needed to receive inbound mail so customers could reply to support threads and the app could parse the reply back into a ticket.

I went looking for the email API that did all three. I found, instead, a stack.

Resend for transactional, because Resend is currently the cleanest landing in the new crop and the TypeScript client is genuinely a joy. Mailchimp for broadcasts, because somebody on the team had used it before and the subscriber management was at least familiar. Some duct tape involving Postmark's inbound parsing and a custom webhook handler, because that was the one piece nobody else seemed to want to talk about. Three contracts. Three suppression lists that did not talk to each other. Three sets of analytics that defined "delivered" slightly differently.

It worked. It was also the second-worst architectural decision I'd made that quarter.

I spent a weekend looking at what it would take to consolidate. The answer, across every existing vendor I evaluated, was the same: pick the one that does your most important thing extremely well, accept that you'll bolt the other two on with webhooks, and never look at it again. That's a defensible answer when your most important thing is clearly the most important thing. It is not a defensible answer when the three workloads are all roughly equal in weight, which is the situation most small teams I know actually live in.

So I built poststack. It is the email API I wanted to use. One product, one API key, one bill, one suppression list, one contact graph.

This is the post about what that means in practice — and, more interestingly, about the four decisions I refused to compromise on.

What "one email API for everything" actually buys you

The pitch is easy to misread. It sounds like a feature checklist: poststack does sending and broadcasts and inbound and workflows, look how many boxes are ticked. That is true, and that is not the point.

The point is what stops happening when you collapse the seams.

A contact who unsubscribes from your newsletter does not need to be hand-synced into your transactional vendor's suppression list. A reply to a transactional thread doesn't have to be routed through a separate inbound parsing vendor and re-stitched back to the originating contact record by a brittle worker you wrote on a Friday. A workflow triggered by an "order placed" event doesn't have to know which provider sent the receipt — that's an implementation detail one layer down.

When the seams go away, the volume of glue code in your application that exists just to keep three vendors agreeing with each other goes away with them. In one of my projects, that glue layer was roughly 600 lines of TypeScript and a Postgres table. After migration to poststack, it was 0 lines and 0 tables, because the integration owned all of that.

That is the whole product thesis. Everything else — REST, SMTP, templating, broadcasts, workflows, contacts, segments, inbound, webhooks, tracking, test mode — is what falls out of taking the thesis seriously.

The four things I refused to ship without

A surprising amount of building a product is deciding what not to ship in version one. These four bits, though, were non-negotiable.

An end-to-end typed SDK

Not "we generated a TypeScript file from our OpenAPI spec and hoped for the best". The TypeScript client was part of how the API got designed. Endpoints that would feel awkward as SDK calls got reshaped before they shipped. Errors are typed unions, not stringly-typed status codes. Request and response bodies share the same schemas as the server, validated by Zod on both ends.

The reason I kept pushing on this is mundane: most developer-facing email products in 2026 still ship "TypeScript support" that is, on inspection, a generated types.d.ts file shipped alongside JavaScript. That's the bare minimum. A real SDK is API-design-driven. It costs more to maintain and it produces a meaningfully better integration experience.

A test mode that's actually transparent

Pass a header on a request and the send is simulated end-to-end. Webhooks fire. Tracking events emit. Addresses get validated. Templates render. Nothing leaves the platform, and nothing gets billed.

The phrase "test mode" appears in most vendors' docs. The implementation varies. Some test modes stub out delivery but bypass validation. Some bypass webhooks. Some are advertised as a feature and turn out, on inspection, to be "use a sandbox API key on a different account". I wanted the version where your CI runs against the real API surface, and the only thing that differs is whether the mail actually leaves the building.

Deliverability work nobody wants to talk about

SPF, DKIM, DMARC, return-path setup. Reverse DNS. The boring authentication stack that determines whether your email lands in inbox or spam.

Some providers — Postmark in particular — are gold-standard on this dimension and walk you through every step. Others assume you have a deliverability engineer on staff and provide a documentation page. poststack's domain-verification flow takes the Postmark approach: every required record is shown, copyable, verified inline, and explained in plain language. The first time you set up a sending domain on poststack should be the last time you need to read an RFC about email authentication.

A workflows primitive that isn't a Zapier clone

I went back and forth on this one for a month. The temptation, when you're building a "marketing automation suite", is to put a drag-and-drop canvas in the dashboard with sixty different node types and call it a day. Most teams don't want that. Most teams want "when this event happens, send this email, unless this condition is true" — composable enough to express their use case, simple enough to read in twenty seconds.

poststack's workflows are deliberately closer to "event triggers a function with branches" than "drag the icon onto the canvas". You can express most of the common patterns in three or four nodes. If you need a 200-step customer-journey orchestration, this is the wrong tool, and that's fine — that's a different product.

What poststack is not (and where Resend or Postmark is the better pick)

A few framings I'd rather you got from me than work out the hard way.

Not the cheapest if your only operation is "user signs up → send welcome email" and you'll never need broadcasts, inbound, workflows, or a contact graph. If that's you, Resend or Postmark on a starter tier will be perfectly fine, and I'd recommend them with no ego on the matter. The poststack thesis is consolidation; if there's nothing to consolidate, the math doesn't work in your favour.

Not an enterprise marketing automation suite. No 200-step journey builder. No predictive-send AI. No native A/B test orchestrator with statistical-significance gating. The workflow primitive is small on purpose.

Not a CDP. Contacts have custom properties, segments have rules, but it doesn't pretend to be Segment or RudderStack. If you have a real customer-data-platform problem, you should use a real CDP and stream events into poststack from there.

Where it runs, and where to look next

poststack runs on hoststack — my own European PaaS — for the obvious-in-retrospect reason that I wanted my email infrastructure to live inside the same jurisdiction as my customers' data. The hoststack post on this blog covers that decision in more depth. If you care about EU data residency, both halves of the stack matter, not just one.

The product itself, full API reference, SDK, and pricing all live at poststack.dev. The transactional + marketing combo on a single contact graph is the bit I'd start your evaluation with — it's the integration that other vendors split across two products, and the seam-collapse savings show up there first. Inbound + webhooks is the second-best place to look, especially if you've ever wanted "reply to this email and we'll parse it back into the app" and ended up writing your own.

If you've spent a year stitching three vendors together to get one usable email stack, the conversation I'd love to have is whether the seams you're maintaining are actually load-bearing — or whether, like mine were, they're just expensive habits.

Was this useful?