Skip to content

Quotas

On a shared server, one account must not be able to consume the resources of all the others. Quotas set that limit. They cap how much an account may store and how many objects of each kind it may hold, so that a single account cannot exhaust the server’s storage or degrade it with an unbounded number of mailboxes or events.

Stalwart has two kinds of quota. A disk quota caps the bytes an account uses for messages, files and other data. An object quota caps the number of items of one kind, such as messages, mailboxes, calendars or app passwords. In the Enterprise edition, tenants have quotas of their own as well, which cap the combined usage of all their members.

The limits of an account are set in the quotas field of its Account object (found in the WebUI under Management › Directory › Groups, Management › Directory › Accounts). The field is a map from a quota type to a number. maxDiskQuota is given in bytes, and every other type is a count. The following value limits an account to 10 GB, 300 calendars and 500 address books:

{
"quotas": {
"maxDiskQuota": 10737418240,
"maxCalendars": 300,
"maxAddressBooks": 500
}
}

The two kinds of quota behave differently when the account does not set them. An account has no disk quota at all unless maxDiskQuota is set. An object quota, on the other hand, always has a limit: a type that the account does not set falls back to a server-wide default. Each default is defined on the singleton of the service that owns the objects:

ObjectsDefault set on
Messages, mailboxes, identities, submissions, masked addresses, public keysEmail (maxMessages, maxMailboxes, maxIdentities, maxSubmissions, maxMaskedAddresses, maxPublicKeys)
Calendars, events, participant identities, event notificationsCalendar (maxCalendars, maxEvents, maxParticipantIdentities, maxEventNotifications)
Address books and contactsAddressBook (maxAddressBooks, maxContacts)
Files and foldersFileStorage (maxFiles, maxFolders)
App passwords and API keysAuthentication (maxAppPasswords, maxApiKeys)

The StorageQuota enumeration lists every quota type an account accepts. The read-only usedDiskQuota field reports the space the account currently uses.

Quotas are always configured on the server. External directories such as LDAP and SQL do not supply them, even when they supply the account itself.

A group account has its own quotas. The messages that members store in the group’s mailboxes count against the group, not against the members who stored them.

When an operation would exceed a quota, the server refuses it. Each protocol reports the refusal in its own way, so the message a user sees depends on the protocol:

  • IMAP answers APPEND with NO [OVERQUOTA] Quota exceeded. and COPY or MOVE with NO [OVERQUOTA] Mailbox quota exceeded. Creating a mailbox beyond the mailbox count fails with NO [OVERQUOTA] There are too many mailboxes, please delete some before adding a new one..
  • JMAP reports the error overQuota on the object that could not be created, with a description such as You have exceeded your account quota.
  • ManageSieve answers with NO (QUOTA/MAXSIZE) "Quota exceeded.".

Incoming mail is treated differently. SMTP accepts mail for an account over its quota and attempts the delivery later. The message stays in the queue with the temporary error 451 4.3.0 Mailbox over quota. and is retried according to the delivery schedule. Delivery succeeds once space is freed. If the message expires first, the sender receives a delivery failure notice.

A tenant’s disk quota produces its own messages. When the tenant’s disk quota is exhausted, IMAP reports NO [OVERQUOTA] Organization disk quota exceeded. and the queue reports Organization over quota..

The server updates the disk usage of an account as data is added and removed. The stored figure can still become wrong, for example after a restore. In that case it can be recomputed with a task, and the task type depends on the scope:

  • An AccountMaintenance task of type recalculateQuota recomputes one account.
  • A StoreMaintenance task of type resetUserQuotas resets the counters of all accounts.
  • In the Enterprise edition, a TenantMaintenance task of type recalculateQuota recomputes a tenant.