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.
Account quotas
Section titled “Account quotas”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:
| Objects | Default set on |
|---|---|
| Messages, mailboxes, identities, submissions, masked addresses, public keys | Email (maxMessages, maxMailboxes, maxIdentities, maxSubmissions, maxMaskedAddresses, maxPublicKeys) |
| Calendars, events, participant identities, event notifications | Calendar (maxCalendars, maxEvents, maxParticipantIdentities, maxEventNotifications) |
| Address books and contacts | AddressBook (maxAddressBooks, maxContacts) |
| Files and folders | FileStorage (maxFiles, maxFolders) |
| App passwords and API keys | Authentication (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.
Exceeded quotas
Section titled “Exceeded quotas”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
APPENDwithNO [OVERQUOTA] Quota exceeded.andCOPYorMOVEwithNO [OVERQUOTA] Mailbox quota exceeded. Creating a mailbox beyond the mailbox count fails withNO [OVERQUOTA] There are too many mailboxes, please delete some before adding a new one.. - JMAP reports the error
overQuotaon the object that could not be created, with a description such asYou 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..
Recalculating usage
Section titled “Recalculating usage”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
AccountMaintenancetask of typerecalculateQuotarecomputes one account. - A
StoreMaintenancetask of typeresetUserQuotasresets the counters of all accounts. - In the Enterprise edition, a
TenantMaintenancetask of typerecalculateQuotarecomputes a tenant.