Skip to content
hMailServer 6.3.8 is the current release, signed 2 November 2026. Windows and Linux, and an in-place upgrade from 5.3 or later, but for the original hMailServer's 5.7.Download 6.3.8 Documentation FAQ
  • 0 Votes
    1 Posts
    124 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) changes three things this guide relies on. A Control Panel signed in to a server on another computer no longer reads or writes its own computer's hMailServer.ini for the [LDAP] values, which it cannot read from the server, where it showed that file or the defaults as the server's; the sidebar is regrouped, and Ctrl+K takes every old page title to its page. With SMTP logging on, 6.3.6 and every earlier version that offered them wrote the bearer token of AUTH XOAUTH2 and AUTH OAUTHBEARER and the lines of SCRAM-SHA-256, OAUTHBEARER and GSSAPI into the SMTP log in the clear; 6.3.7 hides every line of a SASL exchange but the user name of AUTH LOGIN and the authentication identity of AUTH PLAIN. An account given the serveradmin role with a list of domains is, over COM as over REST, confined to those domains and no longer the server's administrator, so a script that runs the directory synchronisation's preview and apply as such an account needs the role given with no list. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026) signs a name in to an account only when it is the account's stored address, compared in lower case after a domain alias and the default domain, for the name an OAuth2 bearer token carries as for a password (work item 104), so a name that differs from the stored address in more than the case of the letters A to Z, or has white space at either end, may no longer sign in. On Windows an OAuth2PublicKeyFile whose path holds characters outside ASCII may be refused with HM7536 (one outside the code page, which worked up to 6.3.7, is refused), and then the key verifies no token: give the file, and the folders above it, an ASCII name before upgrading. See the 6.3.8 announcement. This topic covers three ways an organisation's directory or identity provider vouches for somebody on hMailServer 6.3.4's mail protocols: checking a password against Active Directory or another LDAP directory, creating mailboxes from that directory, and accepting OAuth2 bearer tokens. Know this first: 6.3.4 keeps settings in the database, but the [LDAP] section stays in hMailServer.ini on each server, with no REST route and no environment name; the server re-reads it within two seconds of a change, with no restart. The OAuth2 keys are ordinary [Settings] keys, stored like any other. Three mechanisms, three questions Mechanism The question it answers Control Panel page (Windows) LDAP directory authentication Is this the password of the directory user the account is linked to? Access & abuse protection → Directory authentication (LDAP) Directory synchronisation Which mailboxes should exist, according to the directory? Access & abuse protection → Directory synchronisation OAuth2 bearer tokens Did the identity provider sign this token, and which mailbox does it name? Access & abuse protection → Authentication All three are off by default, and an upgrade switches none of them on: the [LDAP] section is absent until you add it, and OAuth2Enabled defaults to 0. Where the [LDAP] section lives Windows. The Control Panel's page writes the hMailServer.INI of its own machine. Connected to another machine, its Save is disabled, although "the connection test still works with the values typed here". Work on the server, over Remote Desktop. Linux. No Control Panel and no COM. The file is /etc/hmailserver/hMailServer.ini, 0640 root:hmailserver: sudoedit /etc/hmailserver/hMailServer.ini. Not REST or hmctl. The REST ini routes and hmctl ini set handle [Settings] keys only. Per server. On a warm standby each node has its own [LDAP]; keep the two alike by hand. ServicePassword is a line of that file. It is not among the [Settings] secrets 6.3.4 seals under the stored-secrets key; the Control Panel's field for it is write-only. The sign-in keys Key Default What it does Enabled 0 The master switch Server empty The directory host; required Port 0 0 means 636 for LDAPS, 389 otherwise Security 2 2 LDAPS, 1 StartTLS, 0 plain; anything else is LDAPS VerifyCertificate 1 Check the directory's certificate AllowUnprotectedPassword 0 Permit a simple bind over a plain connection BindMethod 0 0 simple; 1 Negotiate (Kerberos or NTLM through Windows SSPI) SearchBase empty Required unless UserDnTemplate is set or the bind is Negotiate UserSearchFilter (&(objectCategory=person)(objectClass=user)(sAMAccountName=%u)) How the user's entry is found UserDnTemplate empty Bind directly, without searching ServiceUsername, ServiceDomain, ServicePassword empty What the search binds with TimeoutSeconds 10 Bounds every directory operation; 1 to 90 FallbackToWindowsLogon 0 Also try Windows LogonUser; Windows only LDAPS with VerifyCertificate=1 is the default and the recommended configuration, proven end to end against a Windows Server 2025 domain controller. Server must be the name in the directory's certificate: the same setup pointed at the controller's IP address, with the right password, is refused, and HM5920 reports a failure "unrelated to the credentials supplied". On Windows, put the issuing CA in LocalMachine\Root; when this was proven the service ran as LocalSystem, and a CurrentUser\Root import served it nothing. The bind needs no extra privilege under NT SERVICE\hMailServer, which a new 6.3.4 installation runs as. On Linux the certificate must chain to the system trust store. StartTLS (Security=1) connects on 389 and upgrades before anything is sent. Plain LDAP is labelled Unprotected LDAP - cleartext (lab networks only): there a simple bind is refused (HM5921) rather than sent, unless AllowUnprotectedPassword is 1. Simple or Negotiate. A simple bind sends the password to the directory, so it belongs on LDAPS or StartTLS. Negotiate, Windows only, never sends it; it worked on 389 against a controller that had no LDAPS certificate yet, and suits a mail server not joined to the domain. Search or template. A search binds with the service credentials, finds the user under SearchBase with UserSearchFilter, then binds as the user. It asks for two entries to see ambiguity: more than one match is a configuration fault and authenticates nobody. UserDnTemplate skips the search, so no service credential need be stored at all; with a simple bind, that is the configuration the feature was proven with. Linking an account to the directory The directory is asked only about linked accounts; others keep their own password. The webmail's sign-in shares the IMAP and POP3 logon, so it takes the directory password too. Control Panel: the account dialog's Windows directory tab, with the domain (ADDomain) and user name (ADUsername); Browse Active Directory searches the forest to fill them. Since 6.3.4 the tab has that name; it was called Directory, and the new Directory entry tab is the organisation's address book, unrelated to Active Directory. REST: PUT /api/v1/accounts/{address} with ad_enabled, ad_domain and ad_username. COM (Windows): IsAD, ADDomain and ADUsername. What a link changes. The account's stored password is no fallback: in the proof run, a linked account's local password was refused. Linked accounts bypass local hashing, so they are exempt from the minimum-hash policy and from password expiry, and cannot sign in with SCRAM-SHA-256; their clients use PLAIN or LOGIN over TLS. App passwords work for them: the directory holds the password, but an app password is local, which is what makes a second factor possible for a directory account at all. The person cannot change the password in the webmail (POST /api/v1/me/password answers 409), and Forgotten your password? cannot reset it, because this server does not hold it. Without LDAP, on Windows, a linked account is checked by LogonUser, which needs the mail server's host joined to the domain. On a host that is not joined, Windows answers every domain name, real or misspelt, as a wrong password, so the account can never sign in; HM5911 says so, naming the domain and the computer. An empty domain, . or the computer's own name means a local Windows account. Never leave the domain empty by accident: with [LDAP] Enabled off, an account linked with an empty domain and the user name administrator would accept the server's local Administrator password. FallbackToWindowsLogon never applies to a wrong password: a directory's rejection deliberately does not fall through to LogonUser, because that would double every failed attempt and trip a lockout policy on a single wrong password. Leave it off on a host that is not domain-joined. Setting it up on Windows For LDAPS or StartTLS, put the directory's issuing CA in LocalMachine\Root on the mail server. On the mail server, open Directory authentication (LDAP). Switch directory authentication on (Enabled); until then a linked account is checked by Windows LogonUser, not with these settings. Fill in the server, the security, the bind, and either the search or UserDnTemplate; the first card asks Is this configuration complete? Test the connection with a directory user name, its AD domain and its password. It tries the values typed on the page. Save. The server re-reads [LDAP] within two seconds. Link one account and sign in with the right password and a wrong one. Over POP3 the proof run got +OK Mailbox locked and ready and -ERR, and the log showed the bind and the rejection separately. Link the others by hand, or with directory synchronisation. Setting it up on Linux The only directory path is an LDAP simple bind over LDAPS or StartTLS, proven against OpenLDAP's slapd. Make sure the directory's certificate chains to the system trust store, and use the name it carries. Add the section with sudoedit /etc/hmailserver/hMailServer.ini, filling in the angle brackets. Without a UserSearchFilter line the search uses Active Directory's filter, (&(objectCategory=person)(objectClass=user)(sAMAccountName=%u)), which finds nobody in another directory such as OpenLDAP; there, write a filter that matches its user entries, with %u for the name: [LDAP] Enabled=1 Server=<the host name the directory's certificate carries> Security=2 VerifyCertificate=1 BindMethod=0 SearchBase=<the DN the users are under> UserSearchFilter=<that filter, unless the directory is Active Directory> ServiceUsername=<the search account> ServicePassword=<its password> Two seconds later the server has it. Link an account over REST (ad_enabled, ad_domain, ad_username) and sign in with the right password and a wrong one. Linux has no Negotiate (BindMethod=1 is refused as a directory failure, not a wrong password: HM6420, reported once), no LogonUser (a linked account while [LDAP] Enabled is off is refused with HM6421, which names the settings to set; FallbackToWindowsLogon refuses with HM6404), and no GSSAPI bind. When the directory cannot answer So that an outage does not read as users mistyping, infrastructure failures are reported apart from credential rejections, throttled per error and endpoint, and TimeoutSeconds bounds the wait. Code Meaning HM5920 The directory could not be used (a certificate not matching Server, say). Reported at High: unrelated to the credentials, and every account on that directory is affected HM5921 A simple bind would have sent the password unprotected, so the logon was refused first HM5911 Windows LogonUser: the host is not joined to the domain; at most once a minute per problem Directory synchronisation: preview, then apply Synchronisation reads the directory, works out which mailboxes should exist, and only when asked creates and updates them; it was verified end to end against a Windows Server 2025 domain controller. The planner writes nothing and the applier decides nothing, so a preview cannot promise what the apply would not do. Per-domain opt-in. A domain takes part only if its Active Directory domain name is set (ADDomainName in the domain dialog, ad_domain_name over REST), so a search base one level too high cannot provision into unrelated hosted domains. Nothing is ever deleted, account or message. The most it does is clear Active, only when asked, and never on a truncated or empty enumeration or for a domain in which nothing was seen. No password. A made account is marked IsAD and signs in through the directory from the start. No existing account claimed. An account that is not linked, or is linked to another AD domain, is reported, not changed. Paged. Active Directory answers a search beyond MaxPageSize (1000) with the first page and a success status, so the enumeration pages; SyncMaxUsers is the ceiling. [LDAP] key Default SyncFilter (&(objectClass=user)(objectCategory=person)(mail=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) SyncMailAttribute mail; proxyAddresses works, preferring the capitalised SMTP: primary SyncUsernameAttribute, SyncDisplayNameAttribute sAMAccountName, displayName SyncMaxUsers 5000; at most 100000 SyncScheduleMinutes 0, off; 15 at least, 10080 (seven days) at most On Windows: Get authentication working first. Synchronisation binds as the service account, honouring BindMethod, so Negotiate works where there is no LDAPS certificate. Set the Active Directory domain name on each mail domain that takes part. Open Directory synchronisation, check the selection keys, choose the domain and whether absent accounts are marked inactive, and run Preview. It changes nothing. Read the report, including the existing accounts it reports and leaves alone. Apply. The button stays disabled until a preview of the same options has run. Behind the page are Settings.PreviewDirectorySync(DomainName, DisableMissing) and Settings.ApplyDirectorySync, for a server administrator and callable from a script. From a Control Panel on another machine the six selection boxes are read-only and, up to 6.3.6, show their defaults; since 6.3.7 the Control Panel no longer reads its own computer's file for the [LDAP] values, which it cannot read from the server, so it no longer shows them as the server's. Preview and Apply still run inside the server. The unattended schedule (SyncScheduleMinutes) runs at start and then every so many minutes. It creates and updates but never disables: unattended is where nobody reads the report that would show a mailbox about to be taken away. The schedule is one of the tasks the server registers as it starts, and only if SyncScheduleMinutes is set then, so restart the service once after first setting it. On Linux, with no COM, there is no preview or apply, and whether the schedule runs there is not documented: treat it as untested. OAuth2 bearer tokens on IMAP, POP3 and SMTP With OAuth2Enabled=1, SMTP, IMAP and POP3 offer XOAUTH2 and OAUTHBEARER (RFC 7628), by default only over TLS (OAuth2RequireTLS=1). The server verifies the token's signature itself, takes the login name from the claim OAuth2UsernameClaim names (email), and signs in to that mailbox; a user= the client asserts must match. The mailbox must already exist: a token never makes one. Key Default What it does OAuth2JwksUrl empty The provider's JWK Set; the token's kid picks the key. https, or plain http to loopback only OAuth2JwksCacheSeconds 3600 How long the set is kept OAuth2PublicKeyFile empty A PEM RSA or EC public key; the fallback OAuth2HmacSecret empty The HS256 key OAuth2AllowedAlgorithms RS256 HS256, RS256 and ES256 recognised; none never OAuth2Issuer, OAuth2Audience empty Expected iss and aud; empty turns the check off OAuth2IntrospectionUrl empty RFC 7662 endpoint asked whether a verified token is still active OAuth2IntrospectionClientId, OAuth2IntrospectionClientSecret empty Who this server introspects as, over HTTP Basic OAuth2IntrospectionCacheSeconds 300 Verdict reuse, never past the token's exp OAuth2IntrospectionFailOpen 0 1 accepts a token the endpoint cannot judge, logging each An unknown kid, which is what a rotation looks like, fetches the set again at once, at most once a minute; a failed fetch keeps the keys held. HttpProxy, when set, carries these fetches. Where to set them. Each applies when saved: on the Control Panel's Authentication page, with PUT /api/v1/settings/ini/{name} and the administrator password, with hmctl ini set, or with COM Settings.SetIniSetting. Not in hMailServer.ini: since 6.3.4 the database holds them, and a line edited in the file is not used; Settings: when a save takes effect explains the store. Choose the key source: OAuth2JwksUrl, so a rotation needs no copied file; or OAuth2PublicKeyFile; or OAuth2HmacSecret with HS256 allowed. Set OAuth2Issuer and OAuth2Audience to what the provider writes into its tokens. Left empty, neither is checked: any token the provider's keys signed is accepted, whatever client it was issued to. Optionally set introspection, so a revoked token stops working before it expires. Only then set OAuth2Enabled to 1. On Windows, read the OAuth2 / XOAUTH2 item of the Control Panel's External setup list. Why that order. Switched on without usable key material, the mechanisms are still advertised, every token fails, and failed bearer sign-ins feed the auto-ban, so a correct client can have its address banned. On Linux before the REST listener is up, hmailserver --set-setting stores a key; a secret is given by name alone and typed at a prompt. A value stored this way reaches the running server at its next save, reinitialise or restart. Set the issuer and audience too, as step 2 says, putting your provider's values in place of these examples: sudo hmailserver --set-setting OAuth2JwksUrl=https://idp.example.com/keys sudo hmailserver --set-setting OAuth2Issuer=https://idp.example.com sudo hmailserver --set-setting OAuth2Audience=hmailserver sudo hmailserver --set-setting OAuth2Enabled=1 sudo systemctl restart hmailserver Since 6.3.4: a bearer token meets the domain's and the account's country policy, as a password does (a stolen token used to sign in from a refused country); an SMTP session signed in with a token can send more than one message (the second used to be refused with 550 "Login credentials no longer valid"); and OAuth2HmacSecret and OAuth2IntrospectionClientSecret are sealed at rest once the installation has a stored-secrets key, which an upgrade does not make until an administrator runs --create-stored-secrets-key. Tested how. The regression fixtures play the identity provider on the loopback, to make it misbehave: RS256 and ES256, the JWK Set and its rotation, introspection and fail-open. A real provider's tokens are not yet part of them. This is inbound only. The OutboundOAuth2 keys and FetchOAuth2Hosts are the server's own token for relaying through and collecting from Microsoft 365; Routes, relays and smart hosts covers relaying with it. Where these end: SCIM, single sign-on and Kerberos The LDAP backend authenticates; SCIM provisions. Synchronisation reads the directory; SCIM is the other direction, Entra ID or Okta calling /scim/v2 under an API key whose role holds provision, and it removes accounts, which synchronisation never does. Single sign-on, OpenID Connect or SAML 2.0, opens the webmail and the Control Deck only, ending in POST /api/v1/session; the protocols' bearer tokens are a separate, older mechanism with the OAuth2 settings above, and single sign-on does not reach mail clients. On Windows, SASL GSSAPI (GssapiEnabled) lets a mail client sign in with a Kerberos ticket, mapped to the account linked to that directory user. SCIM provisioning and single sign-on sets those up; Signing in and Connecting a mail client show the person's side. What it does not do No Negotiate, Windows logon or GSSAPI bind on Linux. hMailServer on Linux lists the rest. No LDAP server here, and the webmail's organisation directory is typed in, not imported from Active Directory. Where to read more Wiki: Settings Reference sections 9.2 and 11, Capabilities and Configuration, Control Panel Reference, Installing on Linux, Security Hardening, Sign-in and Identity, Architecture Documents: SettingsApply.md, ServiceAccount.md, Scim.md, PasskeysAndSingleSignOn.md, TestLab.md The Roadmap rows on LDAP, which record how each part was proven On this forum: the stored-secrets key, auto-ban and the warm standby The public documentation's Creating accounts from Active Directory and Modern authentication Report a security flaw in any of this by SECURITY.md's routes: a confidential GitLab issue, or email to contact-project+hmailserver-hmailserver-86730559-issue-@incoming.gitlab.com, which GitLab files as one.
  • 0 Votes
    1 Posts
    122 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) is a security release that bears on the send-as and sign-in sections here. An authenticated submission is now DKIM-signed as another domain hosted here only when its account may send as the address its From names (its own address, an alias pointing at it, a mailbox that granted it the post right, an address it proved, or a masked address of its own, the addresses the send-as table below lists); otherwise the mail is still accepted and sent, unsigned as that domain, so give such an account the alias or the grant before upgrading. A domain's or an account's rule replies only from an address its owner may send as. SMTP, POP3 and ManageSieve refuse a SASL PLAIN sign-in that asks to act as another account; with SRS on, mail to an SRS address this server handed out is held to the relay rules unless it is a bounce; the IMAP and POP3 listeners can take the client's address from a PROXY protocol header as the SMTP listener does, each from a list of peers of its own, both off by default; and the Control Panel's IP ranges page, which could show no list of ranges at all, is fixed. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026) is a security release that bears on the auto-ban, the lockout and the IP ranges here. The auto-ban saves the IP range it adds under a name of its own, the user name cut so that the name and its suffix fit in the 100 characters a range's name holds, so that it bans the address: up to 6.3.7 a second or later ban for a long user name could be refused (HM6099) and the address given a whole new set of attempts, and now an address's counted failures are cleared only once its range is saved. A sign-in's name is matched to its account as the per-name lockout counts it, so a mail client that signs in with another spelling of the account's address than the stored one, in more than the case of the letters A to Z, or with white space at either end, may no longer sign in, and each such try is counted as a failure: correct the name in the client. With the web services listener on, an address whose IP range allows none of SMTP, POP3 and IMAP, an auto-ban's or one of your own, is now refused there too, before the TLS handshake, loopback and the addresses in WebServicesTrustedProxies apart; such a range of your own closes to its addresses ACME's http-01 validation when this listener answers it, MTA-STS, CalDAV, CardDAV, Autodiscover, autoconfiguration and the Web Key Directory, so before upgrading check that the certificate authority, the sending MTAs and these services' clients do not come from one. See the 6.3.8 announcement. This topic covers who may use this server and how hard it is to abuse it. Know this first: only the IP ranges and auto-ban work out of the box; every other brake here is off until you set it. Until you do, nothing else stops a botnet spending one guess per address, or a stolen password sending thousands of messages. The secure defaults of a new installation, TLS for sign-in and compromised-account detection are in Hardening a public mail server. Where each one is set Since 6.3.4 the database is the settings store, and for a key it holds, a [Settings] line edited in hMailServer.ini changes nothing; on 6.3.3 these keys were lines of the file, applied at the next start. The store, and when a save takes effect, are in the settings topic. What Kept in Set with Takes effect IP ranges the database Control Panel Access & abuse protection → IP ranges; the Control Deck's IP ranges view; /api/v1/ipranges; hmctl iprange; COM Settings.SecurityRanges at once Auto-ban's four settings the database Control Panel Access & abuse protection → Auto-ban; the Deck's settings; PUT /api/v1/settings; COM at once Lockout, tarpits, rate limit, send-as check, hashing, policy the settings store, under their [Settings] names Control Panel; PUT /api/v1/settings/ini/{name}; hmctl ini set <name> <value>; COM Settings.SetIniSetting; on Linux hmailserver --set-setting NAME=VALUE when saved [SendingLimits], [SendingLimitsOverrides], PasswordPepper hMailServer.ini only the file, by hand or through the Control Panel (below) sending limits within seconds; the pepper after a restart The Control Panel and COM are Windows-only. Of these [Settings] keys the Deck edits only SmtpTarpitCount and SmtpTarpitDelaySeconds. A value set with hmailserver --set-setting while the service runs waits for the next save, reinitialise or restart. IP ranges: priority and the relay grid When a client connects, every range containing its address is found and the highest priority wins. The shipped ranges are Internet (priority 10, 0.0.0.0–255.255.255.255) and My computer (priority 30, 127.0.0.1); a range added on the Control Panel's page starts at 15, so a narrow range sits in front of Internet without editing it. At every RCPT TO two decisions are made, in order: may this combination be delivered at all (if not, 550 Delivery is not allowed to this address.), and must the client authenticate first (if so, 530 SMTP authentication is required.). "Local" and "remote" describe the addresses, not the client: an address is local when its domain is a hosted active domain or a route says so. Combination REST fields: allowed / auth required Internet My computer Local → local deliver_local_to_local / require_auth_local_to_local allowed, auth required allowed, no auth Local → remote deliver_local_to_remote / require_auth_local_to_remote allowed, auth required allowed, no auth Remote → local deliver_remote_to_local / require_auth_remote_to_local allowed, no auth allowed, no auth Remote → remote (relay) deliver_remote_to_remote / require_auth_remote_to_remote allowed, auth required allowed, auth required Anti-spam, anti-virus spam_protection, virus_protection on on Require TLS for auth require_tls_for_auth on in a new 6.3.4 installation; otherwise as the server had it off Remote → remote is the open-relay box. Both shipped ranges allow it with authentication required, even from 127.0.0.1, so a client that has not signed in gets 530; a range that does not allow it at all gets 550. The Control Panel's Server status page raises a Critical warning for any range that allows it without authentication. Remote → local is inbound mail and must need no authentication. Local → local needs it on Internet so that nobody outside can forge mail from one of your addresses to another. The protection switches reach further than their names. Clearing Enable anti-spam turns off every spam test, greylisting and the recipient tarpit for the range; clearing Enable anti-virus means its mail is never flagged for scanning. Since 6.3.4 SPF gives loopback no pass, so a content filter that re-injects mail should authenticate or use a range with anti-spam off. Require TLS for auth belongs to the range, not the port. With it set, AUTH is not advertised on a cleartext connection from that range, on SMTP, POP3, IMAP and ManageSieve. A device that cannot sign in gets a range of its own above Internet. For a scanner at 192.0.2.50 that sends from your domains to your own mailboxes only: hmctl iprange create --set name=scanner --set lower=192.0.2.50 --set upper=192.0.2.50 \ --set priority=20 --set allow_smtp=true --set allow_imap=false --set allow_pop3=false \ --set deliver_local_to_local=true --set require_auth_local_to_local=false \ --set deliver_local_to_remote=false --set deliver_remote_to_local=false \ --set deliver_remote_to_remote=false --set spam_protection=true --set virus_protection=true hmctl iprange update <id> and PUT /api/v1/ipranges/{id} (since 6.3.3) change any subset of the fields. The routes refuse a domain-restricted API key; a role needs manage_settings. The Control Panel's Restore defaults (SecurityRanges.SetDefault()) discards every range, your own and the auto-ban ones, and writes back the two shipped ones as the create scripts make them, without Require TLS for auth. Auto-ban, and why its ranges sit at priority 100 Auto-ban counts failed logons per connecting address; SMTP AUTH, POP3, IMAP, ManageSieve, the REST API and the web services listener's CardDAV, CalDAV and Autodiscover sign-ins feed one counter, but since 6.3.8 neither REST, for a failure from loopback (all of 127.0.0.0/8, and ::1), nor the web services listener, for one from loopback or an address in WebServicesTrustedProxies, counts it towards a ban of the address: an account's failed sign-in from there is counted against the name alone. Up to 6.3.7 an account's failed sign-in at REST from loopback was counted towards a ban of 127.0.0.1, which could then be refused at the SMTP, POP3, IMAP and ManageSieve listeners; on 6.3.2 to 6.3.7 AutoBanNeverBan with 127.0.0.1, ::1 avoids it. Behind a reverse proxy on the same machine (the Linux package binds REST to 127.0.0.1), the webmail's failed sign-ins are never auto-banned; account lockout, below, is what limits them there, and it is off until you set it. At the limit auto-ban clears that address's counted failures, creates an expiring range named Auto-ban: <user> at priority 100, and disconnects; SMTP says 535 Authentication failed. Too many invalid logon attempts. Priority 100, above both shipped ranges, is what makes a ban effective; AutoBanNeverBan, below, exempts an address. Setting (COM name) Default Trap AutoBanOnLogonFailure on — MaxInvalidLogonAttempts 3 0 disables auto-ban entirely, whatever the switch says MaxInvalidLogonAttemptsWithin 30 minutes Not a sliding window: how long a failure record survives, deleted by a pass every minute that runs only while auto-ban is on AutoBanMinutes 60 0 disconnects the client but creates no range, so nothing is banned Their REST keys include auto_ban_on_logon_failure and max_invalid_logon_attempts. The office profile (since 6.3.4) raises the limit to 5. AutoBanNeverBan (since 6.3.2): addresses and CIDR blocks whose failures are never counted; the per-connection disconnect still applies, and a bad entry is reported once as HM6524. Server status warns "Localhost is currently banned in the IP ranges." when a ban covers 127.0.0.1. Control Panel sign-in over COM is outside auto-ban and lockout, so guessing an administrator's mailbox name cannot lock them out of the tool. Spam traps and the multi-recipient null-sender check ban through the same ranges (Auto-ban: spam trap <address>, Auto-ban: multi-recipient null sender <address> see Allow and block lists and the anti-spam stack. Firewall bans (AutoBanFirewall, AutoBanCommand, fail2ban) are in Reading the logs. Releasing a banned address. Clear logon-failure list (POST /api/v1/settings/logon-failures/clear, COM Settings.ClearLogonFailureList()) clears counted failures only, for every address at once; a ban stays until its range expires. To release one now: Have the person correct the password in their client first: the counted failures were cleared when the ban was made, so a client still retrying the old one reaches the limit again as soon as the range is gone. Find the range: the IP ranges page, the Deck's IP ranges view, hmctl iprange list or GET /api/v1/ipranges. Its name begins Auto-ban: and its priority is 100. Delete it: on the page, hmctl iprange delete <id>, or DELETE /api/v1/ipranges/<id>. With AutoBanFirewall on, the firewall is reconciled on every range deletion, so its rule goes too. Five error-log codes mean the control has quietly stopped working: Code Meaning HM6114 A failed logon could not be recorded, so no ban will trigger while this persists HM6099 The auto-ban range could not be saved: the address has not been blocked HM6113 Spent failures could not be cleared, so the address may be banned again as soon as its ban expires HM6112 Expired IP ranges could not be removed, so an expired ban keeps blocking HM6115 Expired failures could not be cleared, so occasional failures may add up to a ban Account lockout, by name A distributed attack never crosses any one address's threshold. Lockout counts the name being guessed at, across SMTP AUTH, POP3, IMAP, ManageSieve, REST and the webmail's sign-in. It is off until set; the office profile sets 10. AccountLockoutThreshold=10 ; failed logons per username before a lockout. 0 = off AccountLockoutWindowMinutes=30 ; the window they must fall inside AccountLockoutMinutes=30 ; how long the lock lasts It counts names, not accounts, so a nonexistent name locks as a real one would, and reveals nothing. A locked name is refused before the password is checked, with the ordinary invalid-credentials reply; only its timing differs, deliberately. A lockout refusal is not charged to the connecting address, so an owner retrying from an office NAT does not get everyone behind it auto-banned. Passkeys and single sign-on are not counted, being no guesses. To lift one early: POST /api/v1/accounts/{address}/unlock, which a help desk scoped to the account's domain may call, COM Application.UnlockAccount, or Unlock on the Deck's Accounts row. A password reset clears it too. Tarpits and the submission rate limit All 0, off, until set; these values are a starting point. LogonTarpitSeconds=2 ; per failure on this connection, capped at 30 s. 0 = off SmtpTarpitCount=10 ; recipients an unauthenticated session may name before... SmtpTarpitDelaySeconds=5 ; ...each further RCPT TO waits this long, capped at 30 s MaxSubmissionsPerIPPerMinute=30 ; MAIL FROM commands per source IP per minute. 0 = off The logon tarpit (Auto-ban page) makes a failed logon's refusal wait LogonTarpitSeconds times the failures so far on that connection, on SMTP, POP3 and IMAP. A correct password never waits. The recipient tarpit (Anti-spam settings page; COM AntiSpam.TarpitCount and AntiSpam.TarpitDelay; REST tarpit_count and tarpit_delay on /api/v1/settings/antispam) spares authenticated sessions and ranges with anti-spam off. MaxSubmissionsPerIPPerMinute counts every MAIL FROM, authenticated or not, and refuses the excess with 421 Too many messages from your IP address, which contains a compromised account. The office profile sets 60; gateway keeps 0, since all inbound mail comes from the gateway's few addresses. Since 6.3.4 a save restarts its one-minute window. Behind a load balancer, give the SMTP listener SMTPProxyProtocolEnabled with SMTPProxyProtocolTrustedIPs (or XCLIENT), or auto-ban, the rate limit and the ranges all reason about the proxy's address: see Behind a gateway or reverse proxy. Per-account sending limits The brake on a compromised account, counted against the authenticated user name (never MAIL FROM) over a rolling period. The server level stays in the file: [SendingLimits] MaxMessagesPerAccountPerPeriod=500 MaxRecipientsPerAccountPerPeriod=2000 PeriodHours=24 ; clamped to 1-168 StateSaveIntervalSeconds=10 ; clamped to 1-3600 [SendingLimitsOverrides] [email protected]=5000:50000 [email protected]=0:0 Both limits default to 0, no limit; recipients are the stricter measure. An override replaces the global pair for that address, 0:0 exempts it, and an optional third field sets its period in hours; a malformed line is ignored with a log entry and the global limit applies. On Windows edit C:\Program Files\hMailServer\Bin\hMailServer.INI with an elevated editor, or use the Control Panel's Maintenance → Server limits & expert settings on the server itself; on Linux, sudoedit /etc/hmailserver/hMailServer.ini. They are not in the settings store, so no environment variable or setting profile writes them. What the sender sees: 452 4.7.0 Sending limit for this account has been reached. Please try again later. at MAIL FROM, or 452 4.5.3 Recipient sending limit for this account has been reached. Please try again later. at RCPT TO. The session stays open, the refusal spends no budget, and the application log, not the error log, says SendingLimit refused submission. Counters survive a restart in hmailserver_sendinglimits.dat in the data directory. It fails open: an unreadable file, a limiter exception or a full table of tracked accounts (error 5813) lets the message through. Since 6.3.4 there are three levels. A domain and an account may hold sending_max_messages and sending_max_recipients, which tighten the level above and never loosen it; an address's override line is its server level. Set them on the Levels tab of the domain and account dialogs, in the Deck's editors, with PUT /api/v1/accounts/{address}, or hmctl account set <address> sending_max_messages 100 (inherit returns to the level above); they apply at once. Also since 6.3.4 the webmail's send and the send API consume the same quota, answering 429; a scheduled draft is not counted when it goes. Who may send as whom SmtpAuthenticatedSenderCheck (Control Panel Connections & protocols → Protocols, SMTP tab) came in 6.2.25 and is off by default, since an installation may depend on what off allows: any account sending as anyone. The office and gateway profiles set it to 1. Turned on, it applies to every authenticated session, whose MAIL FROM must then be: Kind Given by The account's own address always An alias resolving to it, up to five hops the administrator A mailbox whose owner granted the post (p) right on their INBOX that owner, with any IMAP client's SETACL An address elsewhere proved by a code mailed to it (since 6.3.4) the person, in the webmail's Settings, Other accounts, Send mail as A masked address the account made, while it is on (since 6.3.4) the person, in the webmail's Settings, Masked addresses Anything else is refused 550 5.7.1 before the message is accepted. The webmail's From picker lists exactly these, so what it offers is what the server takes. The null sender is always allowed; unauthenticated sessions are unaffected. The post right counts only while IMAP ACL enforcement is on (enableimapacl, on by default). Before turning the check on, grant p to every delegate who sends as a shared mailbox. Mail sent as a proved outside address is not aligned with that address's domain, so a receiver honouring its DMARC policy may quarantine or refuse it. How passwords are stored In the Control Panel, Access & abuse protection → Authentication, card Password storage. Schemes: 0 none, 1 Blowfish, 2 MD5, 3 SHA-256, 4 PBKDF2-HMAC-SHA256 (the default), 5 Argon2id, 6 DPAPI (stored secrets only), 7 scrypt. PreferredHashAlgorithm=4 ; 3, 4, 5 or 7. Anything else is refused (HM5528) and read as 4 MinimumAcceptedHashAlgorithm=0 ; refuse a logon whose stored hash is weaker. 0 = off PasswordPepper= ; a server-wide secret mixed into Argon2id and scrypt hashes PasswordHashIterations=0 ; PBKDF2. 0 = 210,000. Range 10,000 to 10,000,000 PasswordHashMemoryKB=0 ; Argon2id. 0 = 19,456 KiB. Range 4,096 to 1,048,576 PasswordHashTimeCost=0 ; Argon2id passes. 0 = 2. Range 1 to 20 Hashes upgrade at a successful logon, only upward. Raising the scheme or a work factor re-derives each hash when its owner next signs in; lowering either affects new hashes only. MinimumAcceptedHashAlgorithm set too high is a lockout. The refusal follows a correct comparison and the upgrade needs a successful logon, so an account below the floor never climbs out: its password must be reset. Raise the preference first, let accounts sign in, then set the floor. Argon2id and scrypt are peers, so 5 accepts either. A work factor out of range is reported as HM5561 and read as 0; HM5607 means Argon2id was asked for on a build whose OpenSSL has none, and another scheme is used. Argon2id allocates PasswordHashMemoryKB on a connection thread at every logon. PasswordPepper must be set before accounts exist: changing it invalidates every Argon2id and scrypt password. PBKDF2 is not peppered, so it stays usable for SCRAM. Since 6.3.4 it lives in hMailServer.ini only and no backup carries it, so keep a copy of the value with the backups: a database or archive restored onto a machine whose file has no pepper, or a different one, refuses every Argon2id and scrypt password, and a warm standby needs the same value in its own file. Where the service cannot write the file (a new Windows installation running as NT SERVICE\hMailServer, or a Linux package installation), COM and REST refuse it: set it with an elevated editor (sudoedit on Linux) and restart the service. The password policy All off until set, applied where a password is chosen, never at logon; on Windows under Access & abuse protection → Administrative access, Password tab. PasswordPolicyMinimumLength=12 PasswordPolicyRequireMixedCase=1 PasswordPolicyRequireDigit=1 PasswordPolicyRequireNonAlphanumeric=1 PasswordPolicyRejectCommon=1 ; refuse passwords from a built-in common list PasswordPolicyHistoryCount=5 ; refuse the last N passwords PasswordPolicyMaximumAgeDays=0 ; 0 = passwords never expire The office profile sets a minimum of 10 and the common list. Expiry needs care: IMAP, POP3 and SMTP cannot change a password and /portal refuses an expired one, so an administrator renews it, or its owner through an app password, which still signs in to /portal. Active Directory accounts are exempt. The breach check is in Hardening a public mail server; the rest of sign-in is in Signing in. What it does not do None of it spam-tests your own users: an authenticated session never is. A setting profile never writes an IP range. Where to read more Wiki: Security Hardening sections 17.1, 17.2, 17.5, 17.7 and 17.9; Settings Reference sections 9.1, 9.9 and 10; Stopping Spam section 10.1; Troubleshooting sections 19.3 and 19.7. Documents: SettingsApply.md, SettingLevels.md, SendAs.md, Profiles.md, Roles.md, ServiceAccount.md. Public documentation: SecurityRange and SecurityRanges, for the COM names of the range flags. On this forum: Being trusted by the servers you send to, The Control Deck, Upgrading to 6.3.4, hMailServer on Linux.
  • 0 Votes
    1 Posts
    156 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) is a security release that closes gaps in what this guide describes. Over COM an account given serveradmin with a list of domains was the server's administrator, its list aside, and one given domainadmin with a list that left out its own domain administered that domain's ordinary accounts; both are now confined as over REST, so before upgrading give serveradmin with no list to any account that is to administer the whole server over COM, a script's or a Control Panel's account among them. A credential confined to named domains is refused a domain's rename, a domain alias, a custom role's creation, change or deletion, a rule action that reaches the server's own addresses, a route's stored credentials or the event script, a relay host that is not public, and the server-wide metric history, over REST and COM alike; and a role is given or taken away only by a credential that takes in what the account holds now and afterwards, so manage_roles in named domains can no longer take a role from an account whose admin level is the server administrator's. A state-changing REST request that a browser reports as cross-site is refused. In the Control Panel, API & monitoring is Monitoring & alerts and REST API keys is under Sign-in & access; Ctrl+K takes every old title to its page. See the 6.3.7 announcement. This guide puts administrator roles in one place. Roles are new since 6.3.4 (schema 6047). The one thing to know first: an upgrade changes nobody's authority. The upgrade writes no assignment, and an account with no assignment holds exactly what its admin level has always given it. Nothing narrows until you give somebody a role. Permissions, roles and assignments A permission is one thing a credential may do, a role is a named set of permissions, and an assignment gives one account one role in named domains. An account holds at most one role. Role For Reaches when no domain is named The same as serveradmin Everything, including the secrets no other role reads Every domain The administrator password, admin level Server, an API key with Scope=full and no role domainadmin The accounts, aliases, lists and mailboxes of a domain The account's own domain Admin level Domain helpdesk Finding an account, resetting its password, unlocking it, and reading where its mail went, and nothing else The account's own domain Nothing before 6.3.4 auditor Reading everything the administration exposes, the audit trail included, and changing nothing Every domain An API key with Scope=readonly and no role The built-in roles cannot be edited or deleted. Their permissions are in the server's code, not the hm_roles table, so a change to the table cannot hand anybody a permission. The 27 permissions and who holds them A permission marked server-wide is reached only by a credential with no list of domains. The queue, the quarantine, the archive, the logs and the settings carry every domain's mail, so a role confined to named domains is refused them whatever it holds. Permission What it reaches serveradmin domainadmin helpdesk auditor administer_server Everything, secrets such as password hashes and private keys included; COM's "is this the server administrator?" yes administer_domain COM's "is this a domain administrator?" yes yes view_configuration Status, settings, listeners, certificates, rules, routes, anti-spam lists, the roles and who holds them, alert rules and events, bounce and complaint readings; never a secret yes yes yes view_accounts Domains, accounts, aliases, lists, groups (server-wide), fetch accounts yes yes yes yes view_mailbox Another account's folders and messages yes yes yes view_queue The delivery queue (server-wide) yes yes view_quarantine The quarantine (server-wide) yes yes yes view_archive The archive (server-wide) yes yes view_logs The logs (server-wide) yes yes view_message_trace The message trace; with view_configuration, the reports and a domain's suppression list yes yes yes yes view_audit The audit trail (server-wide) yes yes manage_accounts Creating, changing and deleting accounts, aliases, lists, groups, fetch accounts and app passwords; a domain's spam traps, DKIM rotation and suppression list; moving a mailbox (needs both domains) yes yes reset_password POST /api/v1/accounts/{address}/password, Application.ResetPassword yes yes yes unlock_account POST /api/v1/accounts/{address}/unlock, Application.UnlockAccount, Account.UnlockMailbox; clearing the logon-failure list (server-wide) yes yes yes manage_mailbox Another account's folders, messages and folder rights, a support session, a PST migration job (with manage_accounts) yes yes manage_queue Retrying or deleting a queued message (server-wide) yes manage_quarantine Releasing or deleting held mail (server-wide) yes yes manage_archive Holding and releasing archived messages (server-wide) yes manage_settings Every setting, listener, certificate, route, rule and anti-spam list, the alert rules (server-wide); the webmail's branding and file-link policy, a confined credential only its own domains' yes manage_domains Which domains exist (server-wide) yes manage_server Reinitialise, back up, reload scripts, clear caches, install an update, run a pass now (server-wide) yes manage_roles Roles and who holds them (server-wide) yes send_through_api Sending through POST /api/v1/send; only an API key reaches it yes provision SCIM 2.0 at /scim/v2, reads and writes; only an API key reaches it yes view_discovery eDiscovery's cases, searches, holds and exports yes yes manage_discovery Opening and closing a case, searching, legal holds, exports yes manage_inbound_webhooks Routing an address or a domain to a URL, as much as reading every message the route takes yes Four rules sit beside the table: The auditor reads mail. It holds view_mailbox; the help desk does not. The reports need two permissions. GET /api/v1/reports needs view_configuration and view_message_trace, because it says who mails whom. domainadmin and auditor read them; helpdesk is refused, and the Deck leaves the Reports view out for any role without both. The trace follows the role's reach. A confined help desk traces one whole address in a domain it reaches and sees only events naming that address exactly: [email protected] does not also show [email protected]. Clearing the logon-failure list is server-wide. hm_logon_failures records only the address a failure came from, with no account or domain, so a confined help desk is refused POST /api/v1/settings/logon-failures/clear, and Settings.ClearLogonFailureList answers the server administrator alone. The help desk unlocks one account with POST /api/v1/accounts/{address}/unlock instead; a password reset clears the lockout too. A ban already placed is an IP range under /api/v1/ipranges, which needs manage_settings. What only serveradmin has Reading a secret. No view_ permission covers a password hash or a private key: an auditor that could read one would be an offline attack away from being every role. Handing out authority. No custom role may hold administer_server, administer_domain or manage_roles, and a credential may never give a role holding a permission, or reaching a domain, that it does not hold itself. Taking over a wider account. A credential may not reset the password of, or change, an account whose whole authority it does not take in. A help desk is refused a domain administrator's or an auditor's password, even in its own domain, because otherwise it could sign in as them; a domain administrator is refused an auditor's. Where the server administrator's own mailbox is in a domain somebody else administers, that domain's administrator is refused all of these on it, over REST and COM. Over COM this is asked where the write is made, not where the object was reached: Account.Save, Account.Delete, Account.MoveTo, Application.ResetPassword, the app passwords and every write to what is in an account (FetchAccount.Save, Rule.Save, IMAPFolder.Save, Message.Save and the rest) ask that the credential reach the account and take in its authority. An event script's objects carry no credential and are left as they were. Roles.md lists every route and COM member that asks this. Which domains a role reaches Credential No domains named * A list An assignment of serveradmin or auditor Every domain Every domain Only those An assignment of any other role, custom ones included The account's own domain Every domain Only those An API key's Domains= line, whatever its role Every domain Matches no domain Only those A custom role holding a server-wide permission needs * before an account can use it at all. The listings answer every_domain over REST, and a fourth field over COM. A credential confined to named domains sees only the assignments of accounts in those domains. Giving a role, surface by surface Control Panel (Windows only): Accounts & domains → Administrator roles lists the roles and who holds them. Type an address, choose a role, optionally name the domains, and press Give the role; select a row and press Take the role away. It applies at once. Control Deck (Windows and Linux): the Roles view does the same. REST: giving or taking away a role needs manage_roles, which only serveradmin holds and which is server-wide: the administrator password, or a serveradmin credential reaching every domain. PUT /api/v1/role-assignments/[email protected] {"role":"helpdesk","domains":"example.test,example.org"} DELETE /api/v1/role-assignments/[email protected] GET /api/v1/role-assignments GET /api/v1/roles COM (Windows only): an empty role name takes the role away, and Account.RoleName, RoleDomains and RolePermissions read it back: $app = New-Object -ComObject 'hMailServer.Application' $account = $app.Authenticate('Administrator', 'your-admin-password') if (-not $account) { throw 'Authentication failed.' } $app.AssignRole('[email protected]', 'helpdesk', 'example.test') $helen = $app.Domains.ItemByName('example.test').Accounts.ItemByAddress('[email protected]') $helen.RoleName; $helen.RoleDomains; $helen.RolePermissions With a second factor on the administrator, Authenticate refuses and the script uses AuthenticateWithCode. Application.CurrentRole and CurrentPermissions say what a session holds. An API key: POST /api/v1/apikeys with "role":"helpdesk" writes a Role= line to hMailServerApiKeys.ini. The key store answers to the administrator password alone. The Deck's API keys view, signed in with that password, also makes a key with a role and its domains, showing the token once. curl -u Administrator:your-admin-password \ -H "Content-Type: application/json" \ -d '{"label":"help desk tool","role":"helpdesk","domains":"example.test"}' \ https://<host>:8045/api/v1/apikeys Use the address and port your listener answers on; bound to loopback with no certificate, it is http://127.0.0.1:8045 (https:// once a certificate, or an ACME one, is in place). A key's role decides what it reaches. The Control Panel's REST API keys page, as its reference describes it, names no role; give a key its role over REST or in the Deck. No API key signs in to the Deck. Custom roles are made over REST from a name, a description and a comma-separated permission list; both editors list them and give them out. A role that releases held mail holds server-wide permissions, so it is given with * and reaches every domain's held mail: POST /api/v1/roles {"name":"quarantine-desk","description":"releases held mail","permissions":"view_quarantine,manage_quarantine"} PUT /api/v1/role-assignments/[email protected] {"role":"quarantine-desk","domains":"*"} A permission the server does not know is dropped, not refused, so a custom role ends with less authority than it asked for, never more. A custom role somebody holds cannot be deleted: DELETE /api/v1/roles/{name} answers 409 saying how many accounts hold it, and the Deck's Delete shows that sentence. Give each holder another role or take this one away first; assignments are never removed for you, because an account with none falls back to its admin level. A built-in role answers 400, and COM cannot delete a role. An assignment decides even when its role holds nothing: holders of a custom role whose permissions name nothing this version knows are ordinary accounts, not their admin level. Where each role works Role Control Deck REST API Control Panel (COM) serveradmin Every view Every route Every page domainadmin Dashboard, DANE / TLSA, domains, fetch accounts, lists, roles and reports for its domains Its domains' accounts, aliases, lists and mailboxes, the status, who holds a role there Domains and Administrator roles helpdesk Domains, fetch accounts and lists, with Reset password and Unlock on every account The reset, the unlock, the account listings, the trace of an address in its domains Welcome and About only; Application.ResetPassword, UnlockAccount and GlobalObjects.MessageTrace answer a script auditor Every view that reads, the audit trail and reports included Every read, the audit trail and alerts included; every write refused Welcome, About and Administrator roles The help desk and the auditor work in the Deck. COM's settings objects answer only the server administrator, so an auditor reads the configuration through the Deck or REST. A domain administrator is not shown the settings, rules, routes, remote domains, certificates, ports, IP ranges, groups, backup, server messages, queue, logs or audit trail, which are server-wide. The quarantine is server-wide as well, so a domain administrator confined to its domain is refused it. Hiding a page is a courtesy, not the boundary. The server refuses the request whatever a page draws, and a Control Panel connected to a server that predates roles shows every page. A role holder signs in with its own address and password, and its second factor where it has one. An app password never carries the role: over REST it is an ordinary account's request, and COM's Application.Authenticate and AuthenticateWithCode treat it as a wrong password. A support session into a mailbox does not carry the person's role either. A role holder's own mail and settings under /api/v1/me stay its own. Setting up a help desk Turn the REST listener on if it is off. It needs RestApiPort set, RestApiBindAddress set to an address staff can reach (the default, 127.0.0.1, serves this machine alone), a certificate unless it is bound to loopback, and a name staff can reach. On Windows set them on the Control Panel's API & monitoring page (Monitoring & alerts since 6.3.7) and press Apply now, since they wait for a reinitialise. On Linux run sudo hmailserver --set-setting RestApiPort=8045 and the same for RestApiBindAddress and, for any address but loopback, RestApiCertificateFile and RestApiPrivateKeyFile (or let an ACME certificate stand in), then sudo systemctl restart hmailserver. The Control Deck topic has the details. Give each person a mailbox of their own; the role goes to that account. Decide the domains. With none named, helpdesk reaches only the account's own domain; name several, comma separated, for a desk serving more. Give the role on any surface above and check it with GET /api/v1/role-assignments or the Roles view. The person signs in to the Deck at https://<host>:8045/ as themselves, then uses Reset password or Unlock on an account. Tell them the limits: no mail reading, no reports, no domain administrator's or auditor's password, no removing a ban, and, when confined, no clearing of the logon-failure list. Each change the help desk makes is on the audit trail as its own, over COM and REST, with actor type account and a detail ending [role: helpdesk]. What a refusal says A permission the role lacks: 403 naming both, for example the role 'helpdesk' does not hold the permission 'manage_settings'. A domain it does not reach: the role 'helpdesk' does not reach that domain, whether or not the account exists, so nobody can list another domain's mailboxes one request at a time. Over COM, Application.ResetPassword and UnlockAccount answer No such account. for both. An account wider than the credential: that account holds authority this credential does not. Over COM, since 6.3.4 a refusal carries the server's sentence rather than a bare Exception from HRESULT: 0x800403E9. An API key on the key store, the [Settings] routes, the audit trail or the alerts: 401 with {"error":"authentication failed"}, the same as "not a key". The two stores only the administrator password opens The key store (/api/v1/apikeys) and the [Settings] section of hMailServer.ini (/api/v1/settings/ini) answer to the administrator password and nothing else: not an account holding serveradmin, not a key of any role or scope. A key that could mint keys could issue itself an unrestricted replacement, and the file holds the server's secrets. An account is refused 403 with the reason, a key 401. The audit trail (/api/v1/audit) and the alerts (/api/v1/alerts/...) are refused to every API key with the same 401, so a stolen key cannot read what it did or silence the alerting. An account whose role reaches every domain reaches them through view_audit, view_configuration, manage_settings or manage_server; a confined role is refused them. Upgrades, the audit trail and backups The upgrade. Schema step 6047 adds hm_roles, seeded with the four built-in rows, and hm_roleassignments, and writes no assignment. Roles are data, not settings: nothing goes into hm_settings or hMailServer.ini. The audit trail. Every role created, changed or deleted, and every role given or taken away, is a row naming the credential that did it; an assignment's row reads like role: helpdesk -> auditor; domains: the account's own domain -> every domain. The actor type follows the role: the administrator password and holders of serveradmin or domainadmin are administrator, every other account is account. Backup and restore. An account's assignment travels with it, by role name, and the custom roles travel whenever the domains or the settings do, restored first. A role the restoring server already has is kept as it is, with any difference named in the backup log. The admin level waits until the assignment is written, so a restore that stops part-way leaves no account wider than its role. An assignment naming a role neither side has is dropped, the level stays withheld, and HM6129 names the account. No archive carries the API key store. What it does not do No mapping from an identity provider. There is no claims mapping; an identity provider saying somebody is an administrator is not obeyed. The server's roles and oidc_administrators or saml_administrators decide. No role on an app password or a support session. No Control Panel or COM on Linux: roles are given there in the Deck and over REST. Where to read more Roles.md, the authority on all of this. Sign-in and Identity §7, The Control Deck, The REST API §2 and The COM API and Scripting §23.2. AlertsAndAuditTrail.md, Backup.md and Reports.md. On this forum: The Control Deck: browser administration at /, The REST API: turning it on, credentials and roles, The COM API on Windows, Hardening a public mail server, Alerts and the audit trail and IP ranges, auto-ban and lockout.
  • 0 Votes
    1 Posts
    140 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) moves the Control Panel's pages: Updates is a page of its own under Maintenance, the sidebar has Compliance and Virus scanning groups, API & monitoring is Monitoring & alerts, the PROXY protocol and XCLIENT are a card on Incoming relays, and Ctrl+K takes every old title and route to its page. A Control Panel signed in to a server on another computer now shows and saves the server's hMailServer.ini [Settings] values. The anti-virus action named Delete infected attachments only in 6.3.6's Control Panel is Remove all attachments and deliver the text in 6.3.7's. The installers carry the .NET Desktop Runtime 10.0.13, Microsoft's security release of 13 October 2026, on which the Control Panel runs, but install it only where no .NET 10 Desktop Runtime is installed at all: an upgraded server keeps the 10.0.12 that 6.3.4, 6.3.5 or 6.3.6 installed, so bring it to 10.0.13 or later through Microsoft Update or Microsoft's installer. See the 6.3.7 announcement. The hMailServer Control Panel (hMailCP.exe) is the Windows desktop administration application: a .NET 10 WPF program, x64 only, that talks to the server over the COM API. That is why it can administer a server on another machine over DCOM, and why there is none on Linux, where the Control Deck, the REST API and hmctl are the administration surfaces (hMailServer on Linux: what you get and what you do not). This topic covers what it writes and where, connecting, the 65 pages with the store behind each, and, since 6.3.4, the mark under each field that says when a saved value applies, the pending bar, the Levels tab and the help pane. The one thing to know first: since 6.3.4 the Control Panel writes every [Settings] key over COM into the database, even when it runs on the server itself, and a Control Panel with no connection says it cannot change such a setting rather than writing to the file, where a stored key's line is ignored in favour of the database's value. What it holds, and what it writes where The Control Panel holds no configuration of its own. Its per-user state (window bounds, theme, language) is under HKCU\Software\hMailServer\ControlPanel. The server is reached over COM. Files on the server (hMailServer.INI, hMailServerApiKeys.ini, the log folder, the event script, certificate and key files) are reachable only when the Control Panel runs on the server itself. Since 6.3.4 the database is the store of the [Settings] keys, and the file holds a copy (where each setting is kept, and what stays in the file). The Control Panel reads those keys over COM, falls back to the file only when it has no session, and writes them over COM only; a [Settings] line edited by hand in the file changes nothing, and the error log names it as HM5804. [Database], [Directories] and [LDAP] are still read from the file only, and [Database] and [Directories] are deliberately not reachable over COM. Since 6.3.4 a new installation runs the service as NT SERVICE\hMailServer; an upgrade keeps the account it had (the service account, and moving to or from it). hMailServer.INI is read-only to that account on purpose, so its copy of the settings goes stale there. For the Control Panel that changes four things, each refused with a sentence rather than failing quietly: What Under the virtual account Settings saved on any page Unchanged, since they are kept in the database; only PasswordPepper, kept in the file only, is refused The Administrator password card, and enrolling or removing the administrator's second factor Refused. For the password the sentence names hMailServer.exe /SetAdministratorPassword from an elevated prompt The data, log and temporary directories Refused: an administrator changes the file and approves the new folder for the service Creating or switching the database Refused before anything is made Maintenance → Server limits & expert settings carries a Windows service account card: what the service actually runs as, and three buttons, each run after the Windows elevation prompt: Grant access (hMailServer.exe --confirm /GrantServiceAccess), Move to NT SERVICE\hMailServer and Move to LocalSystem. The live update's apply and the auto-ban's firewall rules need LocalSystem, and are refused under the virtual account with a sentence. From 6.3.6 a service running as NT SERVICE\hMailServer downloads and verifies an update, and an administrator installs it with Install update on the Server status page of the Control Panel on the server, with one Windows prompt; on 6.3.4 and 6.3.5 Install update cannot do it, and the administrator runs the downloaded installer by hand. Connecting Field What to enter When it is wrong Server localhost, or the remote server's name or IP; an empty box means localhost A name that does not resolve, or does not answer on TCP 135, gets a sentence saying so. The check has a four-second budget, so a mistyped host is a pause, not a hang User name Administrator. A mailbox address also authenticates, but only a server administrator can read the settings "Authentication failed. Check the user name and password." The server never says which of the two was wrong Password The administration password set during installation The same message "hMailServer COM API is not registered on the target machine." means you reached the machine but hMailServer is not installed there. "Unable to reach the server (RPC unavailable)." is HRESULT 0x800706BA: firewall, DCOM permissions, or the service is not running. Two second factors, and they are not the same thing. The server-enforced one, whose secret is [Security] AdministratorTotpSecret in hMailServer.ini, protects every client of the administrator credential: this Control Panel, COM scripts, and the REST API through its X-hMailServer-OTP header. The older one, AdminTotpSecret under HKLM\SOFTWARE\hMailServer, protects this installation of the Control Panel on this machine and nothing else. The code is asked for once, never in a loop, because a wrong password and a missing code look identical from outside. hMailCP.exe /connect <host> <user> <password> signs in as the window loads; the password is on the command line, where anything that can list processes can read it. Connecting opens the Dashboard, not Welcome. COM sign-in is deliberately outside the auto-ban and the per-name lockout, so guessing an administrator's name over IMAP cannot lock that administrator out. The window and the tree Since 6.3.4 the Control Panel is drawn on one design system. The window has three rows: the title bar; a command bar holding the sidebar toggle, a search field that opens the Ctrl+K palette, a server status pill (Not connected, Connected, Reconnecting…, Connection lost), the theme toggle and the administrator's menu; then the sidebar beside the content. Below 1,000 pixels of window width the sidebar collapses to a rail of one glyph per group. What did not change is the part you may have scripted: the navigation map, every page title, tab header, setting caption and automation id (nav-<key>) are what they were. The sidebar holds 65 pages in eight groups in 6.3.4 (55 in 6.3.3), never more than two levels deep: Monitoring & troubleshooting, Accounts & domains, Mail flow & delivery, Spam & virus filtering, Connections & protocols, TLS & certificates, Access & abuse protection and Maintenance, with Welcome, Dashboard and About outside them. The ten pages new in 6.3.4 are Suppression list, Journaling and dual delivery, Audit trail, Discovery, Administrator roles, Remote domains, Allow and block list, Greylisting bypass list, Domain white and black list and Setting profiles. Search (Ctrl+K) answers three questions in one ranked list: a page name or any alias; what you are trying to do, from 97 outcome phrases such as "stop spam"; and a setting name or key, from an index of 448 settings in 6.3.4 (393 in 6.3.3). It also resolves 54 old navigation paths, so Settings > Security > Auto-ban & SSL/TLS opens Auto-ban. Welcome. Since 6.3.4 it offers a throwaway sample domain, example.test, and a first-run tour of seven stops that never acts and is never modal. Every page, by what it writes The wiki lists each page with its navigation key, which never changes when a page is renamed. Grouped by the store behind them, the 65 are: What the page writes Pages Applies Nothing: no settings behind the page (6) Welcome, Dashboard, Live logs, Diagnostics, MX query, About not applicable Read-only, or actions only (12) Server status, Delivery queue, Message trace, Audit trail, Discovery, External setup, DNS records, Server sendout, Spam filtering overview, Quarantine, Virus scanning overview, Transport encryption overview Actions at once The COM settings tree, a COM collection, or the database through COM (25) Diagnosing stalled mail, Suppression list, Journaling and dual delivery, Domains, Public folders, Groups, Administrator roles, Routes, Remote domains, Incoming relays, Rules, Server messages, SURBL servers, DNS blacklists, White list, Blocked senders, Allow and block list, Greylisting white list, Greylisting bypass list, Domain white and black list, Blocked attachments, TCP/IP ports, SSL certificates, IP ranges, Setting profiles At once; a profile's entries as each setting's own mark says [Settings] keys, in the database since 6.3.4 (7) API & monitoring, Web services & autoconfiguration, DNS resolver, Certificates (ACME), Transport security, Authentication, Server limits & expert settings As each field's mark says COM and [Settings] keys together (11) Logging, Delivery of e-mail, Anti-spam settings, Anti-virus settings, Protocols, SSL/TLS, Administrative access, Auto-ban, Backup & restore, Performance, Advanced COM at once, except the syslog card on Logging (since 6.3.4), whose values the sink takes when it starts, at a reinitialise or a service start; the keys as each field's mark says A file on the server (4) REST API keys (hMailServerApiKeys.ini, re-read on every request), Directory authentication (LDAP) and Directory synchronisation ([LDAP], re-read within two seconds), Event scripts (the script file; Save & reload reloads the engine) Without a restart What the table cannot say: Three overview pages are deliberately read-only: Spam filtering overview, Virus scanning overview and Transport encryption overview. They show what no single editor can: a virus scanner that is switched on but cannot run is treated as no virus found, so infected mail is delivered as though examined; a TLS port with no certificate fails to start rather than falling back to plaintext. Discovery (since 6.3.4) changes nothing and is the one page that reads the REST listener, because discovery has no COM interface. It needs RestApiPort set, a certificate it can check for an address beyond loopback, and an administrator without a second factor. A case is opened, searched, held and exported on the Control Deck (eDiscovery and legal holds). Journaling and dual delivery and Audit trail are the server administrator's only. Message trace and Quarantine are inert unless MessageTraceEnabled and QuarantineEnabled are set, and Blocked attachments unless attachment blocking is on in Anti-virus settings. Server limits & expert settings also edits [SendingLimits] and [SendingLimitsOverrides], which stay in the file and are re-read within seconds. Performance also edits the local [Database] rows, and since 6.3.4 has a Message store tab: MessageStoreCompression, off by default, and MessageStoreDedupMinKB, 256. The dialogs. Since 6.3.4 the domain dialog has fourteen tabs (seven in 6.3.3) and the account dialog fifteen (twelve), each ending in Levels. The mark under each field, and the pending bar Since 6.3.4. On 6.3.3 a save of a page whose settings live in hMailServer.INI offers to restart the service. Against a 6.3.4 server a save publishes, and under every field kept in the settings store a small line says when the value takes effect (which keys carry each mark, and what a reinitialise takes The line Meaning Applies on save In effect when the save returns After reinitialize A listener's port or bind address, a TLS context, a work queue's size: waits for Apply now After a restart ServiceAccountName and ServiceAccountPassword, which are retired. The [Database] rows on Performance carry the same words Every key's mark comes in one COM call when such a page is opened, Settings.IniSettingAppliesAll. A page's save writes only the fields whose value changed, because every write publishes, and it says how many of its keys still wait. The pending bar sits at the foot of the window: "N saved setting(s) wait for a reinitialize", with Apply now. The list behind it is Settings.PendingIniSettings, recomputed by the server at every request, so a value put back before anything applied it is not pending. Apply now is Application.Reinitialize over COM: every service stops and starts again in place, with no service restart and no UAC prompt. It asks first. While the server is draining for maintenance the question says that the listeners open again and delivery resumes, because a reinitialise ends the drain. It takes every reinitialize key and not a restart key. When a restart key waits too, what it says afterwards is how many still wait for a service restart, not that the saved settings are in effect. The Control Panel's COM session survives it. The Control Deck's session does not. Three things the pages will not do. Return a key to its default. Clearing a box stores an empty value, which a number reads as 0. The default comes back through DELETE /api/v1/settings/ini/{name}, hmctl ini delete <name> or COM Settings.DeleteIniSetting(name). Change a setting the environment names. A setting set by HM_SETTING_<key> or HM_PROPERTY_<name> (configuration from the environment) is shown disabled, with Set by the environment in place of the mark. Claim more than an older server does. Against a 6.3.3 server, which lacks IniSettingAppliesAll and PendingIniSettings, every field kept in the store is marked After a restart, a save says the service must be restarted, and no pending bar is shown. The Levels tab. Since 6.3.4 the domain and account dialogs list the twenty-seven settings a domain or an account may hold its own value of, ticked where this level holds one, with "In effect: ..., from the ..." beside each. Save levels now writes what changed over COM at once, reads every line back, and shows the server's sentence when it refuses one. Against a server older than schema 6088 the tab says the server has no levels. The help pane Since 6.3.4. Every page has a ? button in the command bar, and F1 does the same: a right-hand pane opens beside the page with what the operator documentation says about it, scrolled to the right heading. It has the document's headings as a list, a search box over the open document, and two links at the foot: Open on the wiki and All documentation. The text is built in. It is the repository's hmailserver/docs/*.md, embedded in the Control Panel as resources (each named Help.<Name>.md, with README.md and DeckParity.md excluded). The Control Panel must work with no REST listener, so it carries its own copy and reads it over no route at all. What is thinner than it sounds. A page whose subject has no document of its own (the TCP/IP ports, the certificates, the groups) opens the nearest one. The search is within the open document only, not across all of them. Open on the wiki is HelpWikiBaseUrl followed by the document's name. The wiki's pages are not named after the documents, so for most documents that link finds no page yet; the pane's own text is the complete one. HelpWikiBaseUrl is a row of hm_settings, shipped as https://gitlab.com/hmailserver/hmailserver/-/wikis/ and edited on the Advanced page under General. A value that is not empty and not an absolute http:// or https:// URL is refused, and empty hides the link. The Control Deck and the webmail have the same pane, served by the server from GET /api/v1/help/{page}. Administering a server on another machine Type the server's name into the Server box and the Control Panel connects over DCOM. That covers everything the COM API can reach. What degrades is anything that means reading a file on the server: On a remote session What you see Live logs "Log folder not found on this machine (live logs need a local server)." REST API keys The key store is a file beside hMailServer.INI; the page needs it The "Listening" badge on TCP/IP ports Every port reads "Unknown": the TCP table probed is this machine's Certificate and private-key inspection "cannot be checked from here" Event scripts The script is loaded from and saved to local disk The [LDAP] and [Database] editors Those sections are read from the file only Editing the [Settings] pages from another machine is not confirmed for 6.3.4. The wiki's Control Panel page says, in section 5.5 on remote administration, that such a page answers "hMailServer.INI was not found on this machine. These settings can only be edited on the server itself." Its 6.3.4 note in section 5.0 says that these keys are now read and written over COM, and that section 5.5 describes 6.3.3 and was not re-checked against the change. Test it on your own installation before relying on it; if a remote page refuses, use Remote Desktop or the REST API. Since 6.3.7 a Control Panel signed in to a server on another computer shows and saves the server's hMailServer.ini [Settings] values, and no longer reads or writes this computer's file for the [Database], [SendingLimits] and [LDAP] values, which it cannot read from there. When the Control Panel itself is the problem Symptom What it means What to do It does not reconnect after you stop the service Deliberate: it rebuilds only a link that broke while the service was up, because activating the COM class would start a service you stopped on purpose Start the service, then use any page An unexpected-error dialog An unhandled UI fault See %LOCALAPPDATA%\hMailServer\ControlPanel\control-panel-errors.log Signing in freezes the window The host accepted TCP 135 and then stalled inside DCOM Check DCOM permissions and the firewall on the server With a server-enforced second factor, a silent reconnect cannot produce a fresh code, so after a service restart you sign in again through the prompt. What it does not do, and where to read more There is no Control Panel on Linux and no COM there; the Control Deck, the REST API and the hmctl client are the surfaces. The Control Panel never returns a key to its default, and it has no page for an account's kind (a person, a meeting room or equipment), encryption at rest, object storage or working an eDiscovery case: those are the Control Deck's and REST's. The public documentation's chapter 20 lists all 65 pages of 6.3.4 by group, and the wiki's Control Panel Pages is the source it follows. Connecting, the shell, the tour and the help pane: https://gitlab.com/hmailserver/hmailserver/-/wikis/The-Control-Panel Every page with its key and its store: https://gitlab.com/hmailserver/hmailserver/-/wikis/Control-Panel-Pages Every page, dialog and field with the setting behind it: https://gitlab.com/hmailserver/hmailserver/-/wikis/Control-Panel-Reference When a saved setting takes effect: https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SettingsApply.md The help pane: https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Help.md The public documentation: https://www.progressiverobot.com/hmailserver-documentation/#5-the-control-panel-your-first-look and https://www.progressiverobot.com/hmailserver-documentation/#20-every-control-panel-page
  • 0 Votes
    1 Posts
    137 Views
    ProgressiverobotP
    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 in hMailServer.ini changes nothing; at the next start the server uses the stored value, names the key in the error log as HM5804, 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 COM Settings object 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, plus UseLanguage, read per call. On 6.3.3 they live in the file, mirrored into hm_inisettings. Since 6.3.4 (schema 6042) hm_inisettings is 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.ini is 0640 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, and ServiceAccount.md says the same of the Linux packages; the wiki's Installing on Linux page names HM5806 at a save and HM5803 at 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. PasswordPepper is 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 as HM5807 at 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 as HM5808. Surface Set a [Settings] key Return 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 0 REST PUT /api/v1/settings/ini/{name} with {"value": "..."} DELETE /api/v1/settings/ini/{name} hmctl, over REST hmctl ini set <name> <value> hmctl ini delete <name> PowerShell module Set-HmIniSetting none 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 prompt none Control Deck only SmtpTarpitCount, SmtpTarpitDelaySeconds, UseLanguage and RewriteEnvelopeFromWhenForwarding none 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> or HM_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/changed Command line hmctl config changed PowerShell Get-HmChangedSetting COM Settings.GetChangedFromDefault The REST route and the COM call answer the same document. store is ini (hm_inisettings) or database (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.ini ships with lines the packaging wrote, such as RestApiBindAddress=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. database defaults 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, smtpallowincorrectlineendings and 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 as RestApiPrivateKeyFile, is a path and is shown. known false: the server holds a value and ships no default for it, such as a key stored for a script of your own. hmctl prints (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; hmctl prints (forced from [SettingsOverride]). environment is variable or file, and hmctl prints (set by the environment). profile names 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 PasswordHashIterations outside the range the server accepts is reported as HM5561 and the built-in work factor used; an unusable PreferredHashAlgorithm is reported as HM5528 (or HM5607, 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 auditor included, with a 403, because the list includes commands the server runs: AutoBanCommand runs as the service account. The feature changes nothing. It does not compare two servers (two hmctl config changed --json answers and diff do), 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 now 211 A save applies it reinitialize 28 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, or Application.Reinitialize over COM restart 31 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, RestApiPrivateKeyFile The metrics listener MetricsServerBindAddress, MetricsServerPort, MetricsServerCertificateFile, MetricsServerPrivateKeyFile, MetricsServerAuthPassword, MetricsServerAuthToken, MetricsServerAuthUsername The web-services listener WebServicesBindAddress, WebServicesHttpPort, WebServicesHttpsPort, WebServicesCertificateFile, WebServicesPrivateKeyFile The ManageSieve listener ManageSieveServerBindAddress, ManageSieveServerPort The SSL contexts of the SMTP, IMAP, POP3 and ManageSieve listeners and the outbound client TlsCipherSuites13, TlsKeyExchangeGroups, TlsSessionCacheSize, TlsSessionTicketsEnabled, TlsSessionTimeoutSeconds, TlsTicketKeyRotationSeconds ACME, the database pool, the fetch queue AcmeEnabled, AcmeCertificateDirectory, DatabaseStatementTimeout, MaxNumberOfExternalFetchThreads The 2 that wait for a restart are ServiceAccountName and ServiceAccountPassword, which are retired: since 6.3.4 hMailServer.exe /Register takes 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 now because a subscriber re-latches them. MaxSubmissionsPerIPPerMinute and MaxOutboundPerDestinationPerMinute start 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 changed DNSServer is used for the next lookup, and an answer already cached stays until its TTL runs out. Pending. A reinitialize or restart key 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/pending answers [{name, stored, running, applies, secret}], and applies and pending come on every /api/v1/settings/ini/{name} answer. The administrator password's route COM Settings.IniSettingApplies(name), Settings.IniSettingAppliesAll, Settings.PendingIniSettings Control 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's IniSettingApplies refuses it and REST answers applies: null. Apply now is a reinitialise. Every service stops and starts again in place, which takes every reinitialize key and not a restart key. It asks first. A reinitialise ends maintenance mode, and POST /api/v1/server/reinitialize answers {"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 as HM5807. 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, or hmailserver --set-setting while the service runs) reaches this server at the next save here, a reinitialise or a restart, because nothing watches the table. hmctl has 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_max Gates plus_addressing_enabled, openpgp_portal_enabled, zero_access_allowed, directory_user_editable Preferences quarantine_digest, quarantine_digest_hour, external_tag_subject, external_tag_header, impersonation_action, quota_warning_percent, country_policy, message_retention_days A 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's SettingOverride. Of the [Settings] keys only QuotaWarningPercent has levels. Where each level is held. A field the domain or the account already had, such as the domain's MaxMessageSize or MessageRetentionDays, stays where it was, with the meaning it always had; its 0 or -1 is the level holding nothing. The rest are rows of hm_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 does POST /api/v1/settings/cache/clear or COM Cache.Clear. A row put in by hand that the interfaces would refuse is treated as holding nothing and reported as HM7311. Nothing changes for a domain or an account that holds no value of its own. Where What REST GET /api/v1/settings/levels lists the twenty-seven. GET /api/v1/domains/{domain} and GET /api/v1/accounts/{address} answer <name>_effective and <name>_source, and <name> where the level is held in the overlay. For a level held in the overlay a PUT takes a value of the setting's own JSON type, and null makes it inherit; for a level held in a field of its own null leaves it unchanged, and the field's own 0 or -1 is "take the level above" COM (Windows only) Domain.SettingOverride(name) and Account.SettingOverride(name), an empty string for "take the level above", written at once and not by Save; EffectiveSetting(name) and EffectiveSettingSource(name) hmctl hmctl domain set <domain> <name> <value\|inherit> and hmctl 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 HM7310 for a domain and HM6109 for an account. The XML backup carries the rows, and on restore a row the build refuses is left out and reported as HM7312. 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 FROM and at IMAP APPEND; the EHLO SIZE advertisement, 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_policy cannot 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 reinitialize key waits for Apply now and a restart key for a service restart. Was it typed into hMailServer.ini? The stored value wins and HM5804 names 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 only 1 is true: 2, yes and true all read as false. Does it need a companion? SRSEnabled needs SRSSecret, ACME needs AcmeDomains, autoconfig needs WebServicesHttpPort or WebServicesHttpsPort, and MTA-STS hosting needs the HTTPS one. Does the error log show HM5807 or HM5808? 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, hmctl and the PowerShell module, the hmailserver command line, the Control Deck, Upgrading to 6.3.4 and hMailServer on Linux.
  • 0 Votes
    1 Posts
    53 Views
    ProgressiverobotP
    The Control Panel raised an error dialog every time you dismissed the Ctrl+K settings palette (GitHub issue 21, reported by grumpymojo). It was present in both 6.2.14 and 6.2.15, and because choosing a result and pressing Esc both went through the same path, it appeared on essentially every search rather than on any particular search term or configuration. What the upgrade involved No server change and no database change. Schema version stays at 6005. Anyone coming from 6.2.14 or earlier should read the 6.2.15 notes as well, because everything in them applies here. Fixed Closing the palette moves the focus away, which raised the deactivation handler while the close was still in progress, and that handler closed the window a second time. WPF refuses that outright: System.InvalidOperationException: Cannot set Visibility to Visible or call Show, ShowDialog, Close, or WindowInteropHelper.EnsureHandle while a Window is closing. The deactivation handler now closes the palette only when a close is not already under way. Nothing was lost to this defect. The navigation had already happened by the time the dialog appeared, so no setting was misapplied. It was noise in the one feature added to make settings easier to find. Still open at this release Discussion #18, the stall after 354 when relaying from Postfix or Proxmox Mail Gateway, remained open and unreproduced. 6.2.15 added debug logging to the SMTP DATA path that distinguishes the three candidate stages, and that log is what will identify the cause. Tracked in #20. Validated by the full regression suite: 1040 of 1040 passing, zero failures. The download is hMailServer-6.2.16-x64.exe. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    49 Views
    ProgressiverobotP
    The IMAP sequence-set parsers only recognised * as the end of a range. Anywhere else it was parsed as zero, so UID STORE *:* +FLAGS (\Deleted) flagged every message in the mailbox, UID EXPUNGE * deleted every \Deleted message, and FETCH * returned nothing while answering OK. Any client using * outside a range was affected. What the upgrade involved No database change. The schema stays at version 6005. Issue #18 is not fixed and remains open, see #20. All four sequence-set parsers now resolve * on either side of a colon and normalise descending ranges, so 3:1 is the same set as 1:3, per RFC 3501. Twelve regression tests cover it, all twelve failing against 6.2.14. Also fixed: Restoring messages emptied the live data directory before checking the backup's message store existed. A settings-only backup restored with the messages option ticked, or a failed extraction, left an empty data directory and the only copy of the mail in a GUID-named temporary folder. It now checks first. A message whose file could not be read hung the outbound connection after the remote answered 354, idle until the client timeout of up to ten minutes, then re-queued and repeated. It now fails immediately. Only a genuinely missing file fails the delivery permanently. BDAT exact-length reads padded short chunks with NUL bytes. A sender announcing BDAT 100000 LAST that vanished after 40,000 octets had the truncated message delivered as complete. DKIM signing hashed the header name in lower case while writing it capitalised (upstream PR 530), so signatures using simple canonicalization failed strict verifiers. Several paths left files with no database row: rejected POP3 RETR, header rewrites leaving .eml.tmp, downloads with no local recipient, unsendable bounces. The account cache had no size cap. ManageSieve now disconnects after three failed authentication attempts and registers them with auto-ban. STATUS (RECENT) reported the selected folder's count for every folder. Settings configurable only in hMailServer.ini gained Control Panel pages: authentication, administrative access, DNS resolver, web services and autoconfiguration, and the consistency scan results. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    56 Views
    ProgressiverobotP
    A message file that could not be written was treated as success. IMAP APPEND answered OK [APPENDUID ...] for messages that were never stored, so Sent Items copies, drafts and migration uploads were lost while the client showed them saved. Anyone hitting a full volume, or a file locked by antivirus or backup, lost mail silently. A failed message copy killed the delivery task in local delivery, forwarding, Sieve redirect and mirroring, leaving the message locked in the queue to fail again on every restart. Both came from an adversarial audit that found and fixed 21 defects. No database change: schema version 6005, unchanged. The regression suite passed 1026 of 1026. Mail loss and stability Every string SQL parameter on MS SQL and SQL CE was bound from freed memory. A failed transaction start leaked its pooled connection, and after a few occurrences SMTP, IMAP and POP3 blocked until a service restart. A failed IMAP folder insert was reported as success, so messages filed into it were written to disk with nothing to find them by. Security DKIM test mode (t=y) turned a failed signature into a pass, which then satisfied DMARC alignment. A failure in test mode is now neutral, per RFC 6376. IMAP SASL credentials were logged verbatim: AUTHENTICATE PLAIN passwords and XOAUTH2/OAUTHBEARER tokens. Only the first DKIM key record at a selector was read, so roughly half of a rotating sender's mail failed verification. MTA-STS enforcement and MX failover were lost for recipients past the first batch. Protocol and Control Panel SELECT/EXAMINE report a sequence number in [UNSEEN], as RFC 3501 requires, not a UID. Reverse-DNS lookups for the Received header moved to their own thread pool, completing the 6.2.13 fix. Backup would not start (GitHub issue 19): a Control Panel call to a method the backup interface does not have. Ctrl+K now searches settings, all 227 indexed by label and INI key. Logging, scanner timeout, indexing and retry settings moved to the pages that own them, which is where #16 went. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    50 Views
    ProgressiverobotP
    Two lists in the Control Panel announced their CLR type name to screen readers instead of their contents. The alias list on the Domains page read hMailServer.ControlPanel.Views.DomainsView+AliasRow for every row, and Live logs read LogsView+LogLine for every line. The live log is the worse of the two. It is the page an administrator is most likely to be reading with a screen reader when something has gone wrong. Both lists use an ItemTemplate, so the text a sighted user sees comes from a binding, while a ListViewItem's accessible name falls back to ToString(). Neither class overrode it. Scope is genuinely those two. Every other list in the application is a DataGrid, which builds a row's name from its cells. The Domains page now reports [email protected] → [email protected], and the live log reports 37 items, none announcing a type name. (16184ce) The regression suite now runs in full 27 of the suite's 1026 tests had never executed on the release machine. They reported inconclusive because SpamAssassin and ClamAV were not installed. Installing both ran them for the first time and two failed, both defects in the tests rather than the server. TestWithVirus put the EICAR string in the plain body of a non-MIME message. Current ClamAV does not extract a plain body as a scannable part, so the message scanned clean and was delivered, failing its own "no messages" assertion. It now sends EICAR as a base64 attachment and matches the signature family rather than one exact name. TestSANotRunning called ServiceController.Stop() and returned immediately. Stop() only asks, so spamd was still answering on port 783 and the message came back with the X-Spam-Status header. It now waits for the port to refuse connections. It also asserted error 5157, reported only when a connection is established then lost mid-read. With spamd stopped, only 5508 is reported. 1026 of 1026 now pass, zero inconclusive, with live SpamAssassin and ClamAV, DMARC against live DNS and TLS 1.2/1.3 handshakes. Drop-in over 6.2.10. No database change (schema version 6005), no configuration change, no server-core change. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    56 Views
    ProgressiverobotP
    6.2.9 is a follow-up to 6.2.8. It completes what that release deliberately left out: the LiveCharts upgrade 6.2.8 had to pin back. No server-core changes, and the regression suite still stands at 898/898. LiveCharts 2.0.5 (GitHub issue 11) 6.2.8 pinned LiveCharts to 2.0.0-rc2 because upgrading painted both dashboard charts as an opaque white block over the dark theme, taking the "No delivery activity yet" and "No active sessions" labels with them. CartesianChart derives from Control, and 2.0.x gives that Control a solid default Background where the release candidate left it unset, so the chart painted a white rectangle across the dark card. The overlay labels were never actually hidden. They are light-grey text that happened to land on that white. Setting Background explicitly fixes both symptoms. Verified in both light and dark themes. Worth recording what it was not. 2.0.5 pulls SkiaSharp.Views.WPF, OpenTK and OpenTK.GLWpfControl, which looks exactly like a GL-hosted surface and the usual WPF airspace problem. It is not that. LiveCharts.RenderingSettings.UseGPU defaults to false, so rendering stays on the software path and ordinary WPF layering applies. Control Panel tests (GitHub issue 12) The GUI previously had no test coverage at all. CI compiled it and stopped there. A ControlPanel.Core library exposes the side-effect-free services (PasswordStrength, NumericField, PasswordGenerator) through shared compile links, so no code moved and the Control Panel project itself is untouched. ControlPanel.Tests runs 17 xUnit tests against them, with coverlet emitting Cobertura coverage that CI publishes on every push. The three .NET 8 projects also gained a solution, ControlPanel.sln. Repository Release tags are now protected against being moved or deleted, and master against force-pushes. Secret scanning and push protection are enabled. A Code of Conduct was added, and the issue chooser routes questions to Discussions. It was a drop-in over 6.2.8: no database change (schema version 6005), no configuration change, no server-core change. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    50 Views
    ProgressiverobotP
    A Control Panel bug-fix release. Both defects made a healthy server look broken, and they hit every Windows GUI administrator. There are no server-core changes since 6.2.6, and the regression suite still stands at 898/898. What the upgrade involved Drop-in over 6.2.7. No database change (schema version 6005) and no configuration change. #6: list editors showed blank rows Every data-driven list pane rendered the right number of rows with nothing in them. Adding an entry appeared to create an empty row, and only the Edit dialog showed the value you had typed. The row model exposed its data as a field, and WPF data binding resolves properties only, so every generated column silently bound to nothing. It was reported against domain aliases, but the same control backs SURBL servers, DNS blacklists, the anti-spam and greylisting white lists, blocked attachments, groups, server messages, external POP3 accounts and account rules. #7: the Control Panel died after a service restart The COM server lives inside the hMailServer service process, so restarting the service invalidated every interface pointer the GUI held, including restarts the Control Panel performed itself after saving a setting. Every page then failed with "The RPC server is unavailable" until you closed and reopened it. The session now verifies the link before use and re-authenticates transparently. A restart triggered from the Control Panel waits for the server to report Running rather than latching onto a service that has registered with Windows but is still opening its database. A restart by anyone else is detected on your next action and healed, with a "Connection restored" notification. The liveness check reads ServerState rather than Version, because a shutting-down service keeps answering Version from a static string after closing its database. The superseded COM proxy is released, and the Control Panel no longer starts a service the administrator deliberately stopped. Both fixes were reproduced on the previous build and verified against a live server: unit assertions on the session logic, a harness driving the real CollectionEditorView and DomainDialog, and UI automation over the running Control Panel. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    53 Views
    ProgressiverobotP
    6.2.7 was a Control Panel usability release. The server core was unchanged since 6.2.6, so nothing in message handling moved. Every change sat in the .NET 8 administration Control Panel, closing the gaps that still forced hand-typed paths, external tools or guesswork. What it changed: File and folder pickers everywhere. Every field holding a file-system path gained a browse button: the backup destination and restore file, the archive folder, the ACME certificate folder, the OAuth2 public key, the REST API / Web Services TLS certificate and key files, the ClamWin executable and database folder, and the DKIM private key. One-click DKIM. Domain > DKIM gained Generate key pair. It creates an RSA-2048 key, saves the private key, fills in the path, and shows the exact selector._domainkey DNS TXT record (v=DKIM1; k=rsa; p=…) with a Copy button. No more running OpenSSL by hand. Passwords. All password boxes got a reveal toggle. The account editor and the quick-create form got a Generate strong password button, using a cryptographic RNG and copying to the clipboard. The external POP3 fetch-account password is masked rather than shown in clear text. Inputs. The auto-reply expiry became a date picker. Numeric server settings and the collection editors use up/down number boxes. Every editor dialog obeys Enter to save and Esc to cancel. MX query and Diagnostics output got a Copy button. Window state. The main window remembers its size, position and maximized state between sessions, and a save-confirmation toast appears after saving. Because the core was untouched, the regression suite result carried over from 6.2.6: 898 of 898 tests passing, zero failures, zero inconclusive, including live SpamAssassin, ClamAV with real EICAR detection, DMARC evaluation against live DNS, and TLS 1.2/1.3 handshakes end to end. One package shipped, hMailServer-6.2.7-x64.exe, 64-bit Windows only. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    52 Views
    ProgressiverobotP
    hMailServer 6.2.6 added IMAP4rev2 (RFC 9051) as an opt-in session mode. The server advertises IMAP4rev2, and a client that issues ENABLE IMAP4rev2 gets RFC 9051 semantics for that connection. IMAP4rev1 behaviour is unchanged until a client opts in. The rest of the release is Control Panel and installer work. IMAP4rev2 In the opt-in mode: ESEARCH by default, \Recent and RECENT dropped from SELECT, EXAMINE and STATUS, the obsolete [UNSEEN] response code suppressed, and UTF-8 acceptance. Control Panel A central theme-aware colour-token system replaced scattered hardcoded colours. Success, warning, danger and info, and the log palette, now adapt to light, dark and high-contrast themes. A Fluent nav selection style and a brand keyboard-focus ring. Live-log colours legible on the light theme, readable data grids with balanced columns, and settings forms capped to a readable column with right-sized inputs. KPI colours that encode state, softened destructive buttons, "no activity" chart placeholders, and a Welcome page of clickable quick-action tiles. Every configurable server setting now has a GUI control: OAuth2 and external-token auth, SRS and BATV, submission and outbound rate limits, OpenTelemetry and the slow-query log, connection timeouts, delivery and queue tuning, search indexing, message archiving and other INI knobs, Logging.Device and LogFormat, cache size caps, the domain Active Directory link, and a write-only secret editor. Documented in settings.md. Two-factor authentication setup renders a real scannable QR code, with a grouped manual key and a copy button, and a larger verification field. Installer A DPI-scaled custom database-type page, modernised copy and refreshed brand imagery. The dead legacy dependency installers were removed: MSI, IE6, MDAC, JET and .NET 2.0. The server core was validated by the full regression suite, 898 of 898 tests passing, including live SpamAssassin, ClamAV against EICAR, DMARC against live DNS, and TLS 1.2 and 1.3 handshakes end to end. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    48 Views
    ProgressiverobotP
    hMailServer 6.2.5 fixed two faults that stopped a default install from connecting to its own database. Anyone who installed with the shipped defaults, an internal SQL Server Compact database with DPAPI secret protection, was affected. Critical fixes DPAPI database-password truncation (SQL CE error 25028). IniFileSettings::ReadIniSettingString_ used a fixed 255-character buffer, so GetPrivateProfileString truncated the ~356-character DPAPI-protected database-password envelope. The truncated blob failed to decrypt, which yielded an empty password and SQL CE error 25028, Authentication failed. The buffer is now 4096 characters, which also covers long OAuth2 HMAC secrets and the password pepper. Fresh-install database version, 6004 to 6005. The CreateTables scripts for MSSQL, MySQL and PostgreSQL still stamped hm_dbversion = 6004 while the server required 6005, so a brand-new install reported "database too old". SQL CE uses the MSSQL script, so it was caught by this too. The recipientdsnnotify column was already present. Only the version row was stale. Validation Checked end to end on a Windows Server 2025 Active Directory domain controller. A default internal-database install connects. AD authentication passes through COM ValidatePassword in both the DNS domain.tld and NetBIOS DOMAIN\user forms, and through a real IMAP LOGIN, correct password returning OK and wrong returning NO. Control Panel The .NET 8 WPF Control Panel (hMailCP.exe) reached full settings parity with the classic Administrator here. The Server Status page (version, server state, database details, statistics, session counts, uptime, and a configuration-warnings panel that includes open-relay detection) and the per-account rule criteria and action editor are validated and wired into navigation. Windows x64 only: one installer, hMailServer-6.2.5-x64.exe, bundling the server, the Control Panel and the .NET 8 Desktop Runtime bootstrapper. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    53 Views
    ProgressiverobotP
    The Control Panel gained a read-only Active Directory browser, which was the last functional-parity item left from the classic Administrator. The whole product is stamped 6.2.4: the server, the Control Panel window header and About page, and the installer all report the same version. Active Directory account pickers Services/ActiveDirectoryService.cs enumerates every domain in the current forest from the RootDSE defaultNamingContext and the Partitions container's domain crossRefs, so there is no dependency on System.DirectoryServices.ActiveDirectory. A domain's users are searched with a single LDAP-escaped DirectorySearcher matching sAMAccountName, displayName, mail and userPrincipalName. It is built on System.DirectoryServices, which net8.0-windows resolves from the Windows Desktop shared framework the installer already bundles. On a machine that is not domain-joined it reports the reason instead of throwing. Account then Directory carries "Browse Active Directory…". The picked account fills ADDomain and ADUsername and ticks linked to Active Directory. Distribution-list recipients gained "Add from AD…", which multi-selects accounts and imports their e-mail addresses into the list. Validated end to end against a live domain controller (progressiverobot.local): domain enumeration, the all-users query and the name and e-mail filters all returned the expected results. Other changes A generic TargetInvocationException from the server is now unwrapped and the real cause explained: connect with the server-administrator account, or the server cannot reach its database. That is what produced the misleading "26 settings could not be read" message on the Protocols page over a non-admin connection. The vendored MariaDB Connector/C client (libmysql.dll and its auth plugins) is staged into the build output by the server post-build step, so MySQL and MariaDB back ends work out of the box. The About page carries maintainer and company details. The Control Panel requires the .NET 8 Desktop Runtime, which the installer bundles and installs silently when missing. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    64 Views
    ProgressiverobotP
    6.2.3 is the first server-focused release since 6.2.2, which shipped Control Panel changes against an unchanged server. The headline is a complete Sieve filtering subsystem (RFC 5228) with an optional ManageSieve service (RFC 5804), running alongside the existing proprietary rules engine. Every new behaviour is additive and default-off, so an existing installation upgraded with no functional change until the new settings were turned on. What the upgrade involved The installer no longer ships the classic Administrator. The .NET 8 Control Panel is the sole bundled GUI and needs the .NET 8 Desktop Runtime, which the installer carries and installs silently when missing. DBSetup, DBUpdater and the Data Directory Synchronizer are retained. Sieve and ManageSieve RFC 5228 parser covering if/elsif/else/stop, the core tests (header, address, exists, size, allof, anyof, not, with :is/:contains/:matches), address parts, the default and i;octet comparators, and keep/fileinto/discard/redirect plus implicit keep. Evaluated during local delivery. An account with no script has zero overhead. An unparseable script is logged and falls through to keep rather than breaking delivery. Scripts stored per account under {DataDirectory}\Sieve\{domain}\{localpart}\ and exposed as Account.SieveScript, Utilities.CheckSieveSyntax and Utilities.EvaluateSieveScript. The account dialog gained a Sieve editor tab. ManageSieve listener on [Settings] ManageSieveServerPort, disabled by default, with SASL PLAIN against the normal account database. SMTP BATV (prvs) backscatter protection, wire-only so SPF and DKIM stay aligned. Off by default via BATVEnabled / BATVSecret. CHUNKING / BDAT (RFC 3030). DATA after BDAT is rejected 503, a non-numeric chunk size 501. The existing DATA path is untouched. Operability /livez, /readyz and /healthz on the metrics listener, plus Prometheus series for pool state, query latency, TLS handshakes, auth success and failure, delivery outcomes and command latency. New keys, all defaulting to 0: SlowQueryLogMilliseconds, ShutdownDrainSeconds, MessageStoreFsync, MessageStoreConsistencyCheck, LogDeleteDays. The Received header now carries an RFC 5321 id clause equal to the numeric TCP session id, and that id prefixes every line of the session log. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    59 Views
    ProgressiverobotP
    The server binary is unchanged from the original 6.2.2. Everything new in this installer, apart from two pieces of authentication hardening, is a substantial upgrade to the Control Panel, the .NET 8 admin app. Server Full RFC 4013 SASLprep for non-ASCII SASL credentials: RFC 3454 mapping, Unicode NFKC normalization, the complete prohibited-output tables (C.2.1/C.2.2, C.3 to C.9) and the RFC 3454 section 6 bidirectional check. NFKC is a no-op on ASCII, so existing credentials are unaffected. Automated RS256 public-key OAuth2 bearer-token regression coverage over POP3 and SMTP, including a tampered-signature rejection check. Control Panel A new Advanced hardening page exposes previously hidden hMailServer.INI knobs: greylisting expiration, SpamAssassin and ClamAV scanner timeouts, DNS cache/server/DNSBL timing, authenticated-user IP replacement, the AUTH disable list, X-AuthUser and X-OriginalRcptTo headers, blocked-IP hold, envelope-from rewrite, and a password-hash-algorithm picker covering Argon2id, PBKDF2, SHA-256, MD5 and Blowfish. The anti-virus page gains live "Test ClamAV connection", "Test ClamWin scanner" and "Test custom scanner" checks, a preset picker for Microsoft Defender, Sophos, ESET, Bitdefender and Kaspersky, and ClamWin auto-detect. Event scripts get an "Insert template" picker with ready-made OnAcceptMessage handlers for an external AV/DLP scanner, a SIEM/Slack/Teams webhook and an external HTTP API verdict. Search and filter on the long list pages: Domains, Accounts, Rules, Delivery queue, TCP/IP ports, SSL certificates, IP ranges and Routes. Deleting aliases, distribution lists, list recipients and incoming relays now prompts for confirmation, and the Domain, Account and Route dialogs report bad numeric input instead of dropping it silently. Cached settings pages refresh on navigation, empty and error placeholders are standardised across the list and grid pages, and the overloaded Advanced group is split into Security, Network and Maintenance. Unhandled errors are logged to %LOCALAPPDATA%\hMailServer\ControlPanel with a restart offered. Screen-reader names on icon-only controls, search boxes and the navigation tree, and a stable AutomationId on every navigation node and data-driven settings editor, took the in-app UI-automation audit from grade F to grade A. Builds clean at 0 warnings and 0 errors. The Control Panel requires the .NET 8 Desktop Runtime, which the installer bundles. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    52 Views
    ProgressiverobotP
    hMailServer 6.2.0 introduces the hMailServer Control Panel, a new desktop administration application shipped alongside the full 6.x server. The .NET 8 Desktop Runtime is bundled and installed automatically when it is missing, so there are no separate downloads. The Control Panel A .NET 8 WPF application with Fluent/Windows 11 design (Mica window), light and dark themes, animated live charts, and the familiar navigation tree from the classic Administrator: Welcome, Status, Domains, Rules, Settings > Advanced, Utilities. Animated dashboard with KPI cards plus live delivery-throughput and session charts. Domains and accounts, with an account editor for quota, password, forwarding and vacation, plus aliases and distribution lists with member management. Delivery queue with Deliver now and Remove, plus live log streaming. Rules with a graphical IF/THEN editor covering criteria and actions. Settings: Protocols, Delivery, Routes, Anti-spam (SPF/DKIM/DMARC/greylisting/SpamAssassin), Anti-virus, Logging. Advanced: Auto-ban and SSL/TLS, Performance and scripting, SSL certificates, TCP/IP ports, IP ranges with a permission editor, Incoming relays, and DANE/DNSSEC, MTA-STS, ARC, TLS-RPT, ACME, REST API, web services and metrics. Utilities: Backup and restore, MX query, Server sendout, Diagnostics. Ctrl+K command palette, guaranteed text contrast, consistent spacing. The classic Administrator remains included. So does the Web Control Deck, the browser admin served at the REST listener root. Quality Server core 6.2.0 build 6 was validated by the full regression suite: 898/898 tests passing, zero failures, on a MariaDB backend with live SpamAssassin and ClamAV and TLS 1.2/1.3 end to end. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    48 Views
    ProgressiverobotP
    6.1.0 is a user interface release. It adds the Web Control Deck, a web admin UI served directly by the built-in REST API listener, and rebuilds the desktop Administrator around a full light/dark theme engine. The server core is unchanged from 6.0.0 build 4 apart from the new web-page endpoint. Web Control Deck Enable RestApiPort in hMailServer.INI and browse to the server. No extra components are required. It carries a live dashboard with animated counters and session stats, domain and account management, retry and delete on the delivery queue, and publish-ready DANE TLSA records. Light and dark themes with a toggle. Sign-in uses the administrator credential. Administrator (desktop) Deep-space dark and clean light palettes applied across every pane and dialog, including dark window title bars, native dark scrollbars and themed menus Theme toggle in the View menu. It follows the Windows app-mode preference by default, and the choice is persisted Ctrl+K command palette, fuzzy-searching every settings page and jumping straight to it Modernised dashboard with glow accents, eased value animations and hover-highlight stat cards Installer Modern wizard branding, and it ships the WebAdmin payload. The release was validated by the full regression suite: 898/898 tests passing, zero failures, against a MariaDB backend with live SpamAssassin and ClamAV and TLS 1.2/1.3 end to end. Full release notes, checksums and signatures