<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[IP ranges, auto-ban, lockout, tarpits, sending limits, send-as and password storage]]></title><description><![CDATA[<p dir="auto"><em>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 <a href="/topic/28277">the 6.3.7 announcement</a>. 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 <code>WebServicesTrustedProxies</code> 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 <a href="/topic/28278">the 6.3.8 announcement</a>.</em></p>
<p dir="auto">This topic covers who may use this server and how hard it is to abuse it. Know this first: <strong>only the IP ranges and auto-ban work out of the box; every other brake here is off until you set it.</strong> 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 <a href="/topic/28241">Hardening a public mail server</a>.</p>
<h3><a class="anchor-offset" name="where-each-one-is-set"></a>Where each one is set</h3>
<p dir="auto">Since 6.3.4 the database is the settings store, and for a key it holds, a <code>[Settings]</code> line edited in <code>hMailServer.ini</code> 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 <a href="/topic/28222">the settings topic</a>.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>What</th>
<th>Kept in</th>
<th>Set with</th>
<th>Takes effect</th>
</tr>
</thead>
<tbody>
<tr>
<td>IP ranges</td>
<td>the database</td>
<td>Control Panel <strong>Access &amp; abuse protection → IP ranges</strong>; the Control Deck's IP ranges view; <code>/api/v1/ipranges</code>; <code>hmctl iprange</code>; COM <code>Settings.SecurityRanges</code></td>
<td>at once</td>
</tr>
<tr>
<td>Auto-ban's four settings</td>
<td>the database</td>
<td>Control Panel <strong>Access &amp; abuse protection → Auto-ban</strong>; the Deck's settings; <code>PUT /api/v1/settings</code>; COM</td>
<td>at once</td>
</tr>
<tr>
<td>Lockout, tarpits, rate limit, send-as check, hashing, policy</td>
<td>the settings store, under their <code>[Settings]</code> names</td>
<td>Control Panel; <code>PUT /api/v1/settings/ini/{name}</code>; <code>hmctl ini set &lt;name&gt; &lt;value&gt;</code>; COM <code>Settings.SetIniSetting</code>; on Linux <code>hmailserver --set-setting NAME=VALUE</code></td>
<td>when saved</td>
</tr>
<tr>
<td><code>[SendingLimits]</code>, <code>[SendingLimitsOverrides]</code>, <code>PasswordPepper</code></td>
<td><code>hMailServer.ini</code> only</td>
<td>the file, by hand or through the Control Panel (below)</td>
<td>sending limits within seconds; the pepper after a restart</td>
</tr>
</tbody>
</table>
<p dir="auto">The Control Panel and COM are Windows-only. Of these <code>[Settings]</code> keys the Deck edits only <code>SmtpTarpitCount</code> and <code>SmtpTarpitDelaySeconds</code>. A value set with <code>hmailserver --set-setting</code> while the service runs waits for the next save, reinitialise or restart.</p>
<h3><a class="anchor-offset" name="ip-ranges-priority-and-the-relay-grid"></a>IP ranges: priority and the relay grid</h3>
<p dir="auto">When a client connects, every range containing its address is found and <strong>the highest priority wins</strong>. The shipped ranges are <em>Internet</em> (priority 10, <code>0.0.0.0</code>–<code>255.255.255.255</code>) and <em>My computer</em> (priority 30, <code>127.0.0.1</code>); a range added on the Control Panel's page starts at 15, so a narrow range sits in front of <em>Internet</em> without editing it.</p>
<p dir="auto">At every <code>RCPT TO</code> two decisions are made, in order: may this combination be delivered at all (if not, <code>550 Delivery is not allowed to this address.</code>), and must the client authenticate first (if so, <code>530 SMTP authentication is required.</code>). "Local" and "remote" describe the <strong>addresses</strong>, not the client: an address is local when its domain is a hosted active domain or a route says so.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Combination</th>
<th>REST fields: allowed / auth required</th>
<th><em>Internet</em></th>
<th><em>My computer</em></th>
</tr>
</thead>
<tbody>
<tr>
<td>Local → local</td>
<td><code>deliver_local_to_local</code> / <code>require_auth_local_to_local</code></td>
<td>allowed, <strong>auth required</strong></td>
<td>allowed, no auth</td>
</tr>
<tr>
<td>Local → remote</td>
<td><code>deliver_local_to_remote</code> / <code>require_auth_local_to_remote</code></td>
<td>allowed, <strong>auth required</strong></td>
<td>allowed, no auth</td>
</tr>
<tr>
<td>Remote → local</td>
<td><code>deliver_remote_to_local</code> / <code>require_auth_remote_to_local</code></td>
<td>allowed, no auth</td>
<td>allowed, no auth</td>
</tr>
<tr>
<td>Remote → remote (relay)</td>
<td><code>deliver_remote_to_remote</code> / <code>require_auth_remote_to_remote</code></td>
<td>allowed, <strong>auth required</strong></td>
<td>allowed, <strong>auth required</strong></td>
</tr>
<tr>
<td>Anti-spam, anti-virus</td>
<td><code>spam_protection</code>, <code>virus_protection</code></td>
<td>on</td>
<td>on</td>
</tr>
<tr>
<td>Require TLS for auth</td>
<td><code>require_tls_for_auth</code></td>
<td>on in a new 6.3.4 installation; otherwise as the server had it</td>
<td>off</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>Remote → remote is the open-relay box.</strong> Both shipped ranges allow it with authentication required, even from 127.0.0.1, so a client that has not signed in gets <code>530</code>; a range that does not allow it at all gets <code>550</code>. The Control Panel's Server status page raises a Critical warning for any range that allows it without authentication. <strong>Remote → local</strong> is inbound mail and must need no authentication. <strong>Local → local</strong> needs it on <em>Internet</em> so that nobody outside can forge mail from one of your addresses to another.</p>
<p dir="auto"><strong>The protection switches reach further than their names.</strong> Clearing <em>Enable anti-spam</em> turns off every spam test, greylisting and the recipient tarpit for the range; clearing <em>Enable anti-virus</em> 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.</p>
<p dir="auto"><strong>Require TLS for auth belongs to the range, not the port.</strong> With it set, <code>AUTH</code> is not advertised on a cleartext connection from that range, on SMTP, POP3, IMAP and ManageSieve.</p>
<p dir="auto"><strong>A device that cannot sign in</strong> gets a range of its own above <em>Internet</em>. For a scanner at 192.0.2.50 that sends from your domains to your own mailboxes only:</p>
<pre><code class="language-bash">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
</code></pre>
<p dir="auto"><code>hmctl iprange update &lt;id&gt;</code> and <code>PUT /api/v1/ipranges/{id}</code> (since 6.3.3) change any subset of the fields. The routes refuse a domain-restricted API key; a role needs <code>manage_settings</code>. <strong>The Control Panel's Restore defaults</strong> (<code>SecurityRanges.SetDefault()</code>) discards every range, your own and the auto-ban ones, and writes back the two shipped ones as the create scripts make them, without <em>Require TLS for auth</em>.</p>
<h3><a class="anchor-offset" name="auto-ban-and-why-its-ranges-sit-at-priority-100"></a>Auto-ban, and why its ranges sit at priority 100</h3>
<p dir="auto">Auto-ban counts failed logons per <strong>connecting address</strong>; SMTP <code>AUTH</code>, 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 <code>127.0.0.0/8</code>, and <code>::1</code>), nor the web services listener, for one from loopback or an address in <code>WebServicesTrustedProxies</code>, 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 <code>127.0.0.1</code>, which could then be refused at the SMTP, POP3, IMAP and ManageSieve listeners; on 6.3.2 to 6.3.7 <code>AutoBanNeverBan</code> with <code>127.0.0.1, ::1</code> avoids it. <strong>Behind a reverse proxy on the same machine</strong> (the Linux package binds REST to <code>127.0.0.1</code>), 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.</p>
<p dir="auto">At the limit auto-ban clears that address's counted failures, creates an expiring range named <code>Auto-ban: &lt;user&gt;</code> at <strong>priority 100</strong>, and disconnects; SMTP says <code>535 Authentication failed. Too many invalid logon attempts.</code> Priority 100, above both shipped ranges, is what makes a ban effective; <code>AutoBanNeverBan</code>, below, exempts an address.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Setting (COM name)</th>
<th>Default</th>
<th>Trap</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>AutoBanOnLogonFailure</code></td>
<td>on</td>
<td>—</td>
</tr>
<tr>
<td><code>MaxInvalidLogonAttempts</code></td>
<td>3</td>
<td><strong><code>0</code> disables auto-ban entirely</strong>, whatever the switch says</td>
</tr>
<tr>
<td><code>MaxInvalidLogonAttemptsWithin</code></td>
<td>30 minutes</td>
<td>Not a sliding window: how long a failure record survives, deleted by a pass every minute that runs only while auto-ban is on</td>
</tr>
<tr>
<td><code>AutoBanMinutes</code></td>
<td>60</td>
<td><strong><code>0</code> disconnects the client but creates no range</strong>, so nothing is banned</td>
</tr>
</tbody>
</table>
<p dir="auto">Their REST keys include <code>auto_ban_on_logon_failure</code> and <code>max_invalid_logon_attempts</code>. The <code>office</code> profile (since 6.3.4) raises the limit to 5.</p>
<ul>
<li><strong><code>AutoBanNeverBan</code></strong> (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 <code>HM6524</code>. Server status warns "Localhost is currently banned in the IP ranges." when a ban covers 127.0.0.1.</li>
<li><strong>Control Panel sign-in over COM</strong> is outside auto-ban and lockout, so guessing an administrator's mailbox name cannot lock them out of the tool.</li>
<li><strong>Spam traps and the multi-recipient null-sender check</strong> ban through the same ranges (<code>Auto-ban: spam trap &lt;address&gt;</code>, <code>Auto-ban: multi-recipient null sender &lt;address&gt;</code><img src="https://www.hmailserver.co.uk/assets/plugins/nodebb-plugin-emoji/emoji/android/1f61e.png?v=6eecd33477c" class="not-responsive emoji emoji-android emoji--disappointed" style="height:23px;width:auto;vertical-align:middle" title="):" alt="😞" /> see <a href="/topic/28249">Allow and block lists</a> and <a href="/topic/28248">the anti-spam stack</a>. Firewall bans (<code>AutoBanFirewall</code>, <code>AutoBanCommand</code>, fail2ban) are in <a href="/topic/28220">Reading the logs</a>.</li>
</ul>
<p dir="auto"><strong>Releasing a banned address.</strong> <strong>Clear logon-failure list</strong> (<code>POST /api/v1/settings/logon-failures/clear</code>, COM <code>Settings.ClearLogonFailureList()</code>) clears counted failures only, for every address at once; a ban stays until its range expires. To release one now:</p>
<ol>
<li>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.</li>
<li>Find the range: the IP ranges page, the Deck's IP ranges view, <code>hmctl iprange list</code> or <code>GET /api/v1/ipranges</code>. Its name begins <code>Auto-ban:</code> and its priority is 100.</li>
<li>Delete it: on the page, <code>hmctl iprange delete &lt;id&gt;</code>, or <code>DELETE /api/v1/ipranges/&lt;id&gt;</code>. With <code>AutoBanFirewall</code> on, the firewall is reconciled on every range deletion, so its rule goes too.</li>
</ol>
<p dir="auto">Five error-log codes mean the control has quietly stopped working:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Code</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>HM6114</code></td>
<td>A failed logon could not be recorded, so no ban will trigger while this persists</td>
</tr>
<tr>
<td><code>HM6099</code></td>
<td>The auto-ban range could not be saved: the address has <strong>not</strong> been blocked</td>
</tr>
<tr>
<td><code>HM6113</code></td>
<td>Spent failures could not be cleared, so the address may be banned again as soon as its ban expires</td>
</tr>
<tr>
<td><code>HM6112</code></td>
<td>Expired IP ranges could not be removed, so an expired ban keeps blocking</td>
</tr>
<tr>
<td><code>HM6115</code></td>
<td>Expired failures could not be cleared, so occasional failures may add up to a ban</td>
</tr>
</tbody>
</table>
<h3><a class="anchor-offset" name="account-lockout-by-name"></a>Account lockout, by name</h3>
<p dir="auto">A distributed attack never crosses any one address's threshold. Lockout counts the <strong>name</strong> being guessed at, across SMTP <code>AUTH</code>, POP3, IMAP, ManageSieve, REST and the webmail's sign-in. It is off until set; the <code>office</code> profile sets 10.</p>
<pre><code class="language-ini">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
</code></pre>
<ul>
<li><strong>It counts names, not accounts</strong>, so a nonexistent name locks as a real one would, and reveals nothing.</li>
<li><strong>A locked name is refused before the password is checked</strong>, with the ordinary invalid-credentials reply; only its timing differs, deliberately.</li>
<li><strong>A lockout refusal is not charged to the connecting address</strong>, so an owner retrying from an office NAT does not get everyone behind it auto-banned.</li>
<li><strong>Passkeys and single sign-on are not counted</strong>, being no guesses.</li>
<li><strong>To lift one early</strong>: <code>POST /api/v1/accounts/{address}/unlock</code>, which a help desk scoped to the account's domain may call, COM <code>Application.UnlockAccount</code>, or <strong>Unlock</strong> on the Deck's Accounts row. A password reset clears it too.</li>
</ul>
<h3><a class="anchor-offset" name="tarpits-and-the-submission-rate-limit"></a>Tarpits and the submission rate limit</h3>
<p dir="auto">All <strong>0, off, until set</strong>; these values are a starting point.</p>
<pre><code class="language-ini">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
</code></pre>
<ul>
<li><strong>The logon tarpit</strong> (Auto-ban page) makes a failed logon's refusal wait <code>LogonTarpitSeconds</code> times the failures so far on that connection, on SMTP, POP3 and IMAP. <strong>A correct password never waits.</strong></li>
<li><strong>The recipient tarpit</strong> (Anti-spam settings page; COM <code>AntiSpam.TarpitCount</code> and <code>AntiSpam.TarpitDelay</code>; REST <code>tarpit_count</code> and <code>tarpit_delay</code> on <code>/api/v1/settings/antispam</code>) spares authenticated sessions and ranges with anti-spam off.</li>
<li><strong><code>MaxSubmissionsPerIPPerMinute</code> counts every <code>MAIL FROM</code>, authenticated or not</strong>, and refuses the excess with <code>421 Too many messages from your IP address</code>, which contains a compromised account. The <code>office</code> profile sets 60; <code>gateway</code> keeps 0, since all inbound mail comes from the gateway's few addresses. Since 6.3.4 a save restarts its one-minute window.</li>
</ul>
<p dir="auto">Behind a load balancer, give the SMTP listener <code>SMTPProxyProtocolEnabled</code> with <code>SMTPProxyProtocolTrustedIPs</code> (or <code>XCLIENT</code>), or auto-ban, the rate limit and the ranges all reason about the proxy's address: see <a href="/topic/28240">Behind a gateway or reverse proxy</a>.</p>
<h3><a class="anchor-offset" name="per-account-sending-limits"></a>Per-account sending limits</h3>
<p dir="auto">The brake on a compromised account, counted against the <strong>authenticated user name</strong> (never <code>MAIL FROM</code>) over a rolling period. The server level stays in the file:</p>
<pre><code class="language-ini">[SendingLimits]
MaxMessagesPerAccountPerPeriod=500
MaxRecipientsPerAccountPerPeriod=2000
PeriodHours=24                   ; clamped to 1-168
StateSaveIntervalSeconds=10      ; clamped to 1-3600

[SendingLimitsOverrides]
newsletter@yourcompany.com=5000:50000
ceo@yourcompany.com=0:0
</code></pre>
<p dir="auto">Both limits default to 0, no limit; recipients are the stricter measure. An override replaces the global pair for that address, <code>0:0</code> 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 <code>C:\Program Files\hMailServer\Bin\hMailServer.INI</code> with an elevated editor, or use the Control Panel's <strong>Maintenance → Server limits &amp; expert settings</strong> on the server itself; on Linux, <code>sudoedit /etc/hmailserver/hMailServer.ini</code>. They are not in the settings store, so no environment variable or setting profile writes them.</p>
<p dir="auto"><strong>What the sender sees</strong>: <code>452 4.7.0 Sending limit for this account has been reached. Please try again later.</code> at <code>MAIL FROM</code>, or <code>452 4.5.3 Recipient sending limit for this account has been reached. Please try again later.</code> at <code>RCPT TO</code>. The session stays open, the refusal spends no budget, and the application log, not the error log, says <code>SendingLimit refused submission</code>. Counters survive a restart in <code>hmailserver_sendinglimits.dat</code> in the data directory. <strong>It fails open</strong>: an unreadable file, a limiter exception or a full table of tracked accounts (error 5813) lets the message through.</p>
<p dir="auto"><strong>Since 6.3.4 there are three levels.</strong> A domain and an account may hold <code>sending_max_messages</code> and <code>sending_max_recipients</code>, which <strong>tighten</strong> the level above and never loosen it; an address's override line is its server level. Set them on the <strong>Levels</strong> tab of the domain and account dialogs, in the Deck's editors, with <code>PUT /api/v1/accounts/{address}</code>, or <code>hmctl account set &lt;address&gt; sending_max_messages 100</code> (<code>inherit</code> 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 <code>429</code>; a scheduled draft is not counted when it goes.</p>
<h3><a class="anchor-offset" name="who-may-send-as-whom"></a>Who may send as whom</h3>
<p dir="auto"><code>SmtpAuthenticatedSenderCheck</code> (Control Panel <strong>Connections &amp; protocols → Protocols</strong>, 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 <code>office</code> and <code>gateway</code> profiles set it to 1. Turned on, it applies to every authenticated session, whose <code>MAIL FROM</code> must then be:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Kind</th>
<th>Given by</th>
</tr>
</thead>
<tbody>
<tr>
<td>The account's own address</td>
<td>always</td>
</tr>
<tr>
<td>An alias resolving to it, up to five hops</td>
<td>the administrator</td>
</tr>
<tr>
<td>A mailbox whose owner granted the <strong>post (<code>p</code>) right on their INBOX</strong></td>
<td>that owner, with any IMAP client's <code>SETACL</code></td>
</tr>
<tr>
<td>An address elsewhere proved by a code mailed to it (since 6.3.4)</td>
<td>the person, in the webmail's <em>Settings, Other accounts, Send mail as</em></td>
</tr>
<tr>
<td>A masked address the account made, while it is on (since 6.3.4)</td>
<td>the person, in the webmail's <em>Settings, Masked addresses</em></td>
</tr>
</tbody>
</table>
<p dir="auto">Anything else is refused <code>550 5.7.1</code> 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. <strong>The post right counts only while IMAP ACL enforcement is on</strong> (<code>enableimapacl</code>, on by default). Before turning the check on, grant <code>p</code> 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.</p>
<h3><a class="anchor-offset" name="how-passwords-are-stored"></a>How passwords are stored</h3>
<p dir="auto">In the Control Panel, <strong>Access &amp; abuse protection → Authentication</strong>, card <strong>Password storage</strong>. 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.</p>
<pre><code class="language-ini">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
</code></pre>
<ul>
<li><strong>Hashes upgrade at a successful logon, only upward.</strong> Raising the scheme or a work factor re-derives each hash when its owner next signs in; lowering either affects new hashes only.</li>
<li><strong><code>MinimumAcceptedHashAlgorithm</code> set too high is a lockout.</strong> 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.</li>
<li><strong>A work factor out of range</strong> is reported as <code>HM5561</code> and read as 0; <code>HM5607</code> means Argon2id was asked for on a build whose OpenSSL has none, and another scheme is used. Argon2id allocates <code>PasswordHashMemoryKB</code> on a connection thread at every logon.</li>
<li><strong><code>PasswordPepper</code> must be set before accounts exist</strong>: 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 <code>hMailServer.ini</code> only and no backup carries it, so <strong>keep a copy of the value with the backups</strong>: 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 <code>NT SERVICE\hMailServer</code>, or a Linux package installation), COM and REST refuse it: set it with an elevated editor (<code>sudoedit</code> on Linux) and restart the service.</li>
</ul>
<h3><a class="anchor-offset" name="the-password-policy"></a>The password policy</h3>
<p dir="auto">All off until set, applied <strong>where a password is chosen</strong>, never at logon; on Windows under <strong>Access &amp; abuse protection → Administrative access</strong>, Password tab.</p>
<pre><code class="language-ini">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
</code></pre>
<p dir="auto">The <code>office</code> profile sets a minimum of 10 and the common list. <strong>Expiry needs care</strong>: IMAP, POP3 and SMTP cannot change a password and <code>/portal</code> refuses an expired one, so an administrator renews it, or its owner through an app password, which still signs in to <code>/portal</code>. Active Directory accounts are exempt. The breach check is in <a href="/topic/28241">Hardening a public mail server</a>; the rest of sign-in is in <a href="/topic/28253">Signing in</a>.</p>
<h3><a class="anchor-offset" name="what-it-does-not-do"></a>What it does not do</h3>
<ul>
<li>None of it spam-tests your own users: an authenticated session never is.</li>
<li>A setting profile never writes an IP range.</li>
</ul>
<h3><a class="anchor-offset" name="where-to-read-more"></a>Where to read more</h3>
<ul>
<li>Wiki: <a href="https://gitlab.com/hmailserver/hmailserver/-/wikis/Security-Hardening" rel="nofollow ugc">Security Hardening</a> sections 17.1, 17.2, 17.5, 17.7 and 17.9; <a href="https://gitlab.com/hmailserver/hmailserver/-/wikis/Settings-Reference" rel="nofollow ugc">Settings Reference</a> sections 9.1, 9.9 and 10; <a href="https://gitlab.com/hmailserver/hmailserver/-/wikis/Stopping-Spam" rel="nofollow ugc">Stopping Spam</a> section 10.1; <a href="https://gitlab.com/hmailserver/hmailserver/-/wikis/Troubleshooting" rel="nofollow ugc">Troubleshooting</a> sections 19.3 and 19.7.</li>
<li>Documents: <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SettingsApply.md" rel="nofollow ugc">SettingsApply.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SettingLevels.md" rel="nofollow ugc">SettingLevels.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SendAs.md" rel="nofollow ugc">SendAs.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Profiles.md" rel="nofollow ugc">Profiles.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Roles.md" rel="nofollow ugc">Roles.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/ServiceAccount.md" rel="nofollow ugc">ServiceAccount.md</a>.</li>
<li>Public documentation: <a href="https://www.progressiverobot.com/hmailserver-documentation/#securityrange-and-securityranges" rel="nofollow ugc">SecurityRange and SecurityRanges</a>, for the COM names of the range flags.</li>
<li>On this forum: <a href="/topic/28188">Being trusted by the servers you send to</a>, <a href="/topic/28192">The Control Deck</a>, <a href="/topic/28193">Upgrading to 6.3.4</a>, <a href="/topic/28189">hMailServer on Linux</a>.</li>
</ul>
]]></description><link>https://www.hmailserver.co.uk/topic/28239/ip-ranges-auto-ban-lockout-tarpits-sending-limits-send-as-and-password-storage</link><generator>RSS for Node</generator><lastBuildDate>Fri, 06 Nov 2026 09:05:49 GMT</lastBuildDate><atom:link href="https://www.hmailserver.co.uk/topic/28239.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 27 Sep 2026 19:21:13 GMT</pubDate><ttl>60</ttl></channel></rss>