> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sendpost.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Tenant Applications

> Build multi-tenant email applications by creating sub-accounts for each tenant, managing domains and IPPools, and using custom headers for event reconciliation via webhooks.

Multi-tenant applications require isolating email sending infrastructure, tracking, and analytics per tenant. SendPost provides sub-accounts, domain management, IPPool routing, and custom headers to build scalable multi-tenant email systems.

## Architecture Overview

A multi-tenant email application typically requires:

1. **Sub-account isolation**: Create a separate sub-account for each tenant
2. **Domain management**: Whitelist and verify sending domains per sub-account
3. **Custom headers**: Include tenant identifiers in email requests for webhook reconciliation
4. **IPPool routing**: Use shared IPPools for smaller tenants and dedicated IPPools for high-volume senders
5. **Webhook processing**: Consume webhook events with custom headers to reconcile stats per tenant

## Creating Sub-Accounts for Tenants

Create a new sub-account for each tenant when they sign up or when you need to isolate their email sending.

```json theme={null}
POST /api/v1/account/subaccount/
X-Account-ApiKey: your_account_api_key

{
  "name": "tenant-acme-corp",
  "companyName": "Acme Corporation"
}
```

Each sub-account receives its own API key (`X-SubAccount-ApiKey`) for sending emails and managing sub-account resources. Store the sub-account ID and API key in your tenant database.

<Info>
  Use the Account API key (`X-Account-ApiKey`) to create and manage sub-accounts. Use the Sub-Account API key (`X-SubAccount-ApiKey`) for all email sending and sub-account-specific operations.
</Info>

## Managing Domains Per Sub-Account

After creating a sub-account, create and verify sending domains for that tenant. Each sub-account can have multiple verified domains.

### Creating a Domain

```json theme={null}
POST /api/v1/subaccount/domain
X-SubAccount-ApiKey: tenant_subaccount_api_key

{
  "domain": "mail.acme-corp.com"
}
```

### Verifying Domain Ownership

After creating a domain, SendPost provides DNS records (SPF, DKIM, DMARC) that must be added to your tenant's DNS. Retrieve the domain details to get the required DNS records:

```json theme={null}
GET /api/v1/subaccount/domain/{domain_id}
X-SubAccount-ApiKey: tenant_subaccount_api_key
```

Once DNS records are verified, the domain is ready for sending. Use the verified domain in the `from.email` field when sending emails for that tenant.

<Info>
  Domain verification is required before sending emails. Unverified domains will cause email sending to fail. See [Create a New Domain](/api-reference/domain/create-a-new-domain) for detailed DNS configuration steps.
</Info>

## Using Custom Headers for Tenant Identification

Include custom headers in every email request to identify the tenant and enable webhook reconciliation. Headers are preserved throughout the email lifecycle and included in all webhook events.

```json theme={null}
{
  "from": {
    "email": "notifications@mail.acme-corp.com",
    "name": "Acme Corp"
  },
  "to": [
    {
      "email": "user@example.com",
      "name": "John Doe"
    }
  ],
  "subject": "Welcome to Acme Corp",
  "htmlBody": "<p>Welcome aboard!</p>",
  "headers": {
    "Tenant-ID": "acme-corp-123",
    "Workspace-ID": "workspace-456",
    "User-ID": "user-789"
  },
  "trackOpens": true,
  "trackClicks": true,
  "ippool": "shared-marketing"
}
```

### Header Best Practices

* Use consistent naming conventions (e.g., `Tenant-ID`, `Workspace-ID`)
* Include tenant identifiers in every email request
* Store header values in your tenant database for easy lookup
* Use headers to filter webhook events in your application

<Info>
  Custom headers are included in all webhook events (Processed, Delivered, Opened, Clicked, Bounced, Unsubscribed, Spam), making it easy to reconcile events per tenant. See [Custom Headers](/api-reference/common-use-cases/custom-headers) for more details.
</Info>

## Managing IPPools for Multi-Tenant Routing

IPPools control which IP addresses or third-party sending providers (TPSPs) are used for sending emails. Use different IPPool strategies based on tenant volume and requirements.

### Shared IPPools for Smaller Tenants

Smaller tenants should use shared IPPools that distribute sending across multiple IPs and TPSPs. This provides cost efficiency and adequate deliverability.

