Repository navigation
Project Handbook
Building each component, running the tests, the contribution rules and required checks, the release process, verifying a release, the security policy, governance, the assurance case, the licence and the third-party components. File and line references point into the repository at the commit this page was written from (6.2.24, master of 4 September 2026). Sections headed Unconfirmed or Contradictions record what could not be verified or where documents disagreed, and are left in on purpose.
Verified 2026-09-04 against the working tree at f13ac06fc (branch server-fixes-wave, v6.2.24-5-gf13ac06fc) and the GitHub repository Progressiverobot/hmailserver via gh api. Paths are relative to the repository root unless stated. "(doc)" means the fact is what a document says and was not independently checkable from code; "(code)" means it was grepped/parsed; "(gh)" means it came from the GitHub API.
- Product: hMailServer, a fork of the original Windows mail server (SMTP/IMAP/POP3), maintained by Christopher Holloway / Progressive Robot Ltd (source: README.md:7-9)
- Repository: https://github.com/Progressiverobot/hmailserver (source: GOVERNANCE.md:5)
- Current version 6.2.27, build 37:
HMAILSERVER_VERSION "6.2.27",HMAILSERVER_VERSION_NUMERIC 6,2,27,37,HMAILSERVER_BUILD 37(source: hmailserver/source/Server/Common/Application/Version.h:5-7, code) - The same version is stamped in exactly seven .csproj
<Version>values: ControlPanel, DataDirectorySynchronizer, DBSetup, DBSetupQuick, DBUpdater, ImportTool, Shared (source:grep -n "<Version>" hmailserver/source/Tools/*/*.csproj, code; RELEASE.md:48-49 says "all seven") - Installer stamp:
AppVersion=6.2.27,OutputBaseFilename=hMailServer-6.2.27-x64,VersionInfoVersion=6.2.27.0(the fourth component stays 0 on purpose) (source: hmailserver/installation/section_setup_64.iss:2,6,10, code) - Schema:
REQUIRED_DB_VERSION 6031(source: hmailserver/source/Server/Common/Application/Constants.h:173, code). README.md:110 still says "Database version 6027" - stale, see section 17. - Latest published release: v6.2.27, published 2026-09-07T01:12:26Z, not draft, not prerelease, six assets:
hMailServer-6.2.27-x64.exe,hmailserver.spdx.json,hmailserver.cyclonedx.json, each with a.cosign.bundle(source:gh release view v6.2.27 --json assets, gh). v6.2.25 and v6.2.26 were published on 2026-09-06. - Tags present: v6.2.19 ... v6.2.22-pre1..pre6, v6.2.23-alpha1, v6.2.23-alpha2, v6.2.24, v6.2.25, v6.2.26, v6.2.27 (source:
git tag -l 'v*', code) - v6.2.23-alpha1 is a lightweight tag (
git cat-file -t= commit); v6.2.23-alpha2 and every tag since (v6.2.24 to v6.2.27) are annotated tag objects (source:git cat-file -t refs/tags/<tag>, code; matches SECURITY.md "from v6.2.23-alpha2 on") - Badges: OpenSSF Best Practices project 14187 and OpenSSF Scorecard (source: README.md:4-5). Best Practices level is "Passing" at 100% (Basics 13/13, Change Control 9/9, Reporting 8/8, Quality 13/13, Security 16/16, Analysis 8/8) (source: https://www.bestpractices.dev/projects/14187, fetched 2026-09-04)
- Supported platforms: 64-bit Windows only, Windows 10 1607 / Server 2016 (build 14393) upward, enforced by the installer (source: README.md:127-129, doc)
- Compiler: Visual Studio 2026, platform toolset
v145, x64 only (source: hmailserver/source/Server/hMailServer/hMailServer.vcxproj:22,29<PlatformToolset>v145</PlatformToolset>, code; README.md:97; .github/CONTRIBUTING.md:12) - MSVC version: the tree pins the toolset family only - the native-dependencies action requires a
14.5*MSVC directory ("The v145 (14.5x) toolset is not installed") (source: .github/actions/native-dependencies/action.yml:77-82, code); the v6.2.24 release notes named the machine's compiler as MSVC 14.51. - Windows SDK: the project pins only
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>(latest installed) (source: hMailServer.vcxproj:17, code). RELEASE.md:76 and the v6.2.24 notes name "Windows SDK 10.0.26100" as the toolchain used - that is the machine's SDK, not a project pin. - VS workloads required: ".NET desktop development" (or "Managed Desktop Build Tools"), "Desktop development with C++"; components "C++ ATL for latest v145 build tools (x86 & x64)" and a Windows 10/11 SDK (source: README.md:195-199, doc)
- winget one-liner:
winget install Microsoft.VisualStudio.BuildTools --override "--quiet --wait --norestart --add Microsoft.VisualStudio.Workload.VCTools;includeRecommended --add Microsoft.VisualStudio.Component.VC.ATL --add Microsoft.VisualStudio.Workload.ManagedDesktopBuildTools"(source: README.md:203-205, doc) - Other required software: Inno Setup 6 (
winget install JRSoftware.InnoSetup, installer only), Perl 5 / Strawberry (OpenSSL only), Python 3 (libpq only) (source: README.md:180-185, doc). README.md:180 also lists "An installed version of hMailServer 5.7 or later (configured with a database)" - inherited upstream text. - MSBuild is located with vswhere (
-latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe) (source: build/Find-MsBuild.ps1:10-19, code) - Native libraries live OUTSIDE the tree under the
hMailServerLibsenvironment variable; the project references$(hMailServerLibs)\boost_1_92_0,$(hMailServerLibs)\openssl-4.0.2,$(hMailServerLibs)\postgresql-18.3(source: hMailServer.vcxproj:76,100, code; post-build.bat:12-18).build/Get-LibraryVersions.ps1parses those paths back out (openssl=4.0.2, boost=1.92.0, postgresql=18.3) for the CI cache keys. - Scripted route:
libraries\build-openssl.ps1 -Version 4.0.2,libraries\build-boost.ps1 -Version 1.92.0andlibraries\build-pgsql.ps1each download one source archive, verify it against a SHA-256 pinned in the script and build it under%hMailServerLibs%(source: README.md:287-289; libraries/build-openssl.ps1:54-94, code) - OpenSSL 4.0.x build:
Perl Configure no-asm VC-WIN64A --prefix=%cd%\out64 --openssldir=%cd%\out64 -D_WIN32_WINNT=0x0A00,nmake clean,nmake build_libs,nmake install_dev install_runtime_libs(notinstall_sw) (source: README.md, doc). Runtime DLLs copied arelibcrypto-4-x64.dllandlibssl-4-x64.dll(source: hmailserver/source/Server/hMailServer/post-build.bat:12-15, code) - PostgreSQL 18.3 libpq build: winflexbison on PATH,
py -m pip install meson ninja, thenmeson setup builddir --buildtype=release -Dssl=openssl -Dauto_features=disabled -Dextra_include_dirs=%hMailServerLibs%\openssl-4.0.2\out64\include -Dextra_lib_dirs=%hMailServerLibs%\openssl-4.0.2\out64\libandmeson compile -C builddir src/interfaces/libpq/libpq:shared_library(source: README.md:325, doc). Output copied frompostgresql-18.3\builddir\src\interfaces\libpq\*.dll(source: post-build.bat:18, code) - Boost 1.92.0 build:
bootstrapthenb2 debug release threading=multi link=static --with-thread --with-filesystem --with-regex --with-chrono --with-atomic address-model=64 stage --build-dir=out64 -j 4 define=BOOST_USE_WINAPI_VERSION=0x0A00(source: README.md:335-336, doc) -
libraries/build-openssl.ps1,build-boost.ps1andbuild-pgsql.ps1(sharingbuild-common.ps1) each download one source archive from the project's own release server, verify it against a SHA-256 pinned in the script, and build it outside the tree under%hMailServerLibs%; nothing they fetch is committed (source: libraries/build-openssl.ps1:54-94; hmailserver/docs/ThirdPartyBinaries.md:48-54, code) - .NET SDK pinned to 10.0.303,
rollForward latestFeature,allowPrerelease false(source: global.json:3-6, code) - All ten .csproj under source/Tools target
net10.0-windows(ControlPanel, ControlPanel.Core, ControlPanel.Tests, DataDirectorySynchronizer, DBSetup, DBSetupQuick, DBUpdater, ImportTool, ImportTool.Tests, Shared) (source:grep TargetFramework hmailserver/source/Tools/*/*.csproj, code) - Control Panel assembly name is
hMailCP(WPF, WinExe) (source: hmailserver/source/Tools/ControlPanel/ControlPanel.csproj:4-15, code) - NuGet lock files are enforced:
RestorePackagesWithLockFile=trueandEnableWindowsTargeting=truefor every Tools project (source: hmailserver/source/Tools/Directory.Build.props:17,33, code); CI restores with--locked-mode(source: .github/workflows/ci.yml:65,75,113) - The regression suite targets .NET Framework 4.8.1 (
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>) with NUnit 4.6.1, NUnit.ConsoleRunner 3.22.0, NUnit3TestAdapter 6.3.0 (source: hmailserver/test/RegressionTests/RegressionTests.csproj:38; hmailserver/test/RegressionTests/packages.config:31-33, code) - The .NET tools build against a checked-in TlbImp wrapper
hmailserver/source/Tools/Interop/Interop.hMailServer.dll, so no registered typelib is needed fordotnet build(source: hmailserver/source/Tools/Interop/README.md:3-7; ci.yml:6-7) - Building on a machine with a production hMailServer: pass
/p:PreBuildEventUseInBuild=false /p:PostBuildEventUseInBuild=false- build.ps1 already does (source: README.md:295; build/build.ps1:44-45, code) - One build tree; the service holds the output binary, so stop the service before linking and never build during a regression run (source: ARCHITECTURE.md "Building")
- Server:
build\build.ps1 -Configuration Release(default is Debug;-Cleanruns /t:Clean first). Runs MSBuild onhmailserver\source\Server\hMailServer\hMailServer.slnwith/m /p:Configuration=<cfg> /p:Platform=x64 /p:PreBuildEventUseInBuild=false /p:PostBuildEventUseInBuild=false, log tologs\build-<cfg>.log(source: build/build.ps1:4-66, code).-Asserts(added 5 Sep 2026, Release only) passes/p:KeepAssertions=true, which definesHM_KEEP_ASSERTIONS: the server's ownHM_ASSERTmacro (StdAfx.h; three modes - Debug = CRT assert, Release = compiled out, kept = reported) then reports a violated assertion as Critical HM6364 through ErrorManager naming expression, file and line, and carries on; loglogs\build-Release-asserts.log; the dynamic-analysis build, never the one that ships.Diagnostics.AssertionsEnabledsays which binary is running andDiagnostics.TriggerAssertion()provokes one (source: build/build.ps1; hMailServer.vcxproj KeepAssertions group; StdAfx.h; COM/InterfaceDiagnostics.cpp) - Server post-build (elevates via UAC):
build\post-build.ps1 -Configuration Release- runspost-build.bat <hMailServerLibs> <outDir> <exe> <intDir>, which doesNET STOP hMailServer, copies OpenSSL, libpq, MariaDB Connector/C (libraries\mariadb-connector-c-3.4.9\libmysql.dll+plugin\*.dll) andhMailServer.tlbbeside the exe, thenhMailServer.exe /Register(source: build/post-build.ps1:8-32; hmailserver/source/Server/hMailServer/post-build.bat:10-42, code) - Output location:
hmailserver\source\Server\hMailServer\x64\<Configuration>\hMailServer.exe(source: build/post-build.ps1:16-17, code) - Admin/setup tools:
build\build-tools.ps1(default Release) runsdotnet publish <proj>.csproj -c <cfg> -o <proj>\publishfor DBSetup, DBSetupQuick, DBUpdater, DataDirectorySynchronizer, ImportTool, deleting each publish folder first (source: build/build-tools.ps1:21-34, code). Solution:hmailserver/source/Tools/hMailServer Tools.sln(projects Shared, DBSetup, DBSetupQuick, DBUpdater, DataDirectorySynchronizer, ImportTool) (source:grep Project( "hMailServer Tools.sln", code) - Control Panel: NOT covered by build-tools.ps1; it is a separate
dotnet publishofhmailserver\source\Tools\ControlPanel\ControlPanel.csprojinto itspublish\folder (source: build/build-tools.ps1:7-11; RELEASE.md:52-55). Solutionhmailserver/source/Tools/ControlPanel.slnholds ControlPanel, ControlPanel.Core, ControlPanel.Tests (source:grep Project( ControlPanel.sln, code). CI's publish command isdotnet publish hmailserver/source/Tools/ControlPanel/ControlPanel.csproj -c Release -o publish --no-build(source: ci.yml:71) - Tests:
build\build-tests.ps1(default Debug) first restores the parenthmailserver\test\hMailServer Tests.sln(/t:Restore /p:RestorePackagesConfig=true) then MSBuildshmailserver\test\RegressionTests\RegressionTests.slnx64, log tologs\build-tests.log(source: build/build-tests.ps1:18-64, code) - Installer: ISCC on
hmailserver\installation\hMailServer64.iss(Inno Setup 6) (source: README.md:292-293; RELEASE.md:88). ISCC on this machine:C:\Users\chris\AppData\Local\Programs\Inno Setup 6\ISCC.exe(local, code).hMailServer64.issreadshMailServerLibsand definesDOTNET_MAJOR "10",DOTNET_CHANNEL "10.0",DOTNET_RUNTIME_FILE "windowsdesktop-runtime-10.0-win-x64.exe"(source: hmailserver/installation/hMailServer64.iss:1-19, code) - Bundled .NET runtime:
build\get-dotnet-runtime.ps1(default-Channel 10.0) downloadshttps://aka.ms/dotnet/10.0/windowsdesktop-runtime-win-x64.exetohmailserver\installation\DotNet\(gitignored, 55+ MB) and rejects files under 40 MB (source: build/get-dotnet-runtime.ps1:16-38, code) - COM wrapper regeneration after any
hMailServer.idlchange and after a Release server build:build\regenerate-interop.ps1runsTlbImp.exe hMailServer.tlb /out:Interop.hMailServer.dll /namespace:hMailServer /machine:X64 /silentAND rewrites the wrapper's SHA-256/size inhmailserver/docs/third-party-binaries.json(source: build/regenerate-interop.ps1:30-130, code). TlbImp default pathC:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools\x64\TlbImp.exe(source: build/regenerate-interop.ps1:31) - COM re-registration for a NEW interface (elevated):
build\register-com.ps1(/RegisterTypeLib, or/Registerwith-IncludeService) (source: build/register-com.ps1:39-93, code) - Fuzzing (separate, clang-cl):
.\fuzz\build-fuzz.ps1then.\fuzz\run-fuzz.ps1 -Target mime_message_fuzzer -Minutes 5; needs "C++ Clang tools for Windows"; never touches hMailServer.sln or the service (source: fuzz/README.md:16-26, doc). Harnesses: mime_message_fuzzer, mime_header_fuzzer, mime_decode_fuzzer; dictfuzz/dict/mime.dict;fuzz/regression/committed;corpus/,build/,bin/,artifacts/are generated not committed (source: fuzz/README.md:32-45;ls fuzz/harness fuzz/dict fuzz/regression, code)
- Warnings as errors:
<TreatWarningAsError>true</TreatWarningAsError>(/WX),<WarningLevel>Level3</WarningLevel>, Debug and Release (source: hMailServer.vcxproj:83-84,153-154, code) - Control Flow Guard:
<ControlFlowGuard>Guard</ControlFlowGuard>compile +/guard:cflink, Debug and Release (source: hMailServer.vcxproj:87,96,164,173, code) - Reproducible Release: compiler
/Zm200 /Brepro /d1trimfile:$(SolutionDir), linker/ignore:4099 /guard:cf /Brepro /pdbaltpath:%_PDB%(source: hMailServer.vcxproj:165,173, code) -
OPENSSL_NO_FILENAMESdefined in every configuration (source: hMailServer.vcxproj:64,77,137,149,168, code) -
<ExceptionHandling>Async</ExceptionHandling>(/EHa) in Debug and Release (source: hMailServer.vcxproj:79,150, code) - /GS, /NXCOMPAT, /DYNAMICBASE are NOT set explicitly in the vcxproj (no BufferSecurityCheck/DataExecutionPrevention/RandomizedBaseAddress elements) - they are MSVC x64 defaults. Verified on the built binary instead:
x64\Release\hMailServer.exePE DllCharacteristics 0xC160 = HIGH_ENTROPY_VA, DYNAMIC_BASE, NX_COMPAT, GUARD_CF, TERMINAL_SERVER_AWARE on; LOAD_CONFIG directory present (320 bytes) (source: PE header parse of the local Release exe, code) - The PE-flag check above was made on the 6.2.24 binary (SHA-256
64406163b1a3a8a865e34d74883b5e2a05a5a1c476b500b26745cde67d8a989b, size 10,171,904, identical to the hash in the v6.2.24 release notes); the project flags have not changed since. The shipped 6.2.27 binary is hMailServer.exe 6.2.27.37, SHA-2568CD745C49657A2E02989A8A86E9290C0AA49D317466B860C3749C757C129410F, byte-identical across three clean Release builds; the installerhMailServer-6.2.27-x64.exeis 77,237,885 bytes, SHA-256F60D3C30F27AF9EDC18BEE295DA231C666E826C1436E2214593B33499227C1A6(source: v6.2.27 release notes, verification section, gh) - Reproducibility claim: two clean Release builds give a byte-identical exe; first shown 22 August 2026; verified per release at RELEASE.md step 8 (source: ASSURANCE-CASE.md "Residual risk"; RELEASE.md:69-78, doc)
- CFG cost measured: full 1,838-test gate 31 minutes vs about 55 before; exe grew about 97 KB (source: ASSURANCE-CASE.md "Residual risk", doc)
- Runner:
build\run-tests.ps1runshmailserver\test\packages\NUnit.ConsoleRunner.3.22.0\tools\nunit3-console.exe hmailserver\test\RegressionTests\bin\x64\Debug\RegressionTests.dll --labels=All, log tologs\run-tests.log;-StopOnErroradds/stoponerror(not for release runs);-Where "<expr>"adds--where=for a subset (source: build/run-tests.ps1:14-69, code) - Test assembly is the Debug x64 build even for release gates (source: build/run-tests.ps1:28, code)
- Pre-flight first:
build\preflight-tests.ps1(-Cleanremoves a stale ERROR log) (source: RELEASE.md:23-27; .github/PULL_REQUEST_TEMPLATE.md:16-18) - Pre-flight checks (in order): service exists and its PathName is the repo Release exe; service running; no stray
HKLM\SOFTWARE\hMailServer\InstallLocationin either registry view; COM auth as Administrator/testar;Domains.Count -eq 1;Settings.TCPIPPorts.Count -eq 4;Database.CurrentVersion -eq RequiredVersion; no stale ERROR log; clamd listening on 3310; serviceSpamAssassinJAMexists; listeners on 25, 110, 143; VPN adapter warning (Proton|WireGuard); NUnit runner and RegressionTests.dll present; no orphan .cs files missing from RegressionTests.csproj (source: build/preflight-tests.ps1:19-159, code) - Test count: 2,124
[Test]attributes across the suite at HEAD (2,024 at v6.2.27); RegressionTests.csproj lists 347<Compile Include>entries explicitly (no glob) (source:grep -c "^\s*\[Test\]"over hmailserver/test/RegressionTests; csproj, code). The v6.2.27 gate was 2024 tests, 2017 passed, 0 failed, the 7 explicit skips, on the assertion build and again on the shipping binary; the Control Panel's tests passed (no count published) (source: v6.2.27 release notes, gh) - Every source file must be listed in RegressionTests.csproj or it is never compiled; pre-flight fails on orphans (source: ARCHITECTURE.md "Tests"; preflight-tests.ps1:133-159)
- Tests that provoke a reported error must clear it with
CustomAsserts.AssertReportedError(...);PerformBasicSetupcallsAssertNoReportedError(source: ARCHITECTURE.md "Tests", doc) - Run elevated: the suite starts/stops the hMailServer and SpamAssassin services; unelevated those tests report inconclusive (source: README.md:519-520, doc)
- Never
dotnet testthe RegressionTests project; it is .NET Framework/packages.config and is built with MSBuild (source: build-tests.ps1; RegressionTests.csproj:38, code) - Control Panel unit tests:
dotnet test hmailserver/source/Tools/ControlPanel.Tests/ControlPanel.Tests.csproj --configuration Release --collect:"XPlat Code Coverage"(cobertura) in CI; the coverage upload to GitHub isfail-on-error: falsebecause the Code Quality repository setting is deliberately off (source: ci.yml:77-148, code) - Import Tool unit tests:
dotnet test hmailserver/source/Tools/ImportTool.Tests/ImportTool.Tests.csproj -c Release --no-buildruns in the "Build .NET tools" job after the solution build (the Maildir reader: folders, messages, file-name flags, line endings) (source: ci.yml:118-126, code) - Other test projects under hmailserver/test (PerformanceTests, MemoryTests, StressTest, TestBedUI, TestInvalidConnections, VMTestRunner.Console, PerformanceTest, hMailServer.PerformanceTests, hMailServer.PerformanceTests.Console, hMailServer.Test.Infrastructure) exist but are built by nothing (source:
find hmailserver/test -name *.csproj; no reference in build/ or .github/workflows, code)
- Real server, nothing mocked: live SMTP/IMAP/POP3 sockets, COM API, live SpamAssassin and ClamAV, real TLS 1.2/1.3 handshakes. DNS is the one exception since 5 September 2026: the suite serves its own zone (
Shared/SuiteDns.cs, a[SetUpFixture]that binds a FakeDnsServer on 127.0.0.1 and pointsDNSServerat it for the run; DMARC, SPF and DKIM fixtures add the records they need) so no test resolves a live name (source: SuiteDns.cs; RegressionEnvironment.md:189-191, code). README.md:13 and ARCHITECTURE.md:170 still say "DMARC against live DNS" - stale. - The service must run from the repository Release build
hmailserver\source\Server\hMailServer\x64\Release\hMailServer.exe, not an installed copy (source: hmailserver/docs/RegressionEnvironment.md:35-41; preflight-tests.ps1:20-24) - Database: SQL Server Compact 4.0 x64 from
hmailserver\installation\SQLCE; bench DB created once via COMDatabase.CreateInternalDatabase()+Reinitialize(), thereafter upgraded never recreated; move it forward withbuild\upgrade-test-database.ps1(through the service's COM API, no elevation) (source: RegressionEnvironment.md:63-87; build/upgrade-test-database.ps1:4-22, code) - Data directory convention
C:\HMTest\Data(short, to avoid MAX_PATH) (source: RegressionEnvironment.md:89-95) - Exactly one domain and exactly four TCP/IP ports at start: SMTP 25, POP3 110, IMAP 143 and the SMTP submission port; the TLS fixtures add twelve more and remove them in teardown (source: RegressionEnvironment.md:96-105; preflight-tests.ps1:53-59)
- COM credentials:
Administrator/testar(blank fallback) - a bench credential, not a secret (source: RegressionEnvironment.md:107-110; preflight-tests.ps1:50) - ClamAV:
C:\clamav\clamd.exe(hard-coded inCustomAsserts),TCPSocket 3310,TCPAddr 127.0.0.1, runs as a bare process (source: RegressionEnvironment.md:112-120) - SpamAssassin: Windows service named
SpamAssassinJAMwrappingspamd.exe -i 127.0.0.1 -A 127.0.0.1 -p 783(source: RegressionEnvironment.md:127-134). README.md:527-535 gives an alternative CPAN build with--port 783. - Without SpamAssassin/ClamAV the dependent tests report inconclusive rather than failing (source: README.md:512, doc)
- The suite wipes domains and accounts; never run it against production (source: README.md:514; RegressionEnvironment.md:17-18)
- Code of Conduct: Contributor Covenant (source: .github/CODE_OF_CONDUCT.md:1; CONTRIBUTING.md:5-6)
- DCO sign-off:
git commit -saddsSigned-off-by:; no CLA; fix isgit commit --amend -s(source: .github/CONTRIBUTING.md:40-48) - The DCO check (
.github/workflows/dco.yml, job "Signed-off-by on every commit") runs onpull_requestto master only, requires the trailer to contain the commit AUTHOR's email, and is skipped entirely when the PR author isdependabot[bot]or hasauthor_associationOWNER or MEMBER (source: dco.yml:28-42,59-70, code) - The DCO job is NOT among the nine required status checks on master (source:
gh api repos/Progressiverobot/hmailserver/rulesets/21165267, gh) - see section 8 - Branch from
master; version branches are bug-fix only; one logical change per PR; add/update regression tests; parameterised SQL exclusively; new server-wide optional features follow the INI-settings pattern (IniFileSettingsgetter + Server features dialog control) (source: CONTRIBUTING.md:50-57) - Coding style:
.editorconfigsetsindent_style = space,indent_size = 3for*.{h,cpp,cs}(source: .editorconfig:4-6, code). Enforced by editorconfig-checker v3.11.3 (installed by the action, then run explicitly - the action alone checks nothing) anddotnet format --verify-no-changeson the Tools solution and ControlPanel.csproj; exclusions live in.editorconfig-checker.jsonat the repository root (source: .github/workflows/style.yml:9,40-52,102-127; .editorconfig-checker.json, code). - Every source file carries a copyright line and
SPDX-License-Identifier: AGPL-3.0-or-later; enforced bypython3 build/add-license-headers.py --check; MIDL output (dlldata.c,hMailServer_i.c,hMailServer_p.c) and the directorieslibraries/,zlib(vendored zlib source under its own licence; in the tree after 6.2.27, not yet in a published release),obj,bin,publish,packages,Outputare skipped (source: build/add-license-headers.py:53-59; style.yml:55-66, code) - The "SPDX identifier on every source file" job also runs, in order:
python3 build/check-mnemonics.py(every static Control Panel caption has an Alt-key mnemonic, no two on one view/method share one),python3 build/check-localisation.py(the generated English catalogueResources/Strings.resxmatches theL(...)/F(...)/N(...)/{loc:L}marks in the source - run it with--writeafter adding a caption; every language keeps its English's{n}placeholders and Alt keys; each of the 17 languages inCOMPLETEmust translate every key; a file inLOCALISEDmay carry no unmarked caption),python3 build/check-catalogues.py(translations keep the server's literal names, page titles and numbers),python3 build/check-ini-coverage.py(every[Settings]keyIniFileSettingsreads is named somewhere in the Control Panel and is read throughIniFileSettings),python3 build/check-authz-choke-point.py(onlyACLManagerdecides folder access). All five gate a PR through that required check; they landed after v6.2.27 (source: .github/workflows/style.yml:65-100; build/check-localisation.py:52-55, code) - Compiler runs with /WX; code must build warning-free; C# builds with
-warnaserrorin CI (source: CONTRIBUTING.md:19; ci.yml:68,116) - PR template checklist: builds warning-free with build/build.ps1; regression suite passes after preflight; new behaviour covered by tests; parameterised SQL; schema changes include MySQL, MS SQL and PostgreSQL scripts in
source/DBScripts/; new settings via COM API or hMailServer.INI pattern (source: .github/PULL_REQUEST_TEMPLATE.md:14-22) -
good first issuelabel marks bounded tasks tied to Roadmap.md gaps (source: CONTRIBUTING.md:33-38) - CODEOWNERS:
@chrisholloway5owns everything, with explicit entries for .github, workflows, SECURITY.md, ThirdPartyBinaries docs, libraries/, installation/, Interop/, TCPIP/, Crypt.cpp/h, LDAP/, RELEASE.md, build/; "Require review from Code Owners" is deliberately OFF because a sole owner cannot approve their own PR (source: .github/CODEOWNERS:1-58, code; rulesetrequire_code_owner_review: false, gh) - Support routing: defects to Issues; questions to Discussions; general hMailServer questions to the hMailServer forum; security to advisories (source: .github/SUPPORT.md; .github/ISSUE_TEMPLATE/config.yml)
- Dependabot: NuGet weekly grouped (
dotnet-dependencies, limit 10) and GitHub Actions weekly grouped (limit 5) for both/and/.github/actions/native-dependencies; native C++ libs are pinned by hand in hMailServer.vcxproj and the digest tables oflibraries/build-*.ps1(source: .github/dependabot.yml, code) - Commit identity for the maintainer: commit as chrisholloway5, no co-author trailers (source: RELEASE.md:91-92)
- Contributions are licensed AGPLv3 (source: CONTRIBUTING.md:66-69)
Twelve workflow files under .github/workflows/ (names as declared, code):
-
ci.yml"CI" - push/PR to master, dispatch. Jobs: "Build Control Panel (.NET 10)" (regenerates and verifiesSettingsSearchIndex.g.cs, restore --locked-mode, build -warnaserror, publish, test with coverage), "Build .NET tools" (locked restore, build -warnaserror,./build/build-tools.ps1), "upload-coverage-csharp" (source: ci.yml:12-148) -
codeql.yml"CodeQL" - push/PR/weekly Monday 04:32 UTC/dispatch. Job "Analyze (csharp)" on every push/PR,security-and-quality, build-mode manual, obj/bin results filtered from SARIF. Job "Analyze (c-cpp)" on push to master, schedule and dispatch but NOT on pull requests (if: github.event_name != 'pull_request'); GitHub-hostedwindows-2025-vs2026, native libraries restored or built by.github/actions/native-dependenciesbefore CodeQL init,security-extended, full build viabuild\build.ps1 -Configuration Release(Debug selectable on dispatch), 240-minute timeout; the status-check name carries the image, "Analyze (c-cpp) (windows-2025-vs2026)" (source: codeql.yml:34-47,160-259; .github/codeql/codeql-config.yml) -
dco.yml"DCO" - PR only; job "Signed-off-by on every commit" (source: dco.yml:1-37) -
dependency-review.yml"Dependency review" - PR only;fail-on-severity: high(source: dependency-review.yml:1-30) -
installer-smoke.yml"Installer smoke test" - dispatch only; job "Install on a throwaway runner and verify": downloadshMailServer-*-x64.exefrom a release tag or aninstallerartifact, runs/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /TYPE=full /LOG=, 10-minute bound, checks service PathName, Running, listeners on 25/110/143,New-Object -ComObject hMailServer.Application, keeps the log, uninstalls (source: installer-smoke.yml:18-223) -
sbom.yml"SBOM" - push to master,release: created, dispatch withrelease_tag; job "Generate SBOM (SPDX + CycloneDX)" with anchore/sbom-action (Syft), thenbuild/merge-native-dependencies-into-sbom.ps1adds OpenSSL/Boost/libpq (versions parsed from hMailServer.vcxproj bybuild/native-dependencies.ps1), verifies every native PURL is present, uploads artifact (90 days) and attaches to the release (source: sbom.yml:24-133) -
scorecard.yml"OpenSSF Scorecard" - Sunday 04:17 UTC, push to master, dispatch;publish_results: truesince 5 September 2026 (the README badge and the scorecard.dev viewer read the public OpenSSF API); SARIF to code scanning (source: scorecard.yml:18-95, code) -
server-build.yml"Server build" - push/PR to master, dispatch (Release/Debug); job "Build server" on GitHub-hostedwindows-2025-vs2026(so the status-check name is "Build server (windows-2025-vs2026)"); the native libraries are restored from cache or built from source by.github/actions/native-dependencies(libraries/build-*.ps1, 30-45 minutes cold), thenbuild\build.ps1 -Configuration Release; uploads hMailServer.exe, .pdb, hMailServer.tlb and the OpenSSL/libpq DLLs as a 14-day artifact; 120-minute timeout; the regression suite is NOT run here - it still needs the maintainer's bench (source: server-build.yml:1-150, code) -
sign-release.yml"Sign release artefacts" -release: created, dispatch withtag; job "Sign and attach signatures": refuses a lightweight tag or one that failsverify-tagagainst.github/allowed_signers;cosign sign-blob --yes --bundle <file>.cosign.bundle; verifies with--certificate-identity-regexp "^https://github\.com/<repo>/"and--certificate-oidc-issuer https://token.actions.githubusercontent.com; uploads bundles; before signing it refuses a release with no asset named exactlyhMailServer-<tag without the leading v>-x64.exe, because the server's update checker (UpdateChecker.cpp:428-429, in the tree after 6.2.27) builds that name from the tag and matches it on equality (source: sign-release.yml:38-189, name check at 139-160) -
style.yml"Coding style" - jobs "editorconfig-checker", "SPDX identifier on every source file", "dotnet format leaves the C# tree unchanged" (source: style.yml:22-82) -
upstream-watch.yml"Upstream watch" - monthly (0 6 1 * *) and dispatch; compares againsthmailserver/hmailserverafter the SHA in.github/upstream-sync;issues: write(source: upstream-watch.yml:14-35) -
verify-binary-provenance.yml"Binary provenance" - push/PR/dispatch; job "Verify committed binaries against the manifest": hash everyartifacts[]entry inhmailserver/docs/third-party-binaries.json, fail on changed/missing/unlisted binaries (Scorecard extension set + MZ/ELF/OLE sniff), warn onremove-*dispositions (source: verify-binary-provenance.yml:35-166) - All actions are pinned to full commit SHAs with version comments (source: every
uses:line, code)
Branch and tag protection (gh, ruleset API, 2026-09-04):
- Ruleset "Protect master: changes arrive by pull request" (id 21165267, active) on
refs/heads/master: rulesdeletion,non_fast_forward,pull_request(required_approving_review_count 0, require_code_owner_review false, dismiss_stale_reviews false, require_last_push_approval false, allowed merge methods merge/squash/rebase, require_extra_approval_for_unattributed_changes true),required_status_checkswithstrict_required_status_checks_policy: true - The nine required status checks, verbatim: "Build Control Panel (.NET 10)", "Build .NET tools", "Analyze (csharp)", "SPDX identifier on every source file", "editorconfig-checker", "dotnet format leaves the C# tree unchanged", "Verify committed binaries against the manifest", "Dependency review", "Build server (windows-2025-vs2026)"
- Not required: "Signed-off-by on every commit" (DCO), Scorecard, CodeQL c-cpp, SBOM, upstream watch
- Ruleset "Protect release tags" (id 20539388, active) on
refs/tags/v*:deletionandnon_fast_forwardblocked - Classic branch protection is not used (
/branches/master/protectionreturns 404 "Branch not protected"); protection is entirely via rulesets
The thirteen ordered steps of RELEASE.md (source: RELEASE.md:6-153, doc, with script facts checked in code):
- Freeze the code (RELEASE.md:8)
- Adversarial review of the complete diff BEFORE version stamping (RELEASE.md:10-17)
- Fix what survives; every defect fix gets a negative-control test that fails on the pre-fix binary (RELEASE.md:18-22)
- Pre-flight:
build\preflight-tests.ps1(-Clean) (RELEASE.md:23-27) -
build\check-roadmap.ps1reconciles Roadmap.md tick boxes against section counts and the contents table (RELEASE.md:28-31; build/check-roadmap.ps1:4-20) -
build\check-db-scripts.ps1builds a throwaway SQL CE database fromCreateTablesMSSQL.sqland applies everyUpgrade*MSSQLCE.sqlusing SQLScriptParser's blank-line splitting (default assemblyC:\Program Files\Microsoft SQL Server Compact Edition\v4.0\Desktop\System.Data.SqlServerCe.dll); plusbuild\check-schema-versions.ps1(pwsh 7 only) which cross-checks REQUIRED_DB_VERSION, DBUpdater's LoadScripts table, GetDatabaseVersionName, the Upgradeto.sql files (four per step) and SchemaVerification.cs probes (RELEASE.md:32-46; build/check-db-scripts.ps1:26-135; build/check-schema-versions.ps1:4-18) - Version stamp: Version.h (three defines), section_setup_64.iss, seven .csproj
<Version>;git grep <old-version>(RELEASE.md:48-50) - Build everything at the stamped version:
build.ps1 -Configuration Release,build-tools.ps1 -Configuration Release, ControlPaneldotnet publish,build-tests.ps1; confirm FileVersion on hMailServer.exe and publish\hMailCP.dll; regenerate the interop wrapper if the IDL changed (AFTER any interface-ordering fix); prove reproducibility by a secondbuild\build.ps1 -Configuration Release -Cleanand compare SHA-256; put the hash in the notes (RELEASE.md:51-78) 8b. Full regression suite on the assertion build first (build.ps1 -Configuration Release -Asserts), expecting no HM6364 line - a violation fails the test that provoked it; then rebuild plain Release before step 9 (RELEASE.md step 8b, added 5 Sep 2026) - Full regression suite on the stamped binary; any change afterwards voids the run; never abort (RELEASE.md:79-83)
- README/release notes: "Fixed" means reproduced-then-fixed or negative-control-tested; otherwise "hardened"/"instrumented"/"still open" (RELEASE.md:84-87,164-167)
- Installer: ISCC on hMailServer64.iss; never run it on the dev machine; validation is the
installer-smoke.ymlworkflow (RELEASE.md:88-90) - Commit as chrisholloway5 (no co-author trailers); master is protected so:
git push origin <branch>,gh pr create --base master --head <branch> --fill,gh pr merge --rebase(self-merge allowed, no reviewer required),git pull --ff-only origin master. Then an annotated SIGNED tag:git tag -s vX.Y.Z -m "hMailServer X.Y.Z",git -c gpg.ssh.allowedSignersFile=.github/allowed_signers verify-tag vX.Y.Z,git push origin vX.Y.Z. Signing is SSH (gpg.format ssh,user.signingkey= public key path); the key must be in.github/allowed_signers. Then publish as a DRAFT:gh release create vX.Y.Z <installer> --draft --prerelease --title "..." --notes-file <notes>,gh workflow run "SBOM" -f release_tag=vX.Y.Z,gh workflow run "Sign release artefacts" -f tag=vX.Y.Z(LAST),gh release view vX.Y.Z --json assets(expect installer + 2 SBOMs + bundles),gh release edit vX.Y.Z --draft=false(RELEASE.md:91-151). The installer asset must be named exactlyhMailServer-<tag without the leading v>-x64.exe(with its.cosign.bundlebeside it): the update checker in every running server builds that name from the tag and matches it exactly, and the signing workflow refuses a release that lacks it (RELEASE.md:159-167; sign-release.yml:139-160). v6.2.22-pre3 shippedhMailServer-6.2.22-x64.exeunder that tag, which is the case the check exists for. - Close the loop on every issue the release resolves or does not (RELEASE.md:152-153)
Mechanics that are facts rather than advice:
- Immutable releases are enabled: a published release refuses further asset uploads (HTTP 422); a tag that backed an immutable release can never back another, even after deletion - a broken release needs the next version number (source: RELEASE.md:124-151; sbom.yml:7-12; sign-release.yml:6-9)
- Draft releases deliver no
releaseevent, so both the SBOM and signing workflows MUST be dispatched by hand with the tag (source: RELEASE.md:141-147; sbom.yml:14-17; sign-release.yml:40-44) - Local git config on the maintainer's machine:
gpg.format ssh,user.signingkey C:/Users/chris/.ssh/id_ed25519.pub(source:git config --local, code) - Allowed signer: principal
christopher.j.holloway@outlook.com, key type ssh-ed25519 (source: .github/allowed_signers:11, code) - Standing rules: prefer two small releases over one large; a fix to a shared layer needs a dependents audit; the public record never overstates (source: RELEASE.md:155-167)
- The installer smoke test ran twice on 2026-09-04 (17:46 and 18:42 UTC), both success, the second at the v6.2.24 publish time (source:
gh run list --workflow=installer-smoke.yml, gh)
- Tag signature:
git -c gpg.ssh.allowedSignersFile=.github/allowed_signers verify-tag v6.2.24(source: SECURITY.md:86-92; .github/allowed_signers:5) - Asset signature:
cosign verify-blob --bundle hMailServer-x.y.z-x64.exe.cosign.bundle --certificate-identity-regexp '^https://github\.com/Progressiverobot/hmailserver/' --certificate-oidc-issuer https://token.actions.githubusercontent.com hMailServer-x.y.z-x64.exe(source: SECURITY.md:94-104; sign-release.yml:30-36) - Signing is keyless Sigstore via GitHub OIDC, recorded in Rekor; no long-lived key exists (source: sign-release.yml:18-22; GOVERNANCE.md:111,123-125)
- Reproducible binary hash for v6.2.27:
8CD745C49657A2E02989A8A86E9290C0AA49D317466B860C3749C757C129410F(hMailServer.exe 6.2.27.37, identical across three clean Release builds) with the v145 toolset and the README library layout; the v6.2.24 hash was64406163b1a3a8a865e34d74883b5e2a05a5a1c476b500b26745cde67d8a989b(source: release notes' verification sections, gh) - The installer is NOT Authenticode-signed; SmartScreen/UAC do not read Sigstore signatures; Azure Trusted Signing is named as the realistic route (source: SECURITY.md:106-107; sign-release.yml:24-28)
- SBOMs: SPDX 2.3 JSON and CycloneDX JSON, produced by Syft plus the native-dependency merge (source: sbom.yml:55-85; build/merge-native-dependencies-into-sbom.ps1:4-9)
- Supported: 6.2.x yes; < 6.2 no (source: .github/SECURITY.md:5-8)
- Report privately via https://github.com/Progressiverobot/hmailserver/security/advisories/new; never a public issue/discussion/PR or the forum; fallback: a bare issue asking for a private channel (source: SECURITY.md:12-22)
- Targets: acknowledgement 5 working days; initial assessment 10 working days; fix for a confirmed vulnerability 90 days from acknowledgement; single maintainer, not contractual (source: SECURITY.md:26-34)
- Coordinated disclosure on a 90-day timetable; advisory published at fix or 90 days, whichever first; reporter credited unless they decline; no NDA, no bounties; CVE requested through GitHub (source: SECURITY.md:36-47)
- In scope: RCE/memory corruption in protocol handlers; auth/authz bypass; TLS/crypto (DANE, MTA-STS, DKIM/ARC, certificates); SQL injection; privilege escalation via the service or COM API (source: SECURITY.md:49-58)
- Out of scope: findings requiring an existing administrator account; missing hardening on a listener deliberately exposed without TLS; scanner output with no demonstrated impact (banners, TLS grades); third-party dependency vulnerabilities with no path from hMailServer (source: SECURITY.md:60-75)
- Supply chain: SBOM (SPDX + CycloneDX) covering .NET and native deps on every release; committed binaries inventoried, checksummed and verified on every build (source: SECURITY.md:77-82)
- Issue template routes "Security vulnerability" to the advisory URL (source: .github/ISSUE_TEMPLATE/config.yml:3-5)
- Single-maintainer project stewarded by Progressive Robot Ltd; Christopher Holloway (@chrisholloway5) holds every role; decisions made in the open on the issue tracker (source: GOVERNANCE.md:13-15,29)
- Maintainer duties: accepting changes, releasing per RELEASE.md (full suite on the exact shipped binary, signing every asset), security response per SECURITY.md, direction via Roadmap.md, infrastructure/credentials (source: GOVERNANCE.md:31-47)
- Contributor: anyone who opens a PR; follows CONTRIBUTING.md; no CLA (source: GOVERNANCE.md:49-57)
- Reporter: SUPPORT.md for defects, SECURITY.md for security; credited unless they decline (source: GOVERNANCE.md:59-66)
- Decisions: maintainer decides with reasons recorded in the PR/issue/release notes; disagreements on the issue, reopening with a reproduction welcome; scope test is "does it serve people running this as a mail server in production"; compatibility with existing deployments is a standing constraint; security decisions are the maintainer's alone (source: GOVERNANCE.md:71-89)
- Becoming a maintainer: demonstrated sustained judgement plus willingness to take release and security duties; say so on an issue (source: GOVERNANCE.md:94-100)
- Critical assets: GitHub repo admin; release signing path (Sigstore keyless, no private key held); "code-signing material - signing the Windows installer"; build environment recipe (VS 2026/v145 + hMailServerLibs); test environment recipe (source: GOVERNANCE.md:108-114). NOTE: the installer is not Authenticode-signed today (SECURITY.md:107), so the "code-signing material" row describes an asset the project does not currently hold - see section 17.
- Continuity: knowledge bus factor 1; access continuity arranged (credentials in a managed arrangement a trusted person can reach); mitigations: everything scripted and committed, keyless signing, AGPLv3 permits a fork (source: GOVERNANCE.md:130-151)
- Changing GOVERNANCE.md: by pull request, maintainer decides with a reason (source: GOVERNANCE.md:156-158)
- Regulatory position: "out of scope as a manufacturer" under the EU Cyber Resilience Act and revised Product Liability Directive, reviewed 12 August 2026, self-assessment not legal advice; premises: AGPLv3, no paid edition/support/hosting, no telemetry, one individual (source: hmailserver/docs/RegulatoryScope.md:1-26, doc)
- Scorecard is measured and published to the OpenSSF API (
publish_results: true, since 5 September 2026); Branch-Protection and Code-Review checks are expected to fail on a single-maintainer repo (source: scorecard.yml:9-15,74-86)
Claims (source: ASSURANCE-CASE.md section 2):
- C1 unauthenticated peer cannot execute code/corrupt memory/crash via mail protocols
- C2 unauthenticated peer cannot read/modify/delete account mail or authenticate as one
- C3 credentials at rest not practically recoverable from a stolen database
- C4 credentials in transit not exposed and never sent to an unverified peer
- C5 untrusted content cannot alter a query, filesystem path or third-party protocol exchange
- C6 an authenticated user cannot reach another user's mail or gain admin capability
- C7 a user can verify the downloaded software is what the project published
Threat model actors A1-A6 (internet stranger, sending MTA, network attacker, authenticated user, malicious upstream DNS/TLSA/MTA, local attacker); administrators are explicitly NOT adversaries (source: ASSURANCE-CASE.md section 3). Trust boundaries B1-B6: TCP/TLS termination, protocol grammar, authentication, parameterised query, external process/filesystem, COM management plane (source: section 4).
Backing, as claimed and as checked in code:
- Single management seam: everything goes through
Server/COM/(source: ASSURANCE-CASE.md section 5; ARCHITECTURE.md "Patterns that matter", doc) - Fail-safe hash default:
PreferredHashAlgorithmread from[Settings]with default 4 (PBKDF2); values 0/1/2 are logged and replaced with 4; 3 = SHA256, 5 = Argon2id (source: hmailserver/source/Server/Common/Application/IniFileSettings.cpp:171,187, code) - Minimum acceptable scheme:
MinimumAcceptedHashAlgorithm, default 0 (source: IniFileSettings.cpp:198; IniFileSettings.h:152, code) - Pepper:
PasswordPepperstring setting, default empty (source: IniFileSettings.cpp:203; IniFileSettings.h:153, code) - Argon2id via OpenSSL EVP_KDF in
DeriveArgon2id(source: hmailserver/source/Server/Common/Util/Hashing/HashCreator.cpp:61-65, code) - Outbound TLS verification:
verify_peer | verify_fail_if_no_peer_cert(source: hmailserver/source/Server/Common/TCPIP/TCPConnection.cpp:556,602,609, code); DANE and DNSSEC inCommon/TCPIP/DaneVerifier.*andDnssecResolver.*;SslContextInitializer.*present (source:ls Common/TCPIP, code) - CSPRNG:
RAND_bytesappears in 37 server source files; the only remainingrand()is the MIME part-boundary string at Common/Mime/Mime.cpp:807, matching the document's stated exception (code) - SCRAM-SHA-256 referenced in TCPConnection.cpp/.h and PersistentAccount.h; TOTP in Common/BO/Account.cpp/.h (code)
- Session ceiling:
GetClientSessionCeiling()(source: IniFileSettings.h:209, code);DatabaseUnavailableMarker.cppexists under Common/SQL and is used by DatabaseConnectionManager.cpp, BackupExecuter.cpp, IniFileSettings.cpp (code) - Compiler hygiene: /WX, CFG, /GS-DEP-ASLR (see section 4; PE header verified)
- SMTP smuggling rule (CVE-2023-51764): bare-LF accepted only with "Allow incorrect line endings", and only at buffer end (source: ASSURANCE-CASE.md section 6, doc - not re-verified here; protocol readers should confirm the setting name)
- Static analysis: "CodeQL runs on every push and pull request" is exactly true for C# only. The C++ job "Analyze (c-cpp)" runs on every push to master, weekly and on dispatch, but not on pull requests (codeql.yml:163); since it moved to the hosted
windows-2025-vs2026image on 5 September 2026 it completes - e.g. run 34179895726 (push, 2026-09-08) "Analyze (c-cpp) (windows-2025-vs2026): success" (source:gh run view <id> --json jobs, gh; Roadmap.md:1368). Before that, every scheduled run since the job was added on 2026-08-13 had been cancelled waiting for a self-hosted runner that was never registered. - Fuzzing: libFuzzer harnesses under
fuzz/for MIME only; HTML/iCalendar/vCard not done; the corpus is generated bymake-corpus.ps1, not committed (source: fuzz/README.md:4-6,47; hmailserver/docs/Fuzzing.md:10-13). The /EHa +catch (...)crash-oracle problem is documented (Fuzzing.md "Why this waited on the crash oracle"). - Supply chain (C7): sign-release.yml, verify-binary-provenance.yml, sbom.yml, Dependabot, dependency-review (see section 8)
- Evidence table names:
fuzz/, CodeQL workflow,/WXin hMailServer.vcxproj, regression suite;Server/Common/BO/;HashCreator.cpp,IniFileSettings.cpp;TCPConnection.cpp,SslContextInitializer.cpp; CONTRIBUTING.md SQL rule;.github/workflows/sign-release.yml,verify-binary-provenance.yml,sbom.yml(source: ASSURANCE-CASE.md section 7) - Residual risk, stated: memory safety mitigated not guaranteed; native statement coverage not measured (only the .NET Control Panel is); reproducibility shown on one toolchain only; CFG is a mitigation not a boundary; bus factor 1; administrators inside the boundary; operator-chosen weakening (plaintext listeners, legacy hashes) is permitted with a warning (source: ASSURANCE-CASE.md section 8)
- Review cadence: revisit on any threat-model change and at least yearly (source: ASSURANCE-CASE.md "Reviewing this document")
- Project licence: GNU Affero General Public License v3, 19 November 2007 text in
LICENSE; SPDX identifier used throughout isAGPL-3.0-or-later(source: LICENSE:1-2; every build/*.ps1 header line 2; dco.yml:4, code) - README states AGPLv3 and points to
hmailserver/docs/Licensesfor third-party texts (source: README.md:568-571) - Copyright line used on source files: "Copyright (c) 2026 Christopher Holloway / Progressive Robot Ltd and the hMailServer contributors" (source: build/build.ps1:1 and all others, code)
- Header enforcement:
build/add-license-headers.py --checkin the "SPDX identifier on every source file" required check (source: style.yml:43-55) - Local nit: run today, the check flags
hmailserver\source\Server\hMailServer\hMailServer.h(MIDL output) - that file is gitignored (.gitignore:24) so CI never sees it, but the script's SKIP_FILES does not list it (code) - Third-party licence texts held: 7-Zip, Boost, Fat Cow Icons, MIME Message encoder analyzer, Microsoft SQL Server Compact Edition, OpenSSL, PostgreSQL interface, RMSPF, String library, ZLib, plus
License list.ods(source:ls hmailserver/docs/Licenses, code) - Known licence gap: no LGPL-2.1 text for MariaDB Connector/C although twenty committed files and the installer include it;
msado28*.tlbredistribution terms not established (source: hmailserver/docs/ThirdPartyBinaries.md "Not yet done", doc; Licenses dir confirms absence, code)
- Out-of-tree (built by the developer or by CI's native-dependencies action, referenced via hMailServerLibs): OpenSSL 4.0.2, Boost 1.92.0, PostgreSQL 18.3 libpq (source: hMailServer.vcxproj:76; README.md:287-336; build/Get-LibraryVersions.ps1)
- In-tree vendored source (not a committed binary, so outside the manifest): zlib 1.3.1 under
hmailserver/source/Server/zlibwith its LICENSE, compiled into hMailServer.exe for IMAP COMPRESS=DEFLATE (in the tree after 6.2.27, not yet in a published release);build/native-dependencies.ps1lists only openssl/boost/postgresql, so zlib is not yet named in the SBOM (source: hmailserver/source/Server/zlib/zlib.h:40; hMailServer.vcxproj; build/native-dependencies.ps1, code) - Manifest
hmailserver/docs/third-party-binaries.json: schemahmailserver-third-party-binaries/1, 40 artifacts, fields path/sha256/size/component/version/publisher/license/upstream/authenticode/authenticode_signer/disposition/used_by/why (source: JSON parse, code) - Dispositions: retain 13, retain-review 13, remove-duplicate 10, remove-unused 3, retain-generated 1 (source: JSON parse, code; matches ThirdPartyBinaries.md "short version" table)
- Authenticode: 12 Valid (10 MSVC runtime signed by "Microsoft Windows Software Compatibility Publisher", 2 SQL CE MSIs by "Microsoft Corporation"), 28 NotSigned (source: JSON parse; ThirdPartyBinaries.md "Authenticode")
- Components: MariaDB Connector/C 3.4.9 (20 files: 10 under
libraries/mariadb-connector-c-3.4.9/, 10 byte-identical duplicates underinstallation/Extras/), MSVC v145 runtime 14.51.36231.0 (10,installation/Microsoft.VC145.CRT/), ADO 2.8 type libraries (2,libraries/msado28/, PE images despite .tlb), SQL Server Compact 4.0 SP1 x64 MSI (Microsoft withdrew the download; this copy is the archive of record), SQL CE x86 MSI (unused), 7za.exe 19.00 (upstream 26.02; refresh candidate), ISC.dll (unattributed, exports CheckPorts(), used by the installer - "should not survive to the next release"), isxdl.dll (declared, never called), atl70.dll (VS .NET 2003 ATL, vestigial), dnsapi.dll (Windows 2000, never loaded), Interop.hMailServer.dll (ours, AGPL) (source: ThirdPartyBinaries.md inventory tables; JSON component counts, code) - Policy: a binary may be committed only if listed in the manifest; changing one means changing its entry in the same commit; prefer not committing > vendor-signed original > hash+URL; unattributed binaries not acceptable long-term (source: ThirdPartyBinaries.md "Policy")
- Update procedure: change file, update
sha256/size/version/upstream/authenticode((Get-FileHash <path> -Algorithm SHA256).Hash.ToLower()), update the doc row, push (source: ThirdPartyBinaries.md "Updating the manifest") - Scorecard
Binary-Artifactsannotation deliberately NOT added until the 13 remove-* entries are gone (source: ThirdPartyBinaries.md "Relationship to OpenSSF Scorecard") - CI does not re-verify Authenticode (Linux runner) (source: ThirdPartyBinaries.md "Not yet done"; verify-binary-provenance.yml:29-33)
-
libraries/also contains the library build scriptsbuild-openssl.ps1,build-boost.ps1,build-pgsql.ps1and their sharedbuild-common.ps1, plusasio-overrides,fat_cow_icons,mssqlce3.5, and licence .rtf copies; its README.md still reads "hmailserver-dependencies-v1 ... This repository contains hMailServer external dependencies" (stale text from the separate upstream repo) (source:ls libraries; libraries/README.md:1-4, code) - MariaDB Connector/C is loaded at runtime from beside the exe (
libmysql.dll) with plugins viaMYSQL_PLUGIN_DIR; supports MySQL 8caching_sha2_password, MariaDBed25519/gssapi(source: ThirdPartyBinaries.md "Required in the tree"; README.md:101) - Interop wrapper regeneration documented in
hmailserver/source/Tools/Interop/README.md(see section 3)
-
Find-MsBuild.ps1- shared vswhere-based MSBuild locator (dot-sourced by the build scripts) -
Get-LibraryVersions.ps1- report the OpenSSL/Boost/PostgreSQL versions the project is pinned to, parsed from hMailServer.vcxproj (openssl=4.0.2,boost=1.92.0,postgresql=18.3plus the*_dirfolder names); CI uses it for the library cache keys and DLL paths -
add-license-headers.py- adds a copyright line + SPDX identifier to every source file lacking one;--checkreports and exits non-zero; handles BOM, CRLF/LF, shebangs, PowerShell help -
analyze.ps1- the static-analysis build: Release x64 rebuilt from scratch with MSVC/analyze, findings summarised by code and file intologs\analyze-warnings.txt(replaces the Release binaries; rebuild before a gate) -
build.ps1- MSBuild the server solution (x64, build events off;-Configuration,-Clean) -
build-tests.ps1- restore the test packages via the parent test solution, then MSBuild RegressionTests.sln (x64) -
build-tools.ps1-dotnet publishthe five setup/migration tools into theirpublish\folders (not the Control Panel) -
capture-cp.ps1- screenshot the running hMailCP window, optionally navigating via UI Automation (-Out,-Nav,-Launch) -
capture-dialog.ps1- open the Domain Properties dialog in the running hMailCP and screenshot it -
check-authz-choke-point.py- fail if any file other than ACLManager and its listed callers namesGetPermissionForFolder(,GetUseIMAPACLorGetAclEnforcementEnabled: every folder-access decision stays ACLManager's -
check-catalogues.py- read each translation catalogue against the English: server literals (log stage names, INI/setting names, INBOX, typed syntax) preserved, page references use the page's translated title, every number kept -
check-db-scripts.ps1- build a throwaway SQL CE database from CreateTablesMSSQL.sql and apply every upgrade script using SQLScriptParser's rules -
check-ini-coverage.py- every[Settings]keyIniFileSettingsreads is named somewhere in the Control Panel (with an EXEMPT list) and is read throughIniFileSettingsso the database mirror sees it -
check-localisation.py- the generated English catalogueStrings.resxmatches theL()/F()/N()/{loc:L}marks (--writeregenerates it); every language keeps placeholders and Alt keys; the 17 languages inCOMPLETEtranslate every key; files inLOCALISEDcarry no unmarked caption -
check-mnemonics.py- every static Control Panel caption (XAML and code-built) carries an Alt-key mnemonic and no two on one view or method share one -
check-roadmap.ps1- reconcile Roadmap.md tick boxes against per-section counts and the contents table; exits non-zero on drift -
check-schema-versions.ps1- prove the schema upgrade chain is contiguous, forward-only and complete for every backend (pwsh 7) -
find-stale-roadmap-rows.py- flag not-started roadmap rows that name symbols present in the tree (advisory, not a gate) -
generate-public-suffix-list.ps1- regenerateCommon/AntiSpam/DMARC/PublicSuffixListData.hfrom the Public Suffix List (-ListFilefor a reproducible local copy) -
generate-settings-index.ps1- regenerate the Control Panel's Ctrl+K settings search indexSettingsSearchIndex.g.cs(CI verifies it is up to date) -
get-dotnet-runtime.ps1- download the .NET Desktop Runtime installer the hMailServer installer bundles (-Channel 10.0) -
hmconfig.ps1- export/diff/apply hMailServer configuration as JSON over the COM API;applyis a dry run without-Force, deletions need-AllowDeletetoo; passwords never exported -
make-app-icon.ps1- generate the Control Panel .ico (256/64/32/16 px) -
make-hmailserver-writable.ps1- grant Everyone Modify on the hMailServer install folders (elevates; test machines only) -
make-installer-art.ps1- generate the Inno Setup wizard bitmaps (164x314 and 55x55) -
merge-native-dependencies-into-sbom.ps1- add OpenSSL/Boost/libpq to a Syft SBOM (SPDX 2.3 or CycloneDX) in place, idempotent by PURL -
native-dependencies.ps1- emit the native dependencies as JSON, versions parsed from hMailServer.vcxproj include paths -
post-build.ps1- elevated wrapper for post-build.bat: copy runtime DLLs and the .tlb, register the COM server/service -
preflight-tests.ps1- verify the machine is in the known-good state for the regression suite;-Cleanremoves a stale ERROR log -
regenerate-interop.ps1- TlbImp the Release type library into Interop.hMailServer.dll and update its manifest hash/size -
register-com.ps1- elevated re-registration of the type library and interfaces (needed only when the IDL adds a NEW interface) -
run-tests.ps1- run the NUnit regression suite against the live service (-StopOnError,-Where) -
upgrade-test-database.ps1- apply pending schema upgrade scripts to the bench database through the running service's COM API (source: header comments of each file under build/, code)
- RELEASE.md line 59 and hmailserver/source/Tools/Interop/README.md line 15 contain a raw carriage-return byte where a backslash should be: the bytes are
build<CR>egenerate-interop.ps1, and RELEASE.md line 60 hashmailserver\docs<TAB>hird-party-binaries.jsonwith a raw TAB.grep -rF 'build\regenerate-interop' --include=*.mdfinds nothing. The intended text isbuild\regenerate-interop.ps1andhmailserver\docs\third-party-binaries.json(source: byte inspection of both files, code) - README.md:110 says "Schema | Database version 6027"; the code requires 6031 (Constants.h:173)
- Stale test-count comment: run-tests.ps1:9 "1361"; actual
[Test]count 2,124 at HEAD and the v6.2.27 gate was 2024 tests, 2017 passed, 7 explicit skips (the old ci.yml and server-build.yml comments have been removed) - GOVERNANCE.md:112 lists "Code-signing material - Signing the Windows installer" as a critical asset; SECURITY.md:106-107 and sign-release.yml:24-28 say the installer is not Authenticode-signed and the project has no certificate
- ASSURANCE-CASE.md section 6 says "CodeQL runs on every push and pull request"; codeql.yml skips the C++ job on pull requests (it runs on push to master, weekly and on dispatch, and completes on the hosted image since 5 September 2026)
- ASSURANCE-CASE.md section 6 says
/GS,/NXCOMPAT,/DYNAMICBASEare "active"; the vcxproj does not set them (MSVC defaults). The shipped binary does have DEP/ASLR/HEVA/CFG on and a load-config directory, so the claim is true in effect but not project-enforced - CONTRIBUTING.md:46-48 says a PR whose commits lack the trailer "fails the DCO check"; the check is skipped for OWNER/MEMBER/dependabot authors and is not a required status check, so it cannot block a merge on its own (dco.yml:39-42; ruleset)
- RELEASE.md:76 cites "Windows SDK 10.0.26100" as part of the reproducibility toolchain; the project pins
WindowsTargetPlatformVersionto10.0(latest installed), so the SDK is not fixed by the source - ASSURANCE-CASE.md section 6 describes the fuzz suite as having "a corpus, dictionaries and a regression directory"; fuzz/README.md:47 says
corpus\is generated, not committed (one dictionary file,dict/mime.dict) - ThirdPartyBinaries.md's "Twenty MariaDB Connector/C DLLs" and "40 committed binaries" both agree with the JSON manifest (20 MariaDB entries, 40 artifacts) - no contradiction, recorded as checked
- README.md:180 requires "An installed version of hMailServer 5.7 or later" to build - the regression environment doc requires the service to run from the repo build, NOT an installed copy (RegressionEnvironment.md:35-41)
- Whether the v6.2.24 installer is (un)signed with Authenticode was not checked against the asset itself; the statement is from SECURITY.md and sign-release.yml
- The SMTP bare-LF / "Allow incorrect line endings" setting name and behaviour (ASSURANCE-CASE.md section 6) - not grepped here; belongs to the SMTP reader
- Whether the OpenSSF Best Practices "Passing 100%" also covers Silver/Gold criteria - the page reports Passing only
- Why the three scheduled C++ CodeQL runs were cancelled (runner offline vs manual) - only the outcome was read
- Whether
libraries/mssqlce3.5is used by anything (not referenced in the manifest doc's inventory) - The Roadmap.md item total (RELEASE.md:31 and check-roadmap.ps1 say "750"; not counted here)
- Whether a second person currently holds any repository rights (GOVERNANCE.md says no; not checked via API)
hMailServer 6.3.8, the latest release (2 November 2026, schema 6108) · AGPL-3.0-or-later · Repository · Mirror on GitHub · Report a documentation error (a GitLab issue naming the page)
Home — full index
Start here
1. Install and run
- Before You Install
- Installing hMailServer
- Installing on Linux
- Running in a Container
- Profiles and Environment
- The Control Panel
- The Control Deck
- Your First Domain and Mailbox
- Connecting a Mail Client
- The Webmail
- DNS for Your Domain
- Migration
2. Secure it
- Encryption and Certificates
- Database TLS
- Encryption for People
- Stopping Spam
- Stopping Viruses
- Security Hardening
- Secure Defaults
- The Service Account
- Secrets at Rest
- Sign-in and Identity
- Security Policy
3. Operate it
- Monitoring and Health
- The SNMP Agent
- Backup and Restore
- Message Storage
- Compliance and eDiscovery
- Troubleshooting
- Diagnosing Stalled Mail
- Relocating an Installation
- Upgrading hMailServer
- Upgrading Guide
- The Update Feed
- Migrating the Database Backend
- High Availability Runbook
- Warm Standby
- Runbooks Digest
4. Extend it
- Rules and Sieve
- Aliases Lists and Public Folders
- Rooms and Equipment
- Mailing Lists
- Routes and Relays
- Mail In to a Webhook
- Outbound Shaping
- The COM API and Scripting
- Event Scripts
- The REST API
- Command Line
- APIs Reference
5. Contribute to it
- Project Handbook
- Architecture
- Contributing
- Release Process
- Governance
- Assurance Case
- Regression Test Environment
- Fuzzing
- Regulatory Scope
- Third-Party Binaries
Look it up — from any journey
- Settings Reference
- Settings Overview
- Capabilities and Configuration
- Control Panel Reference
- Control Panel Pages
- Ports Reference
- Changes-Since-6210
- Version-History-to-6210
- Glossary
About this wiki
- hMailServer 6.3.8 is the latest release (2 November 2026, schema 6108)
- Pages say since 6.3.4 where a feature is new in it
- AGPL-3.0-or-later
- Repository, the one place the project is worked on
- Its mirror on GitHub, since 18 October 2026, with no Issues
- Questions: a GitLab issue with the Question template, GitHub Discussions Q&A, or the forum
- Report a documentation error: a GitLab issue naming the page