Features
Send email for your customers without sharing their mistakes
If your product sends email on behalf of your own customers, give each one a tenant: its own domains, suppression list, stats, sending ramp and pause switch, so one customer's bad list never hurts the rest.
What each tenant gets
Isolation per customer, in one account
You keep one account, one dashboard, and as many API keys and webhook endpoints as you like. Each of your customers gets its own lane.
Its own domains
Its own suppression list
Its own stats
Its own sending ramp
Its own pause switch
Its own keys and webhooks
API
One call per customer, one field per send
Create a tenant with your own id for the customer, then name it on each send. Batch sends take a tenant per item.
external_idis your id for the customer, used everywhere you name the tenantdefault_from_domaincompletes a bare from such as “billing”stream_policy: "transactional_only"refuses product email for that tenantdaily_limitsets your own cap per UTC day- Every email and email webhook carries the tenant, and GET /emails filters by it
Create a tenant
curl -X POST https://api.groundmail.dev/tenants \
-H "Authorization: Bearer $GROUNDMAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_id": "cust_8412",
"name": "Acme Inc",
"default_from_domain": "mail.acme.com"
}'Send as the tenant
curl -X POST https://api.groundmail.dev/emails \
-H "Authorization: Bearer $GROUNDMAIL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tenant": "cust_8412",
"from": "Acme <billing@mail.acme.com>",
"to": "jane@example.com",
"subject": "Your receipt",
"html": "<p>Thanks!</p>"
}'Webhooks
Each customer's events, at their own URL
By default an endpoint gets events for every tenant, with the tenant in each payload. Set tenants on an endpoint and it only gets those tenants' email events.
POST /webhooks
{
"url": "https://acme.example.com/hooks/email",
"events": ["email.delivered", "email.bounced", "email.complained"],
"tenants": ["cust_8412"]
}Node SDK
import { Groundmail } from 'groundmail'
const client = new Groundmail(process.env.GROUNDMAIL_API_KEY!)
await client.tenants.create({ external_id: 'cust_8412', name: 'Acme Inc' })
await client.tenants.domains.assign('cust_8412', 'mail.acme.com')
const { stats, ramp } = await client.tenants.stats('cust_8412', { days: 7 })
await client.tenants.pause('cust_8412', 'Customer asked us to stop')
await client.tenants.resume('cust_8412')Plans
Included on Scale and Dedicated
Tenants are part of the plan, with no per-tenant fee. Billing stays on your sending volume. See pricing.
- Scale: up to 1,000 tenants
- Dedicated: up to 10,000 tenants
- Give any tenant its own dedicated IP, or a pool of them, for $50 per IP per month
- The CLI and SDKs cover tenants, keys and webhook filters
- Walkthrough: the platforms guide
FAQ
Common questions
Do tenants cost extra?
No. Tenants are included on Scale (up to 1,000) and Dedicated (up to 10,000), with no per-tenant fee. You pay for sending volume as usual. Need more tenants, or tenants on another plan? Email support@groundmail.dev.
What happens when one customer sends to a bad list?
Their tenant takes the hit, not your other customers. Bounces and complaints go on that tenant's own suppression list, a new tenant ramps up its daily volume on its own schedule, and if a tenant's bounce or complaint rate gets too high, Groundmail pauses that one tenant instead of your whole account.
Do I have to change my sending code?
Add a tenant field to each send. If you leave it out and send from a domain that belongs to a tenant, the email is that tenant's anyway, so SMTP and existing code get per-tenant isolation as soon as the customer's domain is assigned to their tenant.
Can a customer have their own API key or webhook?
Yes. A key limited to one tenant can only send as that tenant and only sees its emails, domains and suppressions. A webhook endpoint can be filtered to one or more tenants, so each customer's delivery events go to their own URL.
Can one customer have a dedicated IP?
Yes. A tenant can send from its own dedicated IP, or a pool of them, for $50 per IP per month. Request it under Settings, Billing, Dedicated IPs and pick the tenant. We set it up and tell you when the tenant's mail moves over; nothing changes in your code.
Put your transactional email on solid ground.
Start free on our transactional pool. Move to dedicated IPs or a dedicated server when you need the isolation. Same API either way.