Settings: what is not stock, when a save takes effect, and the three levels
-
This topic is about the settings themselves, whichever interface you use: where a setting is stored, which of yours are not what 6.3.4 ships with, when a saved value is in effect, and how the twenty-seven settings a domain or an account may hold its own value of combine with the server's. The one thing to know first: since 6.3.4 the database is the settings store. A
[Settings]line edited by hand inhMailServer.inichanges nothing; at the next start the server uses the stored value, names the key in the error log asHM5804, and, where the service may write the file, puts the line back. Everything below describes 6.3.4 unless it says otherwise; a server on 6.3.3 still reads the file and applies a change at the next start.Two stores, and how a setting is changed
The table
hm_settings. Everything the COMSettingsobject has always carried, such as the anti-spam thresholds and the delivery options. Since 6.3.4 every new setting goes here, and no key is added to[Settings]. 6.3.4 added 193 rows for its features.The
[Settings]keys. 241 keys read by the settings loader, plusUseLanguage, read per call. On 6.3.3 they live in the file, mirrored intohm_inisettings. Since 6.3.4 (schema 6042)hm_inisettingsis the store and the file's section is a copy, which the server keeps current where the service may write the file.Where the service cannot write the file, the copy goes stale. That is a new Windows installation, whose service runs as
NT SERVICE\hMailServer, and a Linux package installation, where/etc/hmailserver/hMailServer.iniis0640 root:hmailserver. There the copy is not refreshed and an edited line is not put back; the database's values are still the ones used. The server reports this once a start in the application log, not as an error, andServiceAccount.mdsays the same of the Linux packages; the wiki's Installing on Linux page namesHM5806at a save andHM5803at every start for them instead. On such a server read a setting from the store, not from the file.The migration is the first start. A key the table has never seen is adopted with the file's value, and there is nothing to run by hand. A line edited after the old server last started, including one edited to prepare the upgrade, is taken for an edit and put back, so make such a change after upgrading. A 6.3.3 server refuses a database at schema 6042 or later with
HM5011; see Upgrading to 6.3.4.What stays in the file.
[Database],[Directories],[Security]and[GUILanguages]are the bootstrap, read before the database is open and never in the store.[LDAP],[SendingLimits]and[SendingLimitsOverrides]stay in the file.PasswordPepperis kept in the file only, never in the database and never in a backup.[SettingsOverride]is the one way to make the file win, for a database that is unreachable or holds a value the server will not start on: a key written there is applied over whatever is stored and named in the error log asHM5807at every start, because no page shows it and no backup carries it. Storing a value for a key an override shadows is accepted and reported asHM5808.Surface Set a [Settings]keyReturn it to the default Control Panel (Windows only) the key's editor, written over COM even on the server itself No. Clearing a box stores an empty value, which a number reads as 0REST PUT /api/v1/settings/ini/{name}with{"value": "..."}DELETE /api/v1/settings/ini/{name}hmctl, over RESThmctl ini set <name> <value>hmctl ini delete <name>PowerShell module Set-HmIniSettingnone COM (Windows only) Settings.SetIniSetting(name, value)Settings.DeleteIniSetting(name)Linux command line, as root hmailserver --set-setting NAME=VALUE, with no listener running. A secret's value is refused on the command line: give the name alone and type the value at the promptnone Control Deck only SmtpTarpitCount,SmtpTarpitDelaySeconds,UseLanguageandRewriteEnvelopeFromWhenForwardingnone The REST ini routes take the administrator password only; an API key of any scope is refused. Since 6.3.4 a setting the environment names, as
HM_SETTING_<key>orHM_PROPERTY_<name>(configuration from the environment), refuses an administrator's change, 409 over REST, until a start without the variable.What this server has changed from stock
Since 6.3.4. One list of every setting whose value is not the one this version ships with, with the shipped value beside it. The example in
ChangedFromStock.md:STORE NAME VALUE DEFAULT ini LogLevel 5 9 ini MaxLogLineLen 2000 500 ini SMTPDMaxTimeout 600 1800 ini OAuth2HmacSecret (set) ini DnsServer 10.0.0.1 (forced from [SettingsOverride]) database smtpnoofretries 6 4 database maxsmtpconnections 200 0 7 of 391 settings are not what this version ships with.Where What to ask Control Deck Changed from stock, in the navigation beside Settings REST GET /api/v1/settings/changedCommand line hmctl config changedPowerShell Get-HmChangedSettingCOM Settings.GetChangedFromDefaultThe REST route and the COM call answer the same document.
storeisini(hm_inisettings) ordatabase(hm_settings).What "default" means. The value the server behaves as though the setting has when nothing has been stored for it, not what a fresh installation's files contain.
hMailServer.iniships with lines the packaging wrote, such asRestApiBindAddress=127.0.0.1, and a line holding the shipped value is not a change; one holding another value is listed.An upgraded installation lists more than a new one.
databasedefaults are what a database created by this version holds. An installation upgraded from an old schema got its values from the upgrade scripts of the time, and where those differ (maxmessagesize,usecache,protocolimap,smtpallowincorrectlineendingsand half a dozen more) the older installation is genuinely different and is listed. A row nothing reads any more (useordb,usespamhaus,tarpitcount,filters,imapport,relaymode) is not reported at all.The marks on an entry.
secret: a setting whose name says its value is a secret is listed by name, with(set)or empty, and never shown. A key file, such asRestApiPrivateKeyFile, is a path and is shown.knownfalse: the server holds a value and ships no default for it, such as a key stored for a script of your own.hmctlprints(none: this server does not read it).overridden:[SettingsOverride]is forcing the value. Such a key is listed even when neither store holds anything for it;hmctlprints(forced from [SettingsOverride]).environmentisvariableorfile, andhmctlprints(set by the environment).profilenames the setting profile whose apply wrote the value, while the setting still holds it.
Which values these are. The value stored, not the value the server settled on where the two differ: a
PasswordHashIterationsoutside the range the server accepts is reported asHM5561and the built-in work factor used; an unusablePreferredHashAlgorithmis reported asHM5528(orHM5607, for Argon2id on a build whose OpenSSL has none).Who may see it. The administrator password, and nothing else. An API key of any scope is refused with a 401, and an account holding an administrative role, an
auditorincluded, with a 403, because the list includes commands the server runs:AutoBanCommandruns as the service account. The feature changes nothing. It does not compare two servers (twohmctl config changed --jsonanswers anddiffdo), and it does not say when or by whom a setting was changed; the audit trail does (GET /api/v1/audit?object_type=setting).When a saved setting takes effect
Since 6.3.4. Until then every
[Settings]key was latched when the service started. Now a save publishes: the store takes the value, the server rebuilds its settings from the rows, and every key whose readers can take a new value is in effect when the save returns, whichever door saved it. Every key carries one of three marks:Mark Keys What it means now211 A save applies it reinitialize28 Bound into something the servers build when they start, so it waits for a reinitialise: Apply now in the Control Panel or the Deck, POST /api/v1/server/reinitialize, orApplication.Reinitializeover COMrestart31 Read once per process: 2 [Settings]keys and the 29 bootstrap keys (20[Database], 5[Directories], 3[Security], 1[GUILanguages])The 28 that wait for a reinitialise.
What is rebuilt Keys The REST listener RestApiBindAddress,RestApiPort,RestApiCertificateFile,RestApiPrivateKeyFileThe metrics listener MetricsServerBindAddress,MetricsServerPort,MetricsServerCertificateFile,MetricsServerPrivateKeyFile,MetricsServerAuthPassword,MetricsServerAuthToken,MetricsServerAuthUsernameThe web-services listener WebServicesBindAddress,WebServicesHttpPort,WebServicesHttpsPort,WebServicesCertificateFile,WebServicesPrivateKeyFileThe ManageSieve listener ManageSieveServerBindAddress,ManageSieveServerPortThe SSL contexts of the SMTP, IMAP, POP3 and ManageSieve listeners and the outbound client TlsCipherSuites13,TlsKeyExchangeGroups,TlsSessionCacheSize,TlsSessionTicketsEnabled,TlsSessionTimeoutSeconds,TlsTicketKeyRotationSecondsACME, the database pool, the fetch queue AcmeEnabled,AcmeCertificateDirectory,DatabaseStatementTimeout,MaxNumberOfExternalFetchThreadsThe 2 that wait for a restart are
ServiceAccountNameandServiceAccountPassword, which are retired: since 6.3.4hMailServer.exe /Registertakes the account from its command line alone, and a stored value is shown as pending until the next start. The bootstrap keys are never in the store, so none is ever pending.Some keys are
nowbecause a subscriber re-latches them.MaxSubmissionsPerIPPerMinuteandMaxOutboundPerDestinationPerMinutestart each limit's one-minute window again, so a saved limit counts from when it was saved. A cache of data is not a setting: a changedDNSServeris used for the next lookup, and an answer already cached stays until its TTL runs out.Pending. A
reinitializeorrestartkey whose stored value is not the value the server is running on is pending. The list is recomputed at every request and never remembered, so a value put back before anything applied it is not pending.Where What REST GET /api/v1/server/settings/pendinganswers[{name, stored, running, applies, secret}], andappliesandpendingcome on every/api/v1/settings/ini/{name}answer. The administrator password's routeCOM Settings.IniSettingApplies(name),Settings.IniSettingAppliesAll,Settings.PendingIniSettingsControl Panel Applies on save, After reinitialize or After a restart under each field kept in the store, and a pending bar with Apply now Control Deck The same words as a badge, and Apply now above its Settings view A name the loader does not read (
UseLanguage, a key a script of your own reads, a misspelling) has no mark: COM'sIniSettingAppliesrefuses it and REST answersapplies: null.Apply now is a reinitialise. Every service stops and starts again in place, which takes every
reinitializekey and not arestartkey. It asks first. A reinitialise ends maintenance mode, andPOST /api/v1/server/reinitializeanswers{"reinitializing": true, "drained": true}when it ended a drain. The Deck's session ends with the REST listener it was using; the Control Panel's COM session survives.What a save does not do. It does not re-read the bootstrap sections or
[SettingsOverride]; a reinitialise or a start re-reads the override section and announces it asHM5807. It does not reconcile the file against the table; that is a start's and a reinitialise's only. And a value stored by another process (another node on the same database, orhmailserver --set-settingwhile the service runs) reaches this server at the next save here, a reinitialise or a restart, because nothing watches the table.hmctlhas no pending verb.On Linux the regression fixture alone proves the marks, with the three COM members answered over REST; the internal tester that swaps settings under load does not run there.
One value, three levels
Since 6.3.4 (schema 6088). Twenty-seven settings may be set for the server, for a domain and for an account, and every place that shows one shows what is in effect and where it came from. For an account: its own value, else its domain's, else the server's. Every setting on the list is exactly one kind:
Kind How many The rule Who sets a level below the server Limit 15 A level below may tighten the level above and never loosen it. A looser value is refused when it is written; a value the level above has since tightened past is capped when it is read Anybody who administers that level: a domain administrator, a key restricted to the domain Gate 4 The deepest level that holds a value wins, either way The server administrator alone; a domain-restricted key is refused with 403 Preference 8 The deepest level that holds a value wins The domain's administrators, and a domain-restricted key The last column is the rule for the levels held in
hm_settingoverrides. A field the domain already had keeps the authority it had, whatever its kind: the domain's maximum message size and the domain's retention are the server administrator's.Kind Settings Limits max_message_size_kb,session_idle_seconds,session_lifetime_seconds,session_one_per_device,session_bind_to_address,quota_grace_percent,quota_send_stop_percent,recall_days,recover_deleted_days,sending_max_messages,sending_max_recipients,reader_fetch_accounts_max,reader_sender_addresses_max,reader_masked_addresses_max,reader_offline_days_maxGates plus_addressing_enabled,openpgp_portal_enabled,zero_access_allowed,directory_user_editablePreferences quarantine_digest,quarantine_digest_hour,external_tag_subject,external_tag_header,impersonation_action,quota_warning_percent,country_policy,message_retention_daysA server setting not on the list is the server's alone: its name is refused on the domain and account routes (400,
unknown field) and by COM'sSettingOverride. Of the[Settings]keys onlyQuotaWarningPercenthas levels.Where each level is held. A field the domain or the account already had, such as the domain's
MaxMessageSizeorMessageRetentionDays, stays where it was, with the meaning it always had; its 0 or -1 is the level holding nothing. The rest are rows ofhm_settingoverrides, where no row means "take the level above". An owner's rows are cached for sixty seconds; every write through the interfaces drops the cache at once, and so doesPOST /api/v1/settings/cache/clearor COMCache.Clear. A row put in by hand that the interfaces would refuse is treated as holding nothing and reported asHM7311. Nothing changes for a domain or an account that holds no value of its own.Where What REST GET /api/v1/settings/levelslists the twenty-seven.GET /api/v1/domains/{domain}andGET /api/v1/accounts/{address}answer<name>_effectiveand<name>_source, and<name>where the level is held in the overlay. For a level held in the overlay aPUTtakes a value of the setting's own JSON type, andnullmakes it inherit; for a level held in a field of its ownnullleaves it unchanged, and the field's own 0 or -1 is "take the level above"COM (Windows only) Domain.SettingOverride(name)andAccount.SettingOverride(name), an empty string for "take the level above", written at once and not bySave;EffectiveSetting(name)andEffectiveSettingSource(name)hmctlhmctl domain set <domain> <name> <value\|inherit>andhmctl account set <address> <name> <value\|inherit>Control Panel (Windows only) A Levels tab on the domain and account dialogs, with "In effect: ..., from the ..." beside each setting and Save levels now Control Deck The same card in its domain and account editors A saved level applies at once, at every level and from every door, because the resolver is asked when the value is used (at
MAIL FROM, when a session is checked) and never latched.Deleting, backing up and moving. Deleting an account or a domain deletes its rows; a delete that cannot remove them is reported as
HM7310for a domain andHM6109for an account. The XML backup carries the rows, and on restore a row the build refuses is left out and reported asHM7312. A mailbox moved to another domain keeps its own values.What is thinner than it sounds.
- Attachment blocking, web push, passkeys and account recovery have no levels.
- The domain's session seconds and switches and its quota grace and send-stop shares could always be set looser than the server's and still can; the ceiling binds the account below them.
- The maximum message size is resolved at
MAIL FROMand at IMAPAPPEND; the EHLOSIZEadvertisement, the webmail's own send and the send API stay the server's. - The session policies are the browser sessions' (the webmail, the portal, the Deck); IMAP, POP3 and SMTP sessions have none.
country_policycannot be set to empty over COM, where an empty string means "take the level above"; REST's""does it.- Twelve of the twenty-seven are proved by what the account and its domain answer rather than by driving the behaviour per account, and the levels' own regression fixture is Windows-only.
When a setting appears to do nothing
- Is it pending? A
reinitializekey waits for Apply now and arestartkey for a service restart. - Was it typed into
hMailServer.ini? The stored value wins andHM5804names the key. Store it instead. - Is the key spelled exactly as the code reads it, and is a boolean literally
1? An unknown key is the default, and only1is true:2,yesandtrueall read as false. - Does it need a companion?
SRSEnabledneedsSRSSecret, ACME needsAcmeDomains, autoconfig needsWebServicesHttpPortorWebServicesHttpsPort, and MTA-STS hosting needs the HTTPS one. - Does the error log show
HM5807orHM5808? A[SettingsOverride]section is forcing a value.
Where to read more
- The tour: https://gitlab.com/hmailserver/hmailserver/-/wikis/Settings-Overview. Every key with its default, validation and mark: https://gitlab.com/hmailserver/hmailserver/-/wikis/Settings-Reference. Where the two disagree, the reference is generated from the code and is right.
- The three documents behind this topic: https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/ChangedFromStock.md, https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SettingsApply.md and https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SettingLevels.md
- The public documentation's settings chapter: https://www.progressiverobot.com/hmailserver-documentation/#21-settings-reference-hmailserverini
- On this forum: the Control Panel on Windows,
hmctland the PowerShell module, thehmailservercommand line, the Control Deck, Upgrading to 6.3.4 and hMailServer on Linux.
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