Skip to content

Mail retention

Without limits, mailboxes and their synchronisation history grow for as long as an account exists. Messages pile up in the Trash and Junk folders, records of sent messages accumulate, and the history that clients use to synchronise keeps growing. Stalwart therefore removes old messages from the Trash and Junk folders, old email submissions and old entries of the change history on a schedule.

The settings that control these processes for mail are part of the DataRetention singleton, found in the WebUI under Settings › Storage › Data Retention › Archiving, Settings › Storage › Data Retention › Data Cleanup, Settings › Storage › Data Retention › Auto-Expunge, Settings › Storage › Data Retention › Telemetry. The same singleton also holds the retention settings of other data types. When and how the freed disk space is returned to the file system is described in Data retention and reclaiming disk space.

Each kind of mail data has its own retention setting, and each removes something different:

FieldDefaultWhat is removed
expungeTrashAfter30 daysMessages in the Trash and Junk folders, once they have been there for longer than this period.
expungeSubmissionsAfter3 daysJMAP email submission records, which track the delivery of messages sent through JMAP. The sent messages themselves are not affected.
maxChangesHistory10000Entries of the change history beyond this number, per account.
archiveDeletedItemsForunsetWhen set, expunged messages are kept in an archive for this period and can be recovered (Enterprise edition).

Durations are given in milliseconds. Each setting can also be turned off. Setting expungeTrashAfter or expungeSubmissionsAfter to null disables that expiry, and setting maxChangesHistory to null keeps the full history.

The settings take effect through a scheduled process, auto-expunge, rather than continuously. The process runs at expungeSchedule, daily at 00:00 unless changed, and processes every account. It deletes the qualifying messages from the Trash and Junk folders, removes expired submissions, and truncates the change history. The following object body keeps messages in the Trash and Junk folders for 14 days, and runs the process at 03:30:

{
"expungeTrashAfter": 1209600000,
"expungeSchedule": {"@type": "Daily", "hour": 3, "minute": 30}
}

Deleting a message and removing it from the server are different steps, and clients reach the second step in different ways. A message that a user deletes in a mail client is normally moved to the Trash folder. It stays there until the user empties the folder, or auto-expunge removes it.

The protocols also allow more direct removal. An IMAP client can mark a message with the \Deleted flag, in which case the message remains in its folder until the client issues EXPUNGE or CLOSE. A JMAP client destroys a message directly with Email/set. In each case, the message is removed from the account as soon as it is expunged, and its size is credited to the account’s quota at once.

Expunging is final unless the deleted-item archive is enabled. When archiveDeletedItemsFor is set, expunged messages are kept for that period and can be restored, as described in Recovering deleted items.

JMAP and IMAP clients synchronise incrementally. Instead of downloading a mailbox again, they ask the server what has changed since a state they saw before. JMAP clients use the /changes methods, and IMAP clients use the CONDSTORE and QRESYNC extensions. The server answers from the change history it keeps for each account.

maxChangesHistory bounds the number of entries kept per account, and the bound has a consequence for clients that stay away too long. A client whose last known state is older than the oldest entry still kept cannot be told what changed. A JMAP client receives a cannotCalculateChanges error, and resynchronises the affected data in full. An IMAP client has to fetch the state of the mailbox again.

The value is therefore a trade-off between storage and synchronisation cost. Raising it lets clients that connect rarely, or accounts with frequent changes, synchronise incrementally for longer, at the cost of more storage per account.