Quotas, retention and the archive: how much mail the server keeps, and for how long
-
This topic covers how much mail an hMailServer 6.3.4 server keeps, and for how long: each mailbox's limit and the quota policy 6.3.4 adds around it; retention, the administrator's and each person's, with the recover-deleted window; and the server archive under
ArchiveDir. The one thing to know first: out of the box nothing is deleted because of its age. A new account has no limit (0), no domain has a retention policy, the archive is off, and once it is on,ArchiveRetentionDaysis0, keep for ever.The limit, and what a full mailbox does
Where it is set.
Account.MaxSizeover COM,max_size_mbover REST, in megabytes;0, the default, is no limit. Set it on the Control Panel's account dialog (Quota (MB), Windows only), in the Control Deck's account editor, withPUT /api/v1/accounts/{address}, in themax_size_mbcolumn of an accounts CSV file (since 6.3.4), or withSet-HmAccount. A domain's Limits tab caps the whole domain (Maximum domain size (MB),0for none; once reached, delivery to its mailboxes fails) and sets the quota new accounts get.What counts is each message's original size: compression does not lower it, and a mailbox encrypted at rest keeps its sizes in the clear. The kept copy of a message the person sent to expire counts against their quota (413,
quota_exceeded).Where At the limit SMTP RCPT TO, withRejectFullMailboxAtRcpton (1, the default)A mailbox already at or over its limit, and past any grace (below), is answered 452 4.2.2 Mailbox is full., a temporary refusal: the sending server keeps the message and retriesA message that arrives while there is room and would overflow it Caught at delivery, with a non-delivery report to the envelope sender RejectFullMailboxAtRcptat0Accepted, then bounced to an envelope sender that spam has usually forged. Leave it on IMAP APPEND,COPY,MOVERefused with [OVERQUOTA], so a client can tell a full mailbox from any other refusalAPPENDinto a folder shared from another mailboxSince 6.3.4 charged to the folder's owner, as COPYandMOVEwereA migration or PST import job Pauses with the account has no room left under its quota and tries again; raise the limit or make room A full disk is a different refusal. Below
MinimumFreeDiskSpaceMB(100) free on the store's volume,MAIL FROMgets452 4.3.1 Insufficient system storage.and IMAPAPPENDNO [UNAVAILABLE], for every mailbox. The log warns first, belowDiskSpaceWarningThresholdMB(1024).What the person sees.
- The webmail's Storage page (since 6.3.2,
GET /api/v1/me/storage
the share used, every folder by size, the twenty largest messages, and a clean-up of Trash and Junk older than 7, 30 or 90 days, or everything. See The webmail portal at /portal. GET /api/v1/meanswersquotawithlimit_mbandused_bytes.- IMAP QUOTA:
QUOTA=RES-STORAGEis advertised;GETQUOTAandGETQUOTAROOTanswer one unnamed root for the whole account withSTORAGEin kilobytes, and an empty list for an account with no limit.SETQUOTAis refused: the limit is the administrator's. It is on as seeded; the switch isimap_quota_enabledonPUT /api/v1/settings(IMAPQuotaEnabledover COM).
The quota policy (since 6.3.4)
The server-wide warning at
QuotaWarningPercent(90) has been there since 6.2.22-pre6. Schema 6061 adds a domain's own warning share and words, a grace and a send-stop, each a share of the limit; schema 6088 lets an account hold its own shares too.Point Server Domain ( -1takes the server's)What it does Warning QuotaWarningPercent, 90;0warns nobodyquota_warning_percentThe delivery that takes the mailbox across this share sends its owner one notice, from the domain's postmaster Grace quota_grace_percent, 0quota_grace_percentHow far past the limit mail from other people is still accepted Send-stop quota_send_stop_percent, 0 (never)quota_send_stop_percentThe share at which the account can no longer send Over COM (Windows):
Settings.QuotaGracePercent,Settings.QuotaSendStopPercent, andDomainproperties of the same names.The warning is sent once, by the delivery that crosses the threshold; nothing records who was warned, so a mailbox emptied and filled again is warned again.
The grace is for mail other people send, the mail otherwise lost. A 1 GB mailbox with a 50% grace receives until it holds 1.5 GB; the owner's own saves and copies over IMAP and the webmail stop at the limit.
The send-stop refuses the account, not the address. An authenticated
MAIL FROMis refused with552 5.2.2and the reason, keyed on the account that signed in, even under a domain alias, not the address it named. Receiving goes on. QuotaPolicy.md describes the refusal at SMTP only; test the webmail's send and the send API before relying on it there.The words are the
QUOTA_WARNING_SUBJECTandQUOTA_WARNINGserver messages, with%MACRO_MAILBOX%,%MACRO_QUOTA%(MB),%MACRO_USED%(MB) and%MACRO_PERCENT%. Server messages are server-wide (the Control Panel's Mail flow & delivery โ Server messages, the Deck's Server messages page,PUT /api/v1/settings/messages/{name}). A domain sets its own subject and text,quota_warning_subjectandquota_warning_text(Domain.QuotaWarningSubject,Domain.QuotaWarningText), so its people can be warned in their own language. They are chosen apart: a domain that sets only the text keeps the server's subject.Levels. The warning is a preference: the deepest level holding a value wins. The grace and the send-stop are limits: an account's own value may tighten its domain's, never loosen it, while a domain's may sit either side of the server's. The domain's shares are the domain administrator's, and a domain-restricted key's.
<name>_effectiveand<name>_sourceon the domain and account routes say why a mailbox was not warned. An account's own quota shares are tested only through what the routes answer, and only on Windows. The mechanism is in Settings: what is not stock, when a save takes effect, and the three levels.Where it is set.
- Control Deck: the domain editor's Quota policy group; the server's grace and send-stop on the Settings page.
- Control Panel (Windows): the domain dialog's Limits tab; the server's grace and send-stop under SMTP, beside
QuotaWarningPercent. - REST: the five domain keys on
PUT /api/v1/domains/{name}; the server's two onPUT /api/v1/settings. - An account's own value: the Levels tab of the Control Panel's account dialog, the Deck account editor's levels card,
hmctl account set, orPUT /api/v1/accounts/{address}.
QuotaWarningPercentis a key of the settings store: set it in the Control Panel (Windows) on Connections & protocols โ Protocols, SMTP tab, withPUT /api/v1/settings/ini/{name}orhmctl ini set, which answer to the administrator password alone (never an API key, nor an account holding a role), or, on the Linux server itself,hmailserver --set-setting, not by editinghMailServer.ini. Every value here applies when it is saved through the server, at every level; when a save takes effect explains why a line edited in the file does not hold and when a value stored by--set-settingarrives. A backup taken before the policy restores with the server's values.One domain warned at 85%, stopped from sending at the limit and given a 20% grace, with a German subject; then one account put back on its domain's grace:
hmctl domain set example.com quota_warning_percent 85 hmctl domain set example.com quota_send_stop_percent 100 hmctl domain set example.com quota_grace_percent 20 hmctl domain update example.com --set "quota_warning_subject=Ihr Postfach ist fast voll" hmctl account set [email protected] quota_grace_percent inheritWho is nearest their limit
GET /api/v1/reports/quotalists every mailbox with a limit and at least one message, nearest first:megabytes,quota_megabytes,percent, thewarns_atandsending_stops_atpoints that apply to it, and astateofok,warned,stoppedorover. It takesdomain,top(1 to 200, default 10) andformat=csv, and ignores the date window. Its test has run on the Windows bench only. The Deck's Reports page shows it as Near their quota. Other than the administrator password, a credential needsview_configurationandview_message_trace. The sectionshmctl reportdocuments do not include it:curl -u Administrator:your-admin-password \ "http://127.0.0.1:8443/api/v1/reports/quota?domain=example.com&top=200&format=csv"Nothing records what a mailbox held yesterday; per-domain storage by day is the
storagesection, in Alerts, the audit trail, syslog and the journal, and per-domain reports.Retention: the administrator's policy
MessageRetentionDays(since 6.2.25) is set per domain and per account; there is no server value. On a domain,0(the default) is no policy and a number deletes mail older than that many days. On an account,0(the default) takes the domain's, a number is its own, and-1keeps for ever whatever the domain says.The sweep.
MailboxRetentionTaskruns at start-up and every six hours. It removes delivered messages whose stored creation time is older than the window, in every folder of the mailbox, through the same deletion an IMAPEXPUNGEperforms, so the quota, the QRESYNC record and an open IMAP session all see it.Utilities.RunMessageRetention(COM, Windows only) runs it now and returns the count; no document names a REST route orhmctlverb for it, so on Linux wait for the next pass.Where it is set. On Windows the Control Panel's domain dialog (Limits tab) and account dialog (General tab); the Deck's domain and account editors;
message_retention_dayson the domain and account routes;hmctl domain setandhmctl account set. A domain's retention is the server administrator's (COM refuses a domain administrator, the domain route a restricted key); an account's own value is the domain administrator's, so an account's-1can switch its domain's policy off for that account.Before switching a domain's policy on:
- Give
-1to each account that must keep everything. - Decide whether what the sweep removes should be recoverable for a while (
recover_deleted_days, below). Off, a removed message is gone. - Set the domain's days. It applies when saved; the next pass, at most six hours away, deletes.
Easy to miss. A restore of the built-in backup does not carry a domain's retention days: the wiki's Backup and Restore page lists them as silently reset to
0, so re-enter them. And a legal hold outranks retention: a held account is left alone by the policy and by the person's own choices, and the log says so.Each person's own retention (since 6.3.4)
Three choices on the webmail's preferences page: Empty Trash after, Empty Junk after and Archive Inbox mail after, each never, 7, 30 or 90 days, or a year, kept as
retention_trash_days,retention_junk_daysandretention_archive_days. The same six-hourly sweep runs them after the administrator's policy. Trash and Junk (the folders designated\Trashand\Junk, or named as clients name them) are emptied of what is older; Inbox mail older than the choice is copied to the\Archivefolder, made as a top-levelArchiveif there is none, then removed from the Inbox. That is a folder of the person's mailbox, not the server archive. A value that is not a whole number of days from 1 to 3650 is off.The recover-deleted window (since 6.3.4)
recover_deleted_daysonPUT /api/v1/settingsor the Deck's Settings view (0 to 365;0, off, by default) keeps a copy of what a person deletes, and of what either retention removes, for the person to put back from the webmail's Recover deleted items. A domain or an account may keep copies for fewer days than the level above, never more. The copies, under<data directory>/Recoverable/<account id>/, count against no quota and are not in the backup, so size the window with the disk in mind; the six-hourly task ends those past the window, and all of them at0. The person's side is in The webmail in depth: search, offline mail, expiring messages, send-as and recovery.The server archive
With
ArchiveDirset, the server writes a copy of every message received by SMTP into a tree of its own, as received and in the clear: encryption at rest does not cover it, and the mailbox retention policy does not reach it. The layout, as the Settings Reference writes it (Windows separators, names lower-cased):Message Where the copy goes From a local sender ArchiveDir\<senderdomain>\<sendername>\Sent-<file>From anybody else ArchiveDir\Inbound\<file>For each local recipient ArchiveDir\<recipientdomain>\<recipientname>\<file>, made from the first copy when there is oneA bounce or report with a null sender The archive's Errorfolder, with no index rowThe archive's settings:
Key Default What it does ArchiveDirempty (off) The folder the copies go to ArchiveDomainsempty (every message) Comma-separated: a message is archived only when its local sender or a recipient is in a listed domain, and only the listed domains' copies are made ArchiveHardLinks0Hard-link instead of copy: a promise that nothing outside the server edits a message file in place ArchiveRetentionDays0(keep for ever)Deletes archived copies older than this many days Its sweep runs at start-up and every twelve hours. It removes only
.emlfiles, follows no symbolic link or junction, is depth-capped, and asks the index first: a held copy stays however old.The index (since 6.2.25, schema 6029): a row per copy in
hm_archiveindex, with who, when, what, where and whether it is held; copies made before schema 6029 have none. Search it in the Deck's Archive view (since 6.3.4), withGET /api/v1/archive(domain,mailbox,sender,recipient,subject,since,until,hold=1,limit1 to 1000, default 200, newest first), or withUtilities.SearchArchiveover COM (Windows). A role needsview_archive; a key restricted to named domains must name one of its own, and the Inbound copies are the administrator's alone. Searching the words of archived mail is an eDiscovery case's work.A hold on one copy,
POST /api/v1/archive/{id}/holdorUtilities.SetArchiveHold, keeps its file and row from the sweep and from an address's erasure;DELETElifts it. Holds on whole accounts and domains are eDiscovery's: see Compliance: eDiscovery, legal holds, personal data, erasure and the audit trail.curl -u Administrator:your-admin-password \ "http://127.0.0.1:8443/api/v1/archive?domain=example.com&[email protected]&since=2026-09-01&limit=50" curl -u Administrator:your-admin-password -X POST http://127.0.0.1:8443/api/v1/archive/4471/holdWhere it is set. On Windows, the Control Panel's Maintenance โ Advanced, Copies of mail tab (
ArchiveDir,ArchiveHardLinks,ArchiveDomains), andArchiveRetentionDayson the SMTP tab of Connections & protocols โ Protocols. The Deck has no page for these keys: usePUT /api/v1/settings/ini/{name}orhmctl ini set <name> <value>(the administrator password only), which take effect when saved, orhmailserver --set-setting NAME=VALUE(withsudo) on the Linux server itself, which, while the service runs, waits for the next save, a reinitialise (POST /api/v1/server/reinitialize) or a restart.Setting one up:
- Choose a folder outside the data directory: a full restore with the messages option replaces that directory, and an archive inside it too, held copies included.
- On Windows, a new installation runs the service as
NT SERVICE\hMailServer, which writes only where it is granted: approve the folder by runninghMailServer.exe /GrantServiceAccesswith--approve-modify "<folder>"from an elevated Command Prompt in the installation'sBinfolder. It must be a full path on a fixed local drive, outside the program folder, Program Files, the Windows folder and the profiles folder: never a share, a drive's root, or a path through a junction or link. - On Linux the service runs as
User=hmailserver, and the packaged unit lets it write only under/var/lib/hmailserver, the data directory itself, and/var/log/hmailserver. Every other folder is read-only to it (/homeis not even visible), and anArchiveDirit cannot write stops archiving. Make the folder writable by thehmailserveruser, add it to the unit with a drop-in (sudo systemctl edit hmailserver, then under[Service]aReadWritePaths=line naming the folder) and restart the service. SecureDefaults.md gives this drop-in for a data folder; no document gives it for the archive. - Set
ArchiveDomainsfirst if only some domains are archived, thenArchiveDir. - Send a test message and find its row in the Deck's Archive view.
Before relying on it.
- The backup does not carry it. The backup copies the data directory, and
hm_archiveindexis not carried: back up the archive folder, and the database with its own tool for the index. - Moving it strands the index.
hm_archiveindex.archivepathis matched as an exact string by the sweep, holds and erasure; do not rewrite it in bulk. If the folder moves, move it back or accept that older rows point at the old place. - A mailbox move leaves the archive under the old address, and an address's erasure with the archive included leaves the copies in other people's trees and in
InbounduntilArchiveRetentionDaysages them out. - It is not journaling, which sends a copy elsewhere and keeps nothing here: Journaling and dual delivery.
- SMTP, as documented. No 6.3.4 document says whether mail the server queues itself, such as the webmail's send, or mail a fetch account collects, is archived.
What it does not do
- No message-count quota: storage is the only quota enforced.
- No server-wide retention policy, and no documented way to run the retention sweep on demand on Linux.
- No write-once archive: a hold is a flag an administrator can lift.
- The archive only grows while
ArchiveRetentionDaysis0, and the recover-deleted store is bounded by its window alone: watch the disk they are on.
Where to read more
- Documents at v6.3.4: QuotaPolicy.md, SettingLevels.md, Reports.md, RecoverDeleted.md, Discovery.md, Backup.md, ServiceAccount.md, RelocatingAnInstallation.md, PersonalData.md, Journaling.md, SecureDefaults.md, SettingsApply.md.
- Wiki: Settings Reference (section 9.13), Your First Domain and Mailbox, Compliance and eDiscovery, Backup and Restore, APIs Reference.
- The documentation page: Storage, retention and archive, Queue, quarantine and archive.
- On this forum: Backup and restore, for what a restore resets; Relocating an installation, and moving or renaming a mailbox, for the archive index; the service account on Windows and the Linux unit, for the folders the service may write; The Control Deck.
- The webmail's Storage page (since 6.3.2,
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better ๐
Register Login