```json theme={null}
{
  "from": {
    "email": "notifications@mail.acme-corp.com",
    "name": "Acme Corp"
  },
  "to": [
    {
      "email": "user@example.com"
    }
  ],
  "subject": "Welcome",
  "htmlBody": "<p>Welcome!</p>",
  "ippool": "shared-pool"
}
```

### Dedicated IPPools for High-Volume Tenants

Large-volume tenants may require dedicated IPPools for better deliverability, reputation management, and compliance. Create dedicated IPPools and assign them to specific tenants.

```json theme={null}
POST /api/v1/account/ippool
X-Account-ApiKey: your_account_api_key

{
  "name": "acme-corp-dedicated",
  "ips": ["IP_100", "IP_101"],
  "routingStrategy": 0,
  "routingMetaData": "{}"
}
```

Then use the dedicated IPPool when sending emails for that tenant:

```json theme={null}
{
  "from": {
    "email": "notifications@mail.acme-corp.com",
    "name": "Acme Corp"
  },
  "to": [
    {
      "email": "user@example.com"
    }
  ],
  "subject": "Welcome",
  "htmlBody": "<p>Welcome!</p>",
  "ippool": "acme-corp-dedicated"
}
```

### IPPool Routing Strategies

SendPost supports multiple routing strategies for IPPools:

* **Round Robin (0)**: Distribute emails evenly across all IPs and TPSPs
* **Email Provider Strategy (1)**: Route emails based on recipient email provider (Gmail, Yahoo, Microsoft, etc.)
* **Volume Percentage Strategy (2)**: Assign specific volume percentages to each IP or TPSP
* **Sending Domain Strategy (3)**: Route emails based on the sending domain

See [IPPool Routing](/api-reference/ippools/routing) for detailed routing strategy configuration.

<Info>
  IPPools are managed at the account level using `X-Account-ApiKey`, but can be used by any sub-account when sending emails. Assign IPPool names to tenants in your database to control which pool each tenant uses.
</Info>

## Webhook Reconciliation

When an email is processed, delivered, hard bounced, soft bounced, opened, clicked, unsubscribed, or marked as spam, SendPost sends a webhook event to your configured endpoint. The webhook payload includes your custom headers, allowing you to reconcile events per tenant.

### Webhook Event Structure

```json theme={null}
{
  "event": {
    "eventID": "edhg-123gh-afasdf-124egh",
    "type": 5,
    "messageID": "mjhl-1401-sasdf-129324",
    "eventMetadata": {
      "userAgent": {
        "Family": "Chrome",
        "Major": "91"
      }
    }
  },
  "emailMessage": {
    "messageID": "mjhl-1401-sasdf-129324",
    "from": {
      "email": "notifications@mail.acme-corp.com",
      "name": "Acme Corp"
    },
    "to": [
      {
        "email": "user@example.com",
        "name": "John Doe"
      }
    ],
    "subject": "Welcome to Acme Corp",
    "headers": {
      "Tenant-ID": "acme-corp-123",
      "Workspace-ID": "workspace-456",
      "User-ID": "user-789"
    },
    "groups": ["transactional", "welcome"]
  }
}
```

### Processing Webhooks

1. **Extract tenant identifier**: Read `emailMessage.headers.Tenant-ID` from the webhook payload
2. **Identify event type**: Check `event.type` to determine the event (Delivered, Opened, Clicked, etc.)
3. **Update tenant stats**: Update your tenant's statistics based on the event type
4. **Store event data**: Persist the event in your database for analytics and reporting

### Webhook Event Types

| Event Type   | Type Value | Description                                                            |
| ------------ | ---------- | ---------------------------------------------------------------------- |
| Processed    | 0          | Email accepted and queued for sending                                  |
| Dropped      | 1          | Email dropped before delivery (invalid address or in suppression list) |
| Delivered    | 2          | Email successfully delivered to recipient's mail server                |
| SoftBounced  | 3          | Temporary delivery failure (will retry)                                |
| HardBounced  | 4          | Permanent delivery failure (invalid address)                           |
| Opened       | 5          | Recipient opened the email                                             |
| Clicked      | 6          | Recipient clicked a link in the email                                  |
| Unsubscribed | 7          | Recipient clicked unsubscribe link                                     |
| Spam         | 8          | Recipient marked email as spam                                         |

