Skip to content

hMailServer 6.3.1

Choose a tag to compare

@RainbowWizard-coder RainbowWizard-coder released this 18 Oct 05:22
· 2812 commits to master since this release

Re-published on GitHub on 18 October 2026 from the GitLab release v6.3.1 of 2026-09-11. Each file below was checked against the SHA-256 that GitLab's package registry records for it before it was uploaded here.

Re-published on GitLab on 24 September 2026 from the GitHub release of 11 September 2026 (2026-09-11 03:44:22 UTC). Issue, pull request and discussion numbers below are GitHub's.

hMailServer 6.3.1

This is the first release of this project to carry an Authenticode signature. The Windows elevation prompt names Progressive Robot Ltd instead of Unknown publisher, and an enterprise policy that refuses unsigned binaries outright stops being a wall.

Nothing in the server changes. The compiled server differs from 6.3.0 by its version stamp and one comment line; everything else in this release is the path a release travels - the workflows that sign and verify it, found wanting while preparing to use the certificate for the first time - and three documentation corrections.


The installer is signed

The installer is signed with Azure Artifact Signing, against a certificate profile issued to Progressive Robot Ltd after Microsoft's identity validation. The account, the validation and the profile were arranged on 10 September 2026, after 6.3.0 had shipped. A published release here is immutable, so 6.3.0 could not be signed retroactively and never will be.

What it changes. The elevation prompt reads the publisher's name. And for administrators on managed estates - a great many of this server's users - a policy that refuses unsigned binaries no longer refuses this one.

What it does not change, said plainly: SmartScreen still warns. Microsoft's own comparison puts a signed installer in the same row as an unsigned one, flagged as unrecognised until reputation accumulates, and reputation attaches to a file that does not change - which a new 80 MB installer every few weeks never is. An EV certificate would not help; Microsoft removed EV's SmartScreen bypass in 2024. Expect the same Windows protected your PC screen, now with the publisher's real name on it.

Only the Windows installer is Authenticode-signed. There is no Authenticode for a .deb, an .rpm or an AppImage. Sigstore is unchanged and remains the check that means something for every asset on the release: each carries a .cosign.bundle beside it, and cosign verify-blob against that bundle verifies it.

One setting becomes usable. UpdateRequireAuthenticode=1 has existed since 6.2.28 and, until now, made the server's own update path refuse every release of this project, because none carried a signature: the check is WinVerifyTrust on the downloaded installer, and an unsigned file is refused with the file carries no Authenticode signature. From 6.3.1 the installer it downloads carries one. The check is Windows-only: on Linux there is no Authenticode to verify, the server says so rather than reporting a pass, and updating is the package manager's job.

The release path

