Orkestr
All posts
Engineering··Mayank Mishra

Building a multi-tenant inbox in a long weekend

How we wired Resend, threading, per-tenant branding, and a Gmail-style UI — and what we deliberately didn't build.

A booking platform needs email. Customer gets a confirmation. Tenant gets a "you have a new booking" alert. Referrer gets a "your referral just converted" credit notice. The interesting bit isn't sending those — it's making them look like they come from the tenant, not the platform, while still being deliverable, threadable, and manageable.

This post is about the design calls we made.

The "From:" problem

When Acme Spaces gets a booking, the customer's inbox should read:

From: Acme Spaces <bookings@acme.com>

NOT

From: Orkestr <notifications@orkestr.in>
Subject: Your booking on Acme is confirmed

The customer's relationship is with Acme. We're plumbing.

There are three architectural paths. We mapped them to our existing plan tiers:

Tier What customer sees Cost
STARTER (free) Acme Spaces <notifications@orkestr.in> Display-name override per send. One Resend domain.
GROWTH ($49) Acme Spaces <bookings@acme.orkestr.in> Per-tenant subdomain via Resend Domains API + Cloudflare wildcard. Programmatic.
PRO ($199) Acme Spaces <bookings@acme-spaces.com> Tenant brings their own domain, adds DNS records once, full white-label.

Tier 1 is what shipped this week. Tiers 2 and 3 are queued.

Why we picked Resend over Klaviyo, SendGrid, etc

The full comparison is in the docs, but the punchline: Klaviyo is built for "one merchant, one Klaviyo account". Running a tenant per Klaviyo account at our pricing would be $2,000/month before we sent a single email. SendGrid's multi-tenant story is sub-users, which is clunky. Resend gave us a single REST API, a great free tier (3k/month, 100/day), and Domains-API control so we can register tenant domains programmatically when we get to tier 2 + 3.

RFC2822 threading

Inbound → /v1/email/inbound → resolve tenant from local-part → find-or-create Thread → write Message. Reconnection back into the same conversation uses the standard References + In-Reply-To headers. Outbound (reply from /provider/inbox) writes a Message-ID we control so the customer's reply slots back into the same thread.

The platform inbox

A subtle gotcha: support@orkestr.in, legal@orkestr.in, dpa@orkestr.in — these aren't tenants. We lazily provision a system tenant with subdomain platform and route them all to it. Admin sees them in /admin/inbox with a "PLATFORM" badge. No dropped mail.

What we deliberately didn't build

IMAP server. A real "open this inbox in Apple Mail" would need either Gmail/Outlook OAuth (Google's verification is calendar-weeks) or running our own IMAP server (Dovecot + custom adapter, multi-week + ops burden). We shipped two pragmatic shortcuts instead:

  1. Forward-to address — per tenant, every inbound message also gets sent to their personal email. They use their normal mail app for reading.
  2. Resend SMTP relay — published in /provider/settings/email for outbound from native mail apps, with a clear note that the mail-app path bypasses inbox tracking.

We also laid the BYO-mailbox foundation: schema for IMAP/SMTP credentials, encrypted via the same AES-256-GCM cipher we use for integration credentials, plus a connect-and-test form. The actual IMAP fetch loop using imapflow + mailparser is the next focused commit.

What we got right

  • Reusing existing primitives. The email-mirror hook on the notification pipeline meant adding new transactional emails costs ~5 lines.
  • Honest stubs over half-built features. When a feature isn't fully wired we return HTTP 501 with a clear message, not silent no-ops.
  • One schema for inbox + mailbox. Inbound from Resend and inbound from a future IMAP poll both land in the same Thread/Message tables.

What we got wrong

The plus-addressing scheme for tenants (acme+booking@orkestr.in) seemed clever — until we realised some inbound mail clients strip the extension before routing. So we ended up with a simpler rule: <subdomain>@orkestr.in for tenants, period. Plus-extensions still work for the future "departments" feature but we don't rely on them for routing.

If you're building a multi-tenant platform that needs email, try us free — the inbox + email layer is one of the bits we're most proud of.

#inbox#email#multi-tenant#design

Want this in your inbox? Subscribe via the RSS feed or email hello@orkestr.in.