Overview
A mailbox in TenantCore is a shared mailbox provisioned on a verified custom domain in a Microsoft 365 tenant. Each domain supports up to 3 mailboxes. Mailboxes are created as shared mailboxes in Exchange Online and do not consume a Microsoft 365 license.
Send limits are opt-in, not mandatory. Mailboxes are created without an enforced send limit by design. If you have fewer domains and want higher per-mailbox volume, you can leave limits unenforced and mailboxes will send without restriction.
Send limit enforcement is a two-step process:
- Set the limit — use
PATCH /v1/tenants/{tenant_id}/mailboxes/{mailbox_id} to store a daily_send_limit value per mailbox
- Provision enforcement — use
POST /v1/tenants/{tenant_id}/mailbox-limits to write the Exchange transport rule that enforces it
Setting a daily_send_limit on a mailbox without provisioning enforcement saves the value but does not restrict sending. The Exchange transport rule is what enforces the ceiling at the infrastructure level.
Exchange Online propagation after provisioning a mailbox takes 2 to 5 minutes. The mailbox will not be immediately available for sending after the API call returns.
List mailboxes
Returns all mailboxes across all domains on a tenant.
GET /v1/tenants/{tenant_id}/mailboxes
Path parameters
| Parameter | Type | Description |
|---|
tenant_id | string | The Microsoft tenant GUID |
Example request
curl https://api.tenantcore.io/v1/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/mailboxes \
-H "Authorization: Bearer tc_live_your_key"
Example response
{
"tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"mailboxes": [
{
"id": "uuid",
"display_name": "John Doe",
"primary_smtp": "john@mail.acmecorp.com",
"user_principal_name": "john@mail.acmecorp.com",
"mail_nickname": "john",
"account_enabled": true,
"daily_send_limit": 25,
"sends_today": 12,
"blocked_at": null,
"created_at": "2025-01-20T10:00:00Z",
"domain_name": "mail.acmecorp.com",
"tenant_name": "Acme Corp"
}
],
"count": 1
}
Response fields
| Field | Type | Description |
|---|
primary_smtp | string | The mailbox email address |
account_enabled | boolean | Whether the account is enabled in Azure AD |
daily_send_limit | number | Configured daily send cap (1 to 25) |
sends_today | number | Emails sent today as reported by Exchange message trace |
blocked_at | timestamp or null | When the mailbox was blocked by enforcement, or null if not blocked |
Errors
| Status | Code | Description |
|---|
404 | tenant_not_found | Tenant does not exist or belongs to a different account |
Provision mailboxes
Creates one or more shared mailboxes on a verified domain. Up to 3 mailboxes per domain. All mailboxes in the request must belong to the same domain.
POST /v1/tenants/{tenant_id}/mailboxes
Path parameters
| Parameter | Type | Description |
|---|
tenant_id | string | The Microsoft tenant GUID |
Request body
{
"domain": "mail.acmecorp.com",
"account_password": "SecureP@ssw0rd!",
"mailboxes": [
{ "name": "John Doe", "email": "john@mail.acmecorp.com" },
{ "name": "Jane Doe", "email": "jane@mail.acmecorp.com" }
]
}
| Field | Type | Required | Description |
|---|
domain | string | Yes | The verified domain to create mailboxes on |
account_password | string | Yes | Initial password for the underlying user account. Min 8 characters. Must meet Microsoft’s complexity requirements. |
mailboxes | array | Yes | List of mailboxes to create. Max 3 total per domain including existing. |
mailboxes[].name | string | Yes | Display name for the mailbox |
mailboxes[].email | string | Yes | Full email address. Must end with @{domain}. |
Example request
curl -X POST \
https://api.tenantcore.io/v1/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/mailboxes \
-H "Authorization: Bearer tc_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"domain": "mail.acmecorp.com",
"account_password": "SecureP@ssw0rd!",
"mailboxes": [
{ "name": "Sales Outreach", "email": "sales@mail.acmecorp.com" }
]
}'
Example response
{
"created_count": 1,
"exists_count": 0,
"failed_count": 0,
"results": [
{
"status": "created",
"name": "Sales Outreach",
"email": "sales@mail.acmecorp.com",
"details": {
"display_name": "Sales Outreach",
"primary_smtp": "sales@mail.acmecorp.com",
"user_principal_name": "sales@mail.acmecorp.com",
"alias": "sales"
}
}
]
}
Result statuses per mailbox
| Status | Meaning |
|---|
created | Mailbox was successfully provisioned |
exists | Mailbox already exists, no action taken |
failed | Provisioning failed for this mailbox, check error field in result |
Prerequisites
- The domain must be verified in Microsoft 365
- Exchange bootstrap must be
ready on the tenant
- SMTP AUTH must be enabled on the tenant
Errors
| Status | Code | Description |
|---|
400 | mailbox_limit_reached | Domain already has 3 mailboxes |
400 | — | Invalid email domain, duplicate emails, or weak password |
404 | tenant_not_found | Tenant does not exist or belongs to a different account |
404 | domain_not_found | Domain not registered on this tenant |
Update mailbox
Updates the display name or daily send limit of a mailbox. Updating daily_send_limit stores the value in TenantCore but does not provision Exchange enforcement on its own. To activate enforcement at the Exchange level, call POST /v1/tenants/{tenant_id}/mailbox-limits after updating the limit.
PATCH /v1/tenants/{tenant_id}/mailboxes/{mailbox_id}
Path parameters
| Parameter | Type | Description |
|---|
tenant_id | string | The Microsoft tenant GUID |
mailbox_id | string | The TenantCore mailbox UUID (from list mailboxes) |
Request body
{
"display_name": "New Display Name",
"daily_send_limit": 20
}
| Field | Type | Required | Description |
|---|
display_name | string | No | New display name for the mailbox |
daily_send_limit | number | No | Daily send cap between 1 and 25. Stores the value in TenantCore. Exchange enforcement must be provisioned separately. |
At least one field must be provided.
Example request
curl -X PATCH \
https://api.tenantcore.io/v1/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/mailboxes/mailbox-uuid \
-H "Authorization: Bearer tc_live_your_key" \
-H "Content-Type: application/json" \
-d '{"daily_send_limit": 20}'
Example response
{
"status": "updated",
"mailbox": {
"id": "mailbox-uuid",
"display_name": "Sales Outreach",
"primary_smtp": "sales@mail.acmecorp.com",
"daily_send_limit": 20,
"sends_today": 12,
"account_enabled": true
}
}
Errors
| Status | Code | Description |
|---|
400 | invalid_send_limit | daily_send_limit is outside the 1 to 25 range |
400 | no_updates | Request body contained no recognised fields |
404 | tenant_not_found | Tenant does not exist or belongs to a different account |
404 | mailbox_not_found | Mailbox does not exist on this tenant |
Set enforcement
Saves a send limit policy and provisions the Exchange Online transport rule that enforces it. This is the step that activates the hard ceiling at the infrastructure level. Until this is called, daily_send_limit values on mailboxes are stored but not enforced by Exchange.
Enforcement is scoped at the domain level. Apply it to a specific domain or tenant-wide across all domains at once.
POST /v1/tenants/{tenant_id}/mailbox-limits
Path parameters
| Parameter | Type | Description |
|---|
tenant_id | string | The Microsoft tenant GUID |
Request body
{
"daily_send_limit": 25,
"domain_scope": "mail.acmecorp.com"
}
| Field | Type | Required | Description |
|---|
daily_send_limit | number | Yes | The enforced daily send cap between 1 and 25 |
domain_scope | string | No | The domain to scope enforcement to. Omit to apply tenant-wide across all domains. |
Example request — single domain
curl -X POST \
https://api.tenantcore.io/v1/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/mailbox-limits \
-H "Authorization: Bearer tc_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"daily_send_limit": 25,
"domain_scope": "mail.acmecorp.com"
}'
Example request — tenant-wide
curl -X POST \
https://api.tenantcore.io/v1/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/mailbox-limits \
-H "Authorization: Bearer tc_live_your_key" \
-H "Content-Type: application/json" \
-d '{"daily_send_limit": 25}'
Example response
{
"status": "success",
"tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"daily_send_limit": 25,
"domain_scope": "mail.acmecorp.com",
"scope_label": "mail.acmecorp.com",
"policy": {},
"provisioning": {}
}
Errors
| Status | Code | Description |
|---|
400 | invalid_send_limit | daily_send_limit is outside the 1 to 25 range |
404 | tenant_not_found | Tenant does not exist or belongs to a different account |
404 | domain_not_found | Specified domain_scope is not registered on this tenant |
409 | exchange_bootstrap_not_ready | Exchange bootstrap has not completed for this tenant |
Get enforcement policy
Returns the current limit policy for a tenant or specific domain.
GET /v1/tenants/{tenant_id}/mailbox-limits
Path parameters
| Parameter | Type | Description |
|---|
tenant_id | string | The Microsoft tenant GUID |
Query parameters
| Parameter | Type | Description |
|---|
domain_scope | string | Optional. Pass a domain name to retrieve the policy for that domain. Omit for the tenant-wide policy. |
Example request
curl "https://api.tenantcore.io/v1/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/mailbox-limits?domain_scope=mail.acmecorp.com" \
-H "Authorization: Bearer tc_live_your_key"
Errors
| Status | Code | Description |
|---|
404 | tenant_not_found | Tenant does not exist or belongs to a different account |
404 | policy_not_found | No limit policy has been set for this scope |
Get mailbox usage
Returns daily send counts, limit status, and block state for a specific mailbox.
GET /v1/tenants/{tenant_id}/mailboxes/{mailbox_id}/usage
Path parameters
| Parameter | Type | Description |
|---|
tenant_id | string | The Microsoft tenant GUID |
mailbox_id | string | The TenantCore mailbox UUID |
Example request
curl https://api.tenantcore.io/v1/tenants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/mailboxes/mailbox-uuid/usage \
-H "Authorization: Bearer tc_live_your_key"
Example response
{
"mailbox_id": "mailbox-uuid",
"primary_smtp": "sales@mail.acmecorp.com",
"display_name": "Sales Outreach",
"account_enabled": true,
"daily_send_limit": 25,
"sends_today": 18,
"remaining_sends": 7,
"is_blocked": false,
"blocked_at": null,
"utilization_pct": 72.0
}
Response fields
| Field | Type | Description |
|---|
daily_send_limit | number | The configured cap |
sends_today | number | Emails sent today from Exchange message trace |
remaining_sends | number | daily_send_limit - sends_today, floored at 0 |
is_blocked | boolean | true if enforcement has blocked this mailbox |
blocked_at | timestamp or null | When the block was applied |
utilization_pct | number | sends_today / daily_send_limit x 100, rounded to 1 decimal |
Errors
| Status | Code | Description |
|---|
404 | tenant_not_found | Tenant does not exist or belongs to a different account |
404 | mailbox_not_found | Mailbox does not exist on this tenant |