Releases here are immutable, so each of these could have put out a permanently wrong release.

  • The Authenticode gate was checking the wrong four of the six settings it guards. It asked for the three Azure secrets and ARTIFACT_SIGNING_ACCOUNT - the one input the signing action marks optional - and never asked about ARTIFACT_SIGNING_ENDPOINT or ARTIFACT_SIGNING_PROFILE, the two it marks required. Five half-configured states got through, each a state somebody passes through while filling in three repository variables one at a time; the action throws on an empty endpoint, and the cosign job declares a dependency on this one, so a release that tripped it would have got no Authenticode signature and no Sigstore bundle on any of its twenty assets. There are three outcomes now: none of the six set is the ordinary case and stays a silent no-op, all six signs, and anything in between stops and names what is missing while the release can still be fixed. The six values, and the tag, reach the shell through the environment rather than being pasted into the script text, because an expression pasted into a script is executed as syntax if it holds a quote.
  • The release is verified as it is attached, not as it was signed. The old check looked only at the job's own copies. A draft stays mutable afterwards, and four things upload over it with --clobber: a re-run of the Linux publish job, the SBOM workflow, a second Authenticode run, and the hand-recovery commands the Linux job prints into its own log. The workflow now ends by re-downloading the release exactly as it stands and verifying every asset against its attached bundle, in both directions - an asset with no bundle, and a bundle whose asset has gone.
  • What a release must carry is asserted before a certificate is spent on it. The only completeness check was "did we sign at least one thing", and the SBOMs were named nowhere but in comments - which is how 6.2.22-pre4 came to be published with an installer and no SBOM at all. Both SBOMs are a hard failure now, in the Authenticode job rather than the signing job, so an incomplete release stops before a code-signing certificate has been spent on it. The Linux sums file and the four package names stay warnings, deliberately: a Linux packaging failure must not hold back the Windows installer every server in the field is waiting for.
  • An RFC3161 countersignature is required, and is checked. These certificates live about seventy-two hours. Get-AuthenticodeSignature answers Valid for a signature carrying no timestamp for as long as the certificate has not expired, which it never has seconds after signing - so an untimestamped installer would look perfect on the day and stop verifying on every machine in the field three days later, on a release that cannot be corrected. The countersignature is proved before the release asset is replaced, so a timestamping failure costs a re-dispatch and nothing else.
  • Verification can no longer pass vacuously. A glob that matched nothing used to verify nothing and succeed. Both verification steps now refuse to pass having checked zero assets, and compare what they verified against what the signing step reported.
  • Runs are serialised per tag. Two dispatches for one tag could interleave, and one run's bundle could end up describing bytes the other had already replaced. They queue now, and are not cancelled: a run stopped between signing and uploading would leave assets with no signature at all.
  • The SBOM workflow refuses to overwrite an SBOM that has already been signed, because cosign signs the bytes attached when it runs and Syft writes a fresh document identifier every time, so a re-upload after signing leaves a signature that verifies against nothing. It also proves the tree it describes is the tag's own commit before Syft runs - a bill of materials describing a tree the release was not built from is the one thing an SBOM must never do.
  • The installer smoke test can read a draft release, which is the only kind it is ever pointed at. It asked for contents: read, and GitHub shows an unpublished release only to a token with push access, so every dispatch against a draft answered "release not found" - which made the documented order, green before publication, impossible rather than merely awkward. It asks for contents: write now, and writes nothing.
  • The Linux package-install check runs under sudo, like every other command in its step. The package makes /etc/hmailserver 0750 root:hmailserver on purpose, because the configuration holds credentials, so a bare stat answered "Permission denied" and under set -e took the job with it. That is why 6.3.0's tagged run attached no Linux packages and they had to be attached by hand.

All of the above was verified by executing the real run bodies against the live 6.3.0 asset list with gh and cosign stubbed - the twenty-asset release, a re-run over already-attached bundles, a Windows-only release, a pre-release tag, the hand-recovery shape, a release with no SBOMs, an orphaned bundle, an asset excluded from signing by design, and an empty download - and the gate across fifteen configurations, including whitespace-only values and five hostile ones, none of which executed anything. The Authenticode path itself was rehearsed end to end on a throwaway copy of the 6.3.0 installer before this tag was cut: a valid, countersigned signature naming Progressive Robot Ltd, attached to nothing.

Documentation

  • The README offers the Linux packages on its download line, where a reader looks for a download, rather than 140 lines further on in the Linux section. The headline of 6.3.0 was that this server runs on Linux at all.
  • Two files named 6.2.29, a version that does not exist and never will: the [Directories] header comment in the server source, and the relocating guide's note about when a relative path began to resolve against the program folder. Both features shipped in 6.3.0 and both now say so. Comment and prose only.
  • The release checklist gives ARTIFACT_SIGNING_ENDPOINT as a full URI rather than a bare host, which is the form the signing action documents and one of the two values that used to pass the old gate and then fail inside the action, and it says the six settings are required together.

Known, and not fixed here

