hMailServer 6.2.15

Built 11 August 2026 6.2 series

This is not the current release. hMailServer 6.3.3 is the one to install unless you need this exact version.

Downloads for 6.2.15

Windows

Windows 10 (version 1607 or later) and Windows 11, or Windows Server 2016 and newer; 64-bit only. Run the installer as an administrator: it upgrades an installation older than this version in place, and it cannot go backwards — an older server refuses a database a newer one has upgraded, so back up the database and the data directory first. It is not Authenticode-signed, so Windows names an unknown publisher and SmartScreen warns before it will run it.

  • hMailServer-6.2.15-x64.exex64 · 71.8 MB
    Download
    SHA-25635e7226cf446…fabe1e88

What’s new in 6.2.15

A correctness release built around two themes: IMAP sequence sets now behave the way RFC 3501 defines them, and every file the server writes now has an owner — several paths could leave a file on disk that no database row referred to, or leave a delivery retrying forever against a file it could never send. Everything raised on the forum by RvdH is incorporated. No database change (schema version 6005).

Full release notes for 6.2.15 6 sections

Download hMailServer-6.2.15-x64.exe below. Validated by the full regression suite: 1040 of 1040 passing, zero failures — with live SpamAssassin and ClamAV, DMARC against live DNS, and TLS 1.2/1.3 end to end. Nothing skipped.

IMAP sequence sets

  • * means "the largest message number or UID in the mailbox". hMailServer only recognised it as the end of a range; anywhere else it was parsed as the number zero. Separately, RFC 3501 states a range is valid in either order — 3:1 is the same set as 1:3 — and that was not implemented at all. Together these produced results that were wrong in both directions, silently:
Command6.2.146.2.15
FETCH * / UID FETCH *returned nothing, answered OKthe newest message
UID STORE *:* +FLAGS (\Deleted)flagged every message in the mailboxflags the newest message
UID EXPUNGE *deleted every \Deleted messageexpunges the one addressed
FETCH *:1matched only message 1the whole mailbox
FETCH 3:1matched nothingthe same set as 1:3

All four sequence-set parsers in the server (the FETCH/STORE/COPY/MOVE path, SEARCH, UID EXPUNGE, and the QRESYNC VANISHED path) now resolve * on either side of a colon and normalise descending ranges. * in an empty mailbox matches nothing and the command still succeeds. Twelve regression tests cover this; all twelve fail against 6.2.14.

A failed restore could destroy the data directory

Restoring messages deleted everything in the live data directory first and only then copied the backup's message store into place — and the copy throws when its source is not there. That is exactly what a settings-only backup restored with the messages option ticked looks like, and what a failed extraction produces (the result of unpacking the archive was never checked). The exception unwound into a handler that logged and swallowed it, so the temporary folder holding the extracted mail was never cleaned up either. The administrator was left with an empty data directory and the only surviving copy of their mail inside a folder named after a GUID.

The restore now confirms the replacement message store exists before deleting anything. If the copy fails after that point — when the data directory has legitimately already been emptied — the extracted copy is deliberately kept rather than deleted, and the log says where it is. Files with no owner, and deliveries that could never succeed

  • A message whose file could not be read hung the outbound connection. After the remote server answered 354, nothing was sent; the session sat idle until the client timeout — up to ten minutes — before the message was re-queued and the whole attempt repeated. It now fails immediately with a logged error, and the connection is dropped rather than sent QUIT (after 354, a QUIT would be read as message content). Only a file that has genuinely disappeared fails the delivery permanently: one that merely could not be opened right now — held by an on-access scanner or a backup — stays queued, because a permanent failure deletes the recipients and bounces the message.
  • A rejected RETR on an external POP3 account created an empty message file every time. One more orphan in the data directory per occurrence.
  • Rewriting a message's headers left a .eml.tmp behind whenever it failed. This runs for every DKIM signature, ARC seal, local delivery and SpamAssassin result, so a full disk or a scanner-locked file dropped one orphan per message into the account's folder — invisible to the consistency check, which looks for database rows with no file rather than files with no row.
  • A downloaded message with no local recipients left its file behind too, and recorded the UID so it would never be fetched again. The file is now removed and the discard logged, so a misconfigured external account is visible rather than silently accumulating.
  • A bounce that could not be sent left its file in the queue directory.
  • The account cache had no size limit. A duplicated line gave the domain cache its 10 MB cap twice and the account cache none, so it grew unbounded until restart.

From the forum

