White-label SaaS emails,
without sub-accounts.
Pass a tenantId in the event payload. Logo, primary colour, support email and reply-to address resolve at render time. One template per email type — every customer of your SaaS sees their own brand.
No Postmark server-token-per-tenant. No SendGrid sub-account-per-customer. One API key, one template, N tenants.
- 1 template, N tenants
- Render-time variable resolution
- GDPR-ready
- Hosted in the EU
// the difference
One field instead of a fan-out.
On the left: what the legacy approach looks like — pick a server token per tenant, look up the right template ID, hope nothing drifts. On the right: what else.events does — one POST, the renderer reads tenant.brand.* at send-time.
// One server token + one template ID per tenant.
// Map lives in your DB or env. Drift is a question of when, not if.
const tenant = await db.tenants.findById(tenantId);
const client = new Postmark.ServerClient(tenant.postmarkServerToken);
await client.sendEmailWithTemplate({
TemplateId: tenant.welcomeTemplateId,
From: tenant.fromAddress,
To: user.email,
TemplateModel: {
brand_logo_url: tenant.logoUrl,
brand_color: tenant.primaryColor,
user_first_name: user.firstName,
},
});
// One API key. One template. tenantId resolves brand vars at render.
await fetch("https://app.else.events/api/events", {
method: "POST",
headers: {
"X-API-Key": process.env.ELSE_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
eventId: crypto.randomUUID(),
eventName: "user.signed_up",
occurredAt: new Date().toISOString(),
payload: {
tenantId: "acme-corp",
user: { email: user.email, firstName: user.firstName },
},
}),
}); The Postmark snippet is a representative pattern, not a quote of any specific Postmark API. The point is the shape of the integration — not the vendor.
// proof
Pick a tenant. Same template, different brand.
The interactive demo below is the same control surface we use in the editor. The header block reads tenant.brand.* — change the active tenant and welcome / invoice / receipt all re-skin in lockstep, with no template fork.
// Live inheritance demo
Pick a brand. Every email updates.
One block, three templates, three tenants. The header block reads the active tenant variables — change the tenant and the same template renders in their colours, with their logo, no fork required.
- welcome.email Acme
Welcome to Acme
Hi Alex — your Acme workspace is ready.
- invoice.email Acme
Your Acme invoice
Your latest Acme invoice is attached.
- receipt.email Acme
Thanks for your Acme order
Receipt #4012 from Acme.
Three things to set up. Then never again.
Tenants are a first-class concept in else.events. They live in the workspace, not glued on through tags or custom payload conventions.
-
1. Define tenants in the dashboard
Logo URL, primary colour, support email, reply-to address, custom sending domain (optional). Each tenant gets a stable tenantId you control. Add a tenant once, or sync the whole table from your DB through the API.
-
2. Pass tenantId in every event
Your existing /api/events POST gains one extra field: payload.tenantId. The rule engine sees it; the renderer resolves it. Nothing else in your integration changes.
-
3. Reference tenant.brand.* in templates
MJML blocks read {{tenant.brand.logoUrl}}, {{tenant.brand.primaryColor}}, {{tenant.brand.supportEmail}}. One welcome.email, one invoice.email — they pick up the active tenant at render time. Cycle-detected, depth-limited, tenant-scoped.
Where multi-tenant transactional email matters.
Four shapes of B2B SaaS where every email needs to look like it came from your customer, not from you.
-
SaaS marketplaces & platforms
Sellers / vendors on your platform send order confirmations, payout notices, dispute notifications. Each one branded to the seller — not to you.
order.confirmed → vendor logo + colours -
Embedded fintech & reseller programs
Payment links, KYC reminders, invoice emails on behalf of partner banks or resellers. Compliance-friendly: the email reads as the partner's, the audit trail stays yours.
kyc.reminder → partner letterhead -
Whitelabel agencies & studios
Run a single product, sell it to dozens of agencies, each with their own client. Tenants nest cleanly: agency → client. Brand per leaf.
client.report.ready → agency brand -
Custom-domain SaaS apps
Customers point their own subdomain at your app and expect emails from support@theirbrand.com. Per-tenant sending domain handles the DNS dance; the rest is template inheritance.
user.invited → custom domain
Your customers' customers stay out of our database.
Multi-tenancy doesn't multiply the privacy surface. We still don't keep a contact list — the recipient address goes to your configured email provider, then becomes a SHA-256 hash in our delivery log. Tenant metadata (logo, colours, support email) lives in the workspace; end-recipient identity does not.
- No end-customer contacts stored on our side
- Per-tenant sending domains supported (BYO DNS)
- DPA covers your SaaS, not every downstream tenant
Things you'll want to know.
Do I need a separate sending domain per tenant?
No, but you can. By default everything ships through your workspace's sending domain (or shared Postmark infrastructure during the beta). If a tenant wants their own domain, you add it to the tenant record and verify the DNS — same SPF / DKIM dance as anywhere else, just scoped per tenant.
What happens if a tenant has no logo or colour set?
Templates fall back deterministically: tenant value → workspace default → empty string. Same chain as locale fallback. You won't ship an email with a literal {{tenant.brand.logoUrl}} placeholder — the editor surfaces missing values during dry-run.
How many tenants can I have per plan?
There's no hard cap on tenant count during the public beta — tenants are metadata, not metered resources. Emails are the metered resource. Each plan's monthly email budget covers all tenants together. If you're sending across thousands of tenants, talk to us — Premium is currently the right fit.
Can I create or update tenants via API?
Yes. POST / PATCH / DELETE on /api/tenants accepts the same fields as the dashboard form. Most teams sync the table once a day from their own DB; some create the tenant just-in-time the first time an event references an unknown tenantId.
What if a customer of mine wants to leave — can I export their tenant data?
Tenant config (brand vars, domain settings) is exportable as JSON via the dashboard or API. Their delivery log lives in your workspace, scoped by tenantId; you can filter and export it the same way you'd export any other slice.
Ship branded emails for every tenant. Today.
14-day free trial, no credit card. POST your first multi-tenant event in an afternoon — your existing integration stays as-is, you just add one field.