The orphan sweep in the 6029 to 6030 upgrade step runs children before parents. Before that step adds seventeen foreign keys, it deletes rows whose parent is gone. Three of the parent tables are themselves pruned by those deletes, and each one's children are cleaned earlier, against a parent that has not yet lost its rows - so pruning an orphaned account, fetch account or distribution list re-orphans rows nothing revisits, and the constraint that follows is refused. It affects only an upgrade from a schema below 6030 on a database that already holds orphaned rows; a database without them upgrades correctly, a fresh installation is never on this path, and when it does fire it fails loudly with the engine's own words and rolls back rather than doing anything quietly. It is in all four database backends. No installation has reported hitting it. The fix is a reordering of seventeen delete statements and is held for 6.3.2, because a change to a database upgrade script belongs in a release whose gates can execute an upgrade - and this project's cannot yet, which is exactly how the defect was able to ship. That gate is being built first.

The report that led to this - a Compact Edition upgrade from schema 6011 refused at the same step (GitHub issue 93) - turned out to be GitHub issue 114, already fixed in 6.2.26: the upgrade had succeeded and the verification probe had crashed the database provider afterwards, and the tool then printed a cause it had no way to know. That installation upgrades on 6.3.0 and on this release.

Verification

The full regression suite ran on the stamped binary: 2,175 tests, 2,166 passed, 0 failed, 9 skipped (the seven explicit IMAP stress tests and two ignored), in 40 minutes, with no ERROR log written. hMailServer.exe 6.3.1.40, SHA-256 8b0ab1a2d1f3645f1e12c3bca1315023474bb3a63abf0efb44f60ba0b2d83235.

The installer has two hashes, and both are given deliberately. hMailServer-6.3.1-x64.exe as built, 79,408,192 bytes: SHA-256 3986fbcccda9e46fee29c1e538a79f2423ebc4d5e3f6e59306ffba4cc7bd8cba. As published, 79,423,896 bytes: SHA-256 68c72a60e7a8530bdd32d28b60eaadab5b9c90505e174c03196e5dfa58ac9b70. They are different, and this is the first release for which that is so: the signing job replaces the installer asset with the signed one before cosign runs, so the bytes on the release are not the bytes the build produced. The second is the one to check a download against. Verified after download with Get-AuthenticodeSignature: Valid, signer CN=Progressive Robot Ltd, O=Progressive Robot Ltd, L=Chester, S=Cheshire West and Chester, C=GB, issued by Microsoft ID Verified CS EOC CA 03 for three days from 10 September 2026 19:35 UTC, countersigned by Microsoft Public RSA Time Stamping Authority - which is what keeps the signature valid after the certificate itself has expired. The installer smoke test ran against this signed file on a throwaway runner and passed.

The assertion build, first. The same source compiled with every HM_ASSERT kept - a violated one is reported as HM6364 in the error log rather than compiled out - and the whole suite run on it: 2,175 tests, 0 failed, 9 skipped (the seven explicit IMAP stress tests and two ignored), no assertion violated anywhere in the run.

Reproducible. Two clean Release builds of the stamped source produced a byte-identical hMailServer.exe, SHA-256 8b0ab1a2d1f3645f1e12c3bca1315023474bb3a63abf0efb44f60ba0b2d83235.

Fuzzing. No parser changed between 6.3.0 and this release, so 6.3.0's run stands, as the release checklist allows for a patch release: the three MIME harnesses, thirty minutes each under libFuzzer and ASan, 8,296,354 executions, no crash, hang or assertion.


Assets

