Mail Server

Managing Mailboxes

Create and manage email accounts, distribution lists, and groups via the Stalwart admin API — including authentication, PATCH format, and quota configuration.

intermediate8 min read

Overview

All mailbox management in Stalwart — creating accounts, setting up distribution lists, and managing groups — is done through the /api/principal endpoint. The admin panel provides a UI for common operations, but the API is the authoritative interface and is required for any automated or programmatic provisioning.

Key Concepts

Principal — Stalwart's unified model for any entity that can send, receive, or route mail. The three principal types relevant to mailbox management are:

Type Description
individual A standard mailbox with a single user. Has a password and can log in via IMAP/JMAP.
group A named collection of individuals. Mail to the group address is delivered to all members. Equivalent to a distribution list when members are individual accounts.
list A mailing list with subscribers. Supports moderated posting and public/private subscription.

Authentication — All Stalwart admin API requests use HTTP Basic authentication. The Authorization header must contain Basic <base64(username:password)>. Bearer tokens are not valid for the admin API.

PATCH Format — Stalwart uses a specific array-of-operations format for all PATCH requests. Each operation has action, field, and value keys. This differs from JSON Patch (RFC 6902).

Creating an Account

POST /api/principal
Content-Type: application/json
Authorization: Basic <credentials>

{
  "type": "individual",
  "name": "alice",
  "emails": ["alice@dramwell.ai"],
  "secrets": ["initialPassword123!"],
  "quota": 1073741824
}

Key fields:

Field Description
type individual, group, or list
name The login name (must be unique)
emails Array of email addresses associated with this account
secrets Array containing the initial plaintext password (hashed on storage)
quota Storage quota in bytes. 0 means unlimited. 1073741824 = 1 GB

A successful creation returns HTTP 200 with the principal name in the response body.

Updating an Account

All updates use PATCH with the array-of-operations format:

PATCH /api/principal/alice
Content-Type: application/json
Authorization: Basic <credentials>

[
  {"action": "set", "field": "quota", "value": 2147483648},
  {"action": "set", "field": "description", "value": "Alice Smith — Engineering"}
]

To add or remove email aliases:

[
  {"action": "addItem", "field": "emails", "value": "a.smith@dramwell.ai"},
  {"action": "removeItem", "field": "emails", "value": "oldAlias@dramwell.ai"}
]

Available actions: set, addItem, removeItem.

Creating a Distribution List (Group)

POST /api/principal
Content-Type: application/json
Authorization: Basic <credentials>

{
  "type": "group",
  "name": "team-engineering",
  "emails": ["engineering@dramwell.ai"],
  "members": ["alice", "bob", "carol"]
}

Mail sent to engineering@dramwell.ai is delivered to all members listed. Members are referenced by their principal name (login name), not their email address.

To add a member to an existing group:

PATCH /api/principal/team-engineering

[{"action": "addItem", "field": "members", "value": "dave"}]

Quota Management

Quota is set in bytes at the account level. Common values:

Quota Bytes
500 MB 524288000
1 GB 1073741824
5 GB 5368709120
Unlimited 0

To check current usage for an account, fetch the principal and read the usedQuota field:

GET /api/principal/alice

The response includes usedQuota (bytes currently used) alongside the configured quota ceiling.

Deleting an Account

DELETE /api/principal/alice
Authorization: Basic <credentials>

Deletion is permanent and immediate. All stored messages are removed. Before deleting a production account, verify no active services depend on it and consider exporting mail via JMAP first.

Tips

  • Always use the principal name (login name) as the identifier in API paths — not the email address. The name is the stable identifier; email addresses can change via PATCH.
  • When creating accounts programmatically (e.g., during customer org provisioning), generate a strong random initial password and immediately send the user a password reset link rather than transmitting the initial password.
  • If the API returns a 401 despite correct credentials, verify you are encoding username:password as a single base64 string — not encoding them separately.

Related Articles

Was this article helpful?