Raised by RvdH, and all correct

  • BOOST_USE_WINAPI_VERSION was left at 0x0601, holding Boost to the Windows 7 API surface on a build targeting Windows 10 1607 everywhere else. Now 0x0A00, with the README's Boost build line corrected to match.
  • Our AsyncReadCompleted rework predated upstream's replacement of the same code, and upstream's is better: it replaced a SpamAssassin-port check with a general rule for when an EOF is a legitimate end of input. That rule is now in place, with this fork's additions (BDAT exact-length reads, the wedged-connection fix, TCP_NODELAY, the SNI error-code fix) kept on top.
  • Adopting it exposed a defect in our exact-length reads, found by an adversarial review of this release and fixed before it shipped. transfer_exactly guarantees the requested octet count only while any error ends the session; once an end-of-stream is tolerated it does not, and the BDAT path still extracted the count it had asked for rather than what arrived. A sender that announced BDAT 100000 LAST and vanished after 40,000 octets had the remainder padded with NUL bytes, the chunk counted as complete, and the truncated message delivered. Reads now take only what actually arrived, and no read is re-armed after an end-of-stream. A regression test covers it.
  • DKIM signing hashed the header name in lower case while writing it capitalised (upstream PR #530). Under simple header canonicalization the two must match exactly, so signatures produced that way could not verify against a strict verifier. The same PR's MIME integer-overflow fix is included.

For the recurring "what did this fork actually change?" question: of the 980 server source files present in both this fork and official master, 936 are byte-identical (95.5%) once the fork's copyright line is discounted. 44 differ and 30 are new.

Also fixed

  • ManageSieve had no limit on authentication attempts — unlike SMTP, IMAP and POP3, a client could try passwords indefinitely. It now disconnects after three failures and registers them with auto-ban.
  • STATUS ... (RECENT) reported the selected folder's count for every folder asked about, so clients polling all folders lit up new-mail indicators on folders that had received nothing.
  • The SMTP DATA path now logs, under debug logging, how many bytes arrived, how many are buffered and whether the end-of-data marker has been seen. This is diagnostic groundwork for #18, which is not fixed and remains open — see #20.

Control Panel

6.2.14 moved settings that were on the wrong page. This release covers settings that were on no page — configurable in hMailServer.ini but invisible in the GUI.

  • Security ▸ Authentication (new): OAuth2, password hash algorithm and minimum accepted algorithm, password pepper, AUTH exemption list.
  • Security ▸ Administrative access (new): administrator password, and an entry point for two-factor setup — which previously existed only on the pre-logon Connect screen, so once signed in there was no way to reach it.
  • Network ▸ DNS resolver (new): DNS server override, DNS cache, DNSBL timing.
  • Network ▸ Web services & autoconfiguration (new): the HTTP/HTTPS listener, client autoconfiguration and MTA-STS policy hosting, kept together because autoconfig is served only by that listener.
  • Advanced ▸ Copies of mail: message archiving, beside mirroring.
  • Backup & restore: BackupMessagesDBOnly, which changes what a backup and a restore contain.
  • Diagnostics now shows what the message-store consistency scan found — how many message rows have no file on disk, when the scan last ran, the affected messages, and a button to open the full recovery report. That scan is a background task with no COM interface, so its result previously existed only in a file in the log folder, a Prometheus gauge and one log line.

Four labels described the wrong thing and were corrected — UseDNSCache, DaemonAddressDomain, LogLevel, and DisableAUTHList (labelled as semicolon-separated IP addresses; it is a comma-separated list of local TCP ports). Two Control Panel bugs went with them: the Anti-virus page always reported "N settings could not be written" (it was counting its own buttons), and the Logging page rendered three tabs all headed "Logging".

Release facts

Version
6.2.15
Packages
1Windows, x86-64
Database schema
6005upgrades in place
Installer SHA-256
35e7226cf446…fabe1e88hMailServer-6.2.15-x64.exe

Every file in 6.2.15

Full SHA-256 of each file as recomputed on this server. The SBOM is not needed to install; it lists every component in the build. Nothing in this release is signed — the signing workflow came later — so the hash above is this server’s own recomputation rather than a check against something the project signed.

FileWhat it isSizeSHA-256Signature
hMailServer-6.2.15-x64.exeWindows installer · x6471.8 MB35e7226cf446635100e2aeb2901e15317cf406b79609d6fd4c1a6c68fabe1e88
hmailserver.spdx.jsonSBOM (SPDX)Every component in the build, in SPDX JSON.92 KBff0abfeba39ed7bd5530564c99bc30a6c4d03ee8b4569a83b1c73fe748c7851e
hmailserver.cyclonedx.jsonSBOM (CycloneDX)The same inventory in CycloneDX JSON.48 KB9cadeb26c0d2c16de10b1be3e7da8e902f6333fecb2590cd6ac286e1440f99c1