File Size SHA-256
Progressiverobot-hmailserver-attestation-46758583.sigstore.json 6,537 f6e9698be816d18ccef8ff623b92d7749b86a4d12a26428e5d427612c6a7f861
hMailServer-6.3.1-aarch64.AppImage 9,624,072 421996c406f092339c95502f73092178a80c66fc051ee54c059c81af7b2fdaf9
hMailServer-6.3.1-aarch64.AppImage.cosign.bundle 10,759 eaed6793204f8143362aa7ad7fd8fb64c1bb7b13596f69f7a1ca2ff363a11818
hMailServer-6.3.1-x64.exe 79,423,896 68c72a60e7a8530bdd32d28b60eaadab5b9c90505e174c03196e5dfa58ac9b70
hMailServer-6.3.1-x64.exe.cosign.bundle 10,807 7bcca1ead82f3a26cdcafa4d3c353bde509c34b70f675d6eea8f64351b48b8bd
hMailServer-6.3.1-x86_64.AppImage 9,939,448 72fd05d3c80dcd548f12de070640d32b642cd11702a1a504f7201b9212f101cb
hMailServer-6.3.1-x86_64.AppImage.cosign.bundle 10,763 32821036fb2a45b42dd54e8543dc99b92bddda76de91c21035d07ce08502cd4d
hmailserver-6.3.1-1.aarch64.rpm 3,586,638 0da4253e38bbb5002fedb6aba4cc638f06ed508399cce9f2d21c753a2194231a
hmailserver-6.3.1-1.aarch64.rpm.cosign.bundle 10,715 87aaec04c31b5be09bd0933a7f890f35b773aeba8de67fa2fde8c7fddfd885d5
hmailserver-6.3.1-1.x86_64.rpm 3,648,150 0f97ea33b8bf6254c9f6fb2ae9de22b4158ababde8c2bbc0bc29cc9c057bdfcf
hmailserver-6.3.1-1.x86_64.rpm.cosign.bundle 10,815 8bdd689394d3e6abb7e09e7d830a69a0803cc2c8af36f8d43b6131ee8bde9be6
hmailserver-linux-6.3.1-SHA256SUMS.txt 584 7e1c261932a336e812bb7f7379599d5219f11e1c493216347bbda42c90ee5bad
hmailserver-linux-6.3.1-SHA256SUMS.txt.cosign.bundle 10,767 ec036fbcb1f520d3cff286d76c4d3660b294fd5e561dee26cb94b41aad7a4baf
hmailserver.cyclonedx.json 203,167 e88343bba16db480325fc16036641d7e4701f1b29e782424e04bd456ba13366a
hmailserver.cyclonedx.json.cosign.bundle 10,811 9344231cde221006204aa6cb8167eb6f95fa79aa3fc3b98933ed386637881492
hmailserver.spdx.json 331,259 42144251bcf65463419d3cc0f658afb555865e53bd3f0e55b6815b3fe1acd43c
hmailserver.spdx.json.cosign.bundle 10,855 e4a723bdcc0d86d7ea0aa506de0d8a29385e1700421f7fe8256e624d87a434e9
hmailserver_6.3.1_amd64.deb 3,629,898 57cab27c70ce8a55a730d0b88ea91b712134acd5eda103b88e508cf4292b7171
hmailserver_6.3.1_amd64.deb.cosign.bundle 10,763 84399c7433b1d4993dbab643cb2138de138f75338af78e13892b324c9a4925cf
hmailserver_6.3.1_arm64.deb 3,559,742 dcdba7cca4b53e99ac8f7fc9772aa244e2abbc78b9954d02dfbff37b31977cba
hmailserver_6.3.1_arm64.deb.cosign.bundle 10,855 4d739c7dbfddd3e3bb9db64bc38f3d9adf632a222dc433a720abcbe7c577c3a5

These are the files published with the GitHub release, byte for byte, re-hosted in this project's package registry. The hashes above were computed from them on 24 September 2026. Each .cosign.bundle / .sigstore.json is the Sigstore bundle GitHub Actions made when the release was signed; all of them were verified again before re-publishing, against the former GitHub repository's workflow identity (https://github.com/Progressiverobot/hmailserver/..., issuer https://token.actions.githubusercontent.com), which is the identity to give cosign verify-blob for these files. The Windows installer carries a valid Authenticode signature (CN=Progressive Robot Ltd).