IP ranges, auto-ban, lockout, tarpits, sending limits, send-as and password storage
-
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
WebServicesTrustedProxiesapart; 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 inhMailServer.inichanges 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; COMSettings.SecurityRangesat once Auto-ban's four settings the database Control Panel Access & abuse protection → Auto-ban; the Deck's settings; PUT /api/v1/settings; COMat once Lockout, tarpits, rate limit, send-as check, hashing, policy the settings store, under their [Settings]namesControl Panel; PUT /api/v1/settings/ini/{name};hmctl ini set <name> <value>; COMSettings.SetIniSetting; on Linuxhmailserver --set-setting NAME=VALUEwhen saved [SendingLimits],[SendingLimitsOverrides],PasswordPepperhMailServer.inionlythe 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 onlySmtpTarpitCountandSmtpTarpitDelaySeconds. A value set withhmailserver --set-settingwhile 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 TOtwo 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_localallowed, auth required allowed, no auth Local → remote deliver_local_to_remote/require_auth_local_to_remoteallowed, auth required allowed, no auth Remote → local deliver_remote_to_local/require_auth_remote_to_localallowed, no auth allowed, no auth Remote → remote (relay) deliver_remote_to_remote/require_auth_remote_to_remoteallowed, auth required allowed, auth required Anti-spam, anti-virus spam_protection,virus_protectionon on Require TLS for auth require_tls_for_authon 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 gets550. 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,
AUTHis 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=truehmctl iprange update <id>andPUT /api/v1/ipranges/{id}(since 6.3.3) change any subset of the fields. The routes refuse a domain-restricted API key; a role needsmanage_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 of127.0.0.0/8, and::1), nor the web services listener, for one from loopback or an address inWebServicesTrustedProxies, 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 of127.0.0.1, which could then be refused at the SMTP, POP3, IMAP and ManageSieve listeners; on 6.3.2 to 6.3.7AutoBanNeverBanwith127.0.0.1, ::1avoids it. Behind a reverse proxy on the same machine (the Linux package binds REST to127.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 says535 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 AutoBanOnLogonFailureon — MaxInvalidLogonAttempts3 0disables auto-ban entirely, whatever the switch saysMaxInvalidLogonAttemptsWithin30 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 AutoBanMinutes60 0disconnects the client but creates no range, so nothing is bannedTheir REST keys include
auto_ban_on_logon_failureandmax_invalid_logon_attempts. Theofficeprofile (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 asHM6524. 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, COMSettings.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 listorGET /api/v1/ipranges. Its name beginsAuto-ban:and its priority is 100. - Delete it: on the page,
hmctl iprange delete <id>, orDELETE /api/v1/ipranges/<id>. WithAutoBanFirewallon, 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 HM6114A failed logon could not be recorded, so no ban will trigger while this persists HM6099The auto-ban range could not be saved: the address has not been blocked HM6113Spent failures could not be cleared, so the address may be banned again as soon as its ban expires HM6112Expired IP ranges could not be removed, so an expired ban keeps blocking HM6115Expired 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; theofficeprofile 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, COMApplication.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
LogonTarpitSecondstimes 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.TarpitCountandAntiSpam.TarpitDelay; RESTtarpit_countandtarpit_delayon/api/v1/settings/antispam) spares authenticated sessions and ranges with anti-spam off. MaxSubmissionsPerIPPerMinutecounts everyMAIL FROM, authenticated or not, and refuses the excess with421 Too many messages from your IP address, which contains a compromised account. Theofficeprofile sets 60;gatewaykeeps 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
SMTPProxyProtocolEnabledwithSMTPProxyProtocolTrustedIPs(orXCLIENT), 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:0Both limits default to 0, no limit; recipients are the stricter measure. An override replaces the global pair for that address,
0:0exempts 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 editC:\Program Files\hMailServer\Bin\hMailServer.INIwith 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.atMAIL FROM, or452 4.5.3 Recipient sending limit for this account has been reached. Please try again later.atRCPT TO. The session stays open, the refusal spends no budget, and the application log, not the error log, saysSendingLimit refused submission. Counters survive a restart inhmailserver_sendinglimits.datin 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_messagesandsending_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, withPUT /api/v1/accounts/{address}, orhmctl account set <address> sending_max_messages 100(inheritreturns 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, answering429; 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. Theofficeandgatewayprofiles set it to 1. Turned on, it applies to every authenticated session, whoseMAIL FROMmust 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 INBOXthat owner, with any IMAP client's SETACLAn 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.1before 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, grantpto 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.
MinimumAcceptedHashAlgorithmset 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
HM5561and read as 0;HM5607means Argon2id was asked for on a build whose OpenSSL has none, and another scheme is used. Argon2id allocatesPasswordHashMemoryKBon a connection thread at every logon. PasswordPeppermust 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 inhMailServer.inionly 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 asNT SERVICE\hMailServer, or a Linux package installation), COM and REST refuse it: set it with an elevated editor (sudoediton 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 expireThe
officeprofile sets a minimum of 10 and the common list. Expiry needs care: IMAP, POP3 and SMTP cannot change a password and/portalrefuses 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.
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login