<Info>
  Custom headers are included in every webhook event for a given email, allowing you to filter and process webhooks based on tenant identifiers without needing to store additional mapping data. See [Understanding Webhook Event Lifecycle](/api-reference/webhook/understanding-webhook-event-lifecycle) for complete event lifecycle details.
</Info>

## Complete Multi-Tenant Example

Here's a complete example of setting up and sending emails for a new tenant:

### 1. Create Sub-Account

```json theme={null}
POST /api/v1/account/subaccount/
X-Account-ApiKey: your_account_api_key

{
  "name": "tenant-acme-corp",
  "companyName": "Acme Corporation"
}
```

Response:

```json theme={null}
{
  "id": 12345,
  "name": "tenant-acme-corp",
  "companyName": "Acme Corporation",
  "apiKey": "AHEZEP8192SEGH"
}
```

### 2. Create and Verify Domain

```json theme={null}
POST /api/v1/subaccount/domain
X-SubAccount-ApiKey: AHEZEP8192SEGH

{
  "domain": "mail.acme-corp.com"
}
```

Add DNS records to tenant's DNS, then verify domain is ready for sending.

### 3. Send Email with Custom Headers

```json theme={null}
POST /api/v1/subaccount/email/
X-SubAccount-ApiKey: AHEZEP8192SEGH

{
  "from": {
    "email": "notifications@mail.acme-corp.com",
    "name": "Acme Corp"
  },
  "to": [
    {
      "email": "user@example.com",
      "name": "John Doe",
      "customFields": {
        "firstName": "John"
      }
    }
  ],
  "subject": "Welcome {{firstName}}!",
  "htmlBody": "<p>Hi {{firstName}}, welcome to Acme Corp!</p><p><a href='{{unsubscribe}}'>Unsubscribe</a></p>",
  "headers": {
    "Tenant-ID": "acme-corp-123",
    "Workspace-ID": "workspace-456"
  },
  "ippool": "shared-pool",
  "trackOpens": true,
  "trackClicks": true,
  "groups": ["transactional", "welcome"]
}
```

### 4. Process Webhook Events

When the email is delivered, opened, or clicked, you'll receive webhook events with the custom headers:

```json theme={null}
{
  "event": {
    "type": 5,
    "messageID": "mjhl-1401-sasdf-129324"
  },
  "emailMessage": {
    "headers": {
      "Tenant-ID": "acme-corp-123",
      "Workspace-ID": "workspace-456"
    }
  }
}
```

Extract `Tenant-ID` from headers and update tenant statistics accordingly.

## Related Use Cases

Multi-tenant applications also leverage these features:

* **[Personalization](/api-reference/common-use-cases/personalisation-within-emails)**: Use Handlebars templating with `customFields` to personalize email content per recipient
* **[Unsubscribe Links](/api-reference/common-use-cases/adding-unsubscribe-links)**: Add `{{unsubscribe}}` template variables to comply with email regulations
* **[Sender Name and Email Control](/api-reference/common-use-cases/controlling-sender-name-and-email)**: Set tenant-specific sender identities using the `from` field
* **[Email Classification](/api-reference/common-use-cases/using-groups-for-email-classification)**: Use `groups` to categorize emails by type, campaign, or product line for analytics

## Best Practices

1. **Isolate by sub-account**: Create separate sub-accounts for each tenant to ensure complete isolation
2. **Verify domains early**: Set up and verify domains as part of tenant onboarding
3. **Always include headers**: Include tenant identifiers in every email request for webhook reconciliation
4. **Choose appropriate IPPools**: Use shared IPPools for smaller tenants and dedicated IPPools for high-volume senders
5. **Process webhooks idempotently**: Use `eventID` to prevent duplicate processing of webhook events
6. **Monitor tenant stats**: Use custom headers to filter and aggregate statistics per tenant from webhook events

<Warning>
  Each sub-account requires its own verified domain. Sending from unverified domains will fail. Ensure domains are verified before sending emails for a tenant.
</Warning>

<Info>
  Sub-accounts provide complete isolation: each tenant has separate API keys, domains, suppressions, and statistics. Use sub-accounts to ensure tenant data and sending infrastructure remain isolated.
</Info>
