Skip to content
hMailServer 6.3.8 is the current release, signed 2 November 2026. Windows and Linux, and an in-place upgrade from 5.3 or later, but for the original hMailServer's 5.7.Download 6.3.8 Documentation FAQ
  • 0 Votes
    1 Posts
    370 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.6 (6 October 2026) adds three one-way schema steps (6106 to 6108), changes more without a switch (DANE lookups that do not come back whole, external accounts' days to keep messages, the COM helpers, Windows folder permissions, the REST listener's Host) and installs by the live update from 6.3.4 or 6.3.5: read the 6.3.6 announcement before upgrading. hMailServer 6.3.7 (17 October 2026), a security release, adds no schema step (6108 stays, so the live update's rollback from it to 6.3.6 meets no newer schema) and installs by the live update from 6.3.4, 6.3.5 or 6.3.6, with the exceptions its announcement lists; it too changes what an upgraded server does without a switch: an authenticated submission is DKIM-signed as another hosted domain only when the account may send as the From address; a domain's or an account's rule may no longer set From, Sender, Resent-From, Resent-Sender, DKIM-Signature or the loop count, nor a Sieve script add or delete them or send notify from an arbitrary :from; RuleLoopLimit 0 stops out-of-office replies; the serveradmin role with a list of domains is confined to those domains over COM; forwards of outside mail take an envelope sender in the hosted domain only on a DMARC pass; the anti-virus action that removes attachments replaces a single-part attachment message with its note and deletes unreadable mail; SASL PLAIN acting as another account is refused; on Windows /ProtectFolders hardens the program folder, Bin and ControlPanel, the x64 installer's MariaDB Connector/C 3.4.11 drops MySQL Enterprise's Windows authentication, and an upgraded server keeps the .NET 10 Desktop Runtime it had, where the installers carry 10.0.13. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026), a security release, adds no schema step either (6108 stays, so the live update's rollback from it meets no newer schema) and installs by the live update from 6.3.4, 6.3.5, 6.3.6 or 6.3.7, with the exceptions its announcement lists; of what it changes without a switch, these are the most likely to need something done before upgrading: TlsMode=verify-full on MySQL or MariaDB without TlsCaFile, to a database server on the same machine, is refused with HM7535; on Windows a file whose path holds characters outside ASCII - the database's TlsCaFile or PostgreSQLSslRootCert, a TLS certificate or private key file, dh2048.pem, a client-certificate CA file, MessageStoreObjectCaFile, OAuth2PublicKeyFile or AcmeCertificateDirectory - may be refused with HM7534 or HM7536; on Linux files are named in UTF-8 whatever LANG says, so where a server ran under a LANG that is not UTF-8, each file or folder named outside ASCII is to be renamed to its UTF-8 name; a sign-in name spelt otherwise than the stored address, in more than the case of the letters A to Z, or with white space at either end, may no longer sign in; an IP range of your own that allows some addresses none of SMTP, POP3 and IMAP now closes the web services listener to them too; a REST body that is not one JSON object within the bounds is answered 400; an AcmeDomains host the certificate lacks is ordered at the first check, and one the CA cannot validate holds the renewal for the others; and on Windows setup refuses with exit code 7 a program folder, Bin or ControlPanel, or a folder or a link on the way to them, that another account controls, and refuses an installation of the original hMailServer's 5.7, which no upgrade step reaches: move such a server's mail over IMAP instead. See the 6.3.8 announcement. This topic covers what comes after the installer in an upgrade to 6.3.4 (27 September 2026, schema 6104): the 24 changes CHANGELOG.md lists under "What changes on upgrade without a switch", with what to do about each; what else differs coming from 5.x or early 6.x; what the server says when the schema and the server do not match; and how to go back. The path, the slow steps and the backup are in Upgrading to 6.3.4. Know this first: an upgrade cannot undo itself. An older server refuses a newer schema rather than misread it, so the database backup taken before the installer ran is the only way back. Going back from 6.3.4 can also need the hMailServer.ini you had before the upgrade, as Rolling back from 6.3.4 below explains. Keep a copy of both. The 24 changes, and what to do about each Numbered as CHANGELOG.md numbers them; all are since 6.3.4. # What changes What to do Detail 1 The database is the settings store (schema 6042); [Settings] in hMailServer.ini is its copy. A line edited in the file is put back and named as HM5804 Do not edit the file to prepare the upgrade; restart the old service once after your last change. Afterwards use the Control Panel, COM (Settings.SetIniSetting), REST (PUT /api/v1/settings/ini/{name}) or, on Linux, hmailserver --set-setting NAME=VALUE Upgrading to 6.3.4; Settings 2 211 keys apply when saved, 28 at a reinitialise, 2 at a restart A script that counted on nothing happening until the next start now sees its change at once Settings: when a save takes effect 3 SPF follows RFC 7208: 127.0.0.0/8 and ::1 no longer pass before any policy is read. SPF now works on Linux, where every check had been TempError A content filter that re-injects mail authenticates, or connects from an IP range with anti-spam off The anti-spam stack 4 The audit trail is on (schema 6043), kept until a retention is set; alerts are on, but nothing is mailed until AlertRecipient and AlertSenderAddress are set Set AuditRetentionDays, and the two addresses Alerts and the audit trail 5 Compromised-account detection starts in watch mode (schema 6071): it raises account.compromised and holds nothing Set compromise_detection_mode to enforce when you want a takeover held Hardening: compromised-account detection 6 A 421, or a provider's rate-limit 4xx, pauses that destination for OutboundBackoffMinutes (2, doubling to 60) Nothing; 0 turns it off Outbound shaping 7 A backup carries what an account keeps beyond its mail: address book, preferences, calendars, S/MIME keys, keywords and more Expect larger archives. One from 6.3.3 or earlier restores as it did, without them Backup and restore 8 The out-of-office memory is a table (schema 6060) Nothing: a restart no longer sends everyone the reply again Rules and Sieve: vacation replies 9 Collected addresses are suggestions under Other contacts; CardDAV serves only kept contacts Tell users a phone no longer receives collected addresses; Keep makes one a contact Calendars and contacts 10 In the container image, HM_SETTING_<key> and HM_PROPERTY_<name> are stored at every start, and the setting is refused to the other interfaces Remove the variable and start once without it. No container image of 6.3.4 is published In a container 11 GET /api/v1/me/search goes on from where it stopped Below Below 12 IMAP answers as the RFCs say: NO rather than BAD for a missing mailbox, \Seen set by every BODY[<section>] without .PEEK, SORT and THREAD ordering, APPEND byte for byte Test clients and scripts that relied on the old answers Connecting a mail client 13 MySQL and MariaDB tables become utf8mb4 (schema 6102), every table rebuilt MySQL 5.7.9 or MariaDB 10.2.2 or later, the ALTER privilege on the database, free disk of the order of the largest table Upgrading to 6.3.4; Databases on Linux: the upgrade floor 14 Schema 6101 adds two columns to hm_messages On a large store, time it on a copy first Upgrading to 6.3.4 15 The database connection is encrypted when the database server offers TLS, for MySQL and MariaDB without checking the certificate; PostgreSQL is unchanged Read the application log at the first start, or run --check-database; TlsMode and TlsCaFile in [Database] choose otherwise Choosing a database: encrypting the link 16 The administrator password is hashed again at the first successful administrator sign-in; a browser session made under the old hash ends once Sign in once. A file the service cannot write keeps the old value (HM7494) Hardening a public mail server 17 A COM change to a route, an incoming relay, a DNS black list, an SSL certificate or five more kinds of shared object takes effect at Save() Add Save() where a script relied on setting a property; the Control Panel is not affected The COM API on Windows: Save() 18 Mail labelled ISO-8859-1 is decoded as windows-1252 Below Below 19 A restore refuses an unsafe archive whole (HM7540) Nothing: no backup this server writes has such an entry Backup and restore 20 A rule's Run function action must name a plain function: otherwise HM5018 on Windows, and on Linux nothing runs and the ERROR log has a Script Error line Rename such functions to ASCII letters, digits, _ and $, not starting with a digit Event scripts: the 6.3.4 security fix; the advisory 21 A domain can no longer be named as one of the server's own directories Below Below 22 A one-time code is taken once, over COM and REST: a TOTP code the server has accepted is refused if it comes again within its window, but not counted as a wrong code, so it locks nobody out A script that sent the administrator's password and a code with every REST request now has only its first request in each half minute accepted, the others refused with 401: sign it in once with POST /api/v1/session and use the hmailsession cookie, or give it an API key The REST API: one-time codes 23 The outbound relay sends its OAuth2 token over TLS only: a route or the SMTP relay whose host is on OutboundOAuth2Hosts and whose connection security is none, or STARTTLS optional against a server that does not offer it, fails with a temporary 450 4.7.0 (HM5912), and the message waits for the route's retries Set that connection security to TLS or STARTTLS required. A route to Exchange Online on 587, set up as Microsoft documents it, is not affected Routes, relays and smart hosts: OAuth2 24 A hash stored before 6.3.4 of a password with a character above U+00FF is refused Set such passwords again, and soon Upgrading to 6.3.4; Hardening a public mail server Three that no table row can hold ISO-8859 (18). ISO-8859-1 is decoded as windows-1252, as every mail client reads it, and ISO-8859-2 to -9, -13 and -15 by their own code pages. There was no ISO-8859 name in the server's table at all, so a Western Windows server decoded Latin-1 right by accident and decodes it as before, one with another ANSI code page now decodes it right too, and on Linux Latin-1 is no longer turned into replacement characters. There is nothing to set. Reserved domain names (21). A domain's mail is kept in the directory named after it under the data directory, beside the server's own stores. So a single-label name such as protected, confidential, recoverable, discovery, quarantine, files, lists or blobs, in any case, or temp, events and database, which the Linux packages put there, is refused for a new domain and for a rename over COM (Domain.Save) and REST, and so in the Deck. The Control Panel already refused every name without a dot. A domain that already has such a name is still saved, so that it can be managed, and is named as HM7597 in the error log at every start and as domain_name_reserved on the first-hour checklist. Rename it: the rename moves each of its accounts' mailboxes and leaves the store's files where they are. Until then, a domain named recoverable, discovery, confidential or protected has its mail in a folder the backup leaves out. The search route (11). Only a client of GET /api/v1/me/search other than the webmail needs to change. A search with more hits than limit answered complete: true, more: true and could not reach the rest; it now answers complete: false, more: true with next_before_id, which before_id continues from. Hits come newest first across every folder by message id, where they came folder by folder (Performance.md). Coming from 5.x or early 6.x The 24 apply to you too, and so do the changes of every release in between: section 5 of Changes Since 6.2.10 lists what came without a switch from 6.2.10 to 6.2.28. On 5.3 to 5.5, back up first and test the restore. Four things are particular to an older installation, all on Windows: The Administrator is replaced by the Control Panel. hMailAdmin.exe was retired in 6.2. The Control Panel, hMailCP.exe, does everything it did, and its navigation tree mirrors the old layout. Your TOTP secret carries over. The PHP WebAdmin is gone. Administer a remote server with the Control Panel, which connects to it directly, or from a browser with the Control Deck. The "Administrative tools" component now only registers the COM type library for scripts on another machine. A pre-5 hMailServer.ini moves into Bin. The installer copies it from the Windows directory to Bin\hMailServer.ini, leaves a .old copy where it was and deletes the original; the server reads only the one in Bin. The .NET 10 runtime. Since the first release after 6.2.18 the Control Panel and the setup tools (DBSetup, DBSetupQuick, DBUpdater) need the .NET 10 Desktop Runtime. The installer bundles windowsdesktop-runtime-10.0-win-x64.exe and installs it /quiet /norestart when it is missing (6.3.7's installers carry 10.0.13 and install it only where no .NET 10 Desktop Runtime is installed at all: an upgraded server keeps the one it had, 10.0.12 where 6.3.4 to 6.3.6 installed it, and brings it to 10.0.13 or later through Microsoft Update or Microsoft's installer). If the runtime does not install. Upgrading.md says the server, native code with no .NET dependency, is left working without the Control Panel. The documentation's 18.5 says otherwise, and for an upgrade to 6.3.4, which always moves the schema, it is right: Upgrading.md itself says the setup tools need the runtime too, and the server refuses to start against an old schema, so there is no mail server until the schema is moved. Install the runtime (x64) by hand from https://dotnet.microsoft.com/download/dotnet/10.0, run DBUpdater.exe from the installation's Bin folder, then start the service. When it goes wrong At every start the server compares the version in hm_dbversion with the one it requires and refuses to run if they differ, in either direction. The ERROR log has one of these: Code and message What it means What to do HM5011: The database is too old for this version of hMailServer. Please run hMailServer Database updater (DBUpdater.exe) to upgrade it. The schema did not get all the way up Run DBUpdater.exe from the installation's Bin folder HM5011: The database is too new for this version of hMailServer. Please upgrade hMailServer. An older server against a newer schema: an old binary left in place, or a previous release reinstalled Install the matching or a newer server. Do not try to downgrade the database HM5010: Database version could not be detected. hm_dbversion could not be read at all Check the connection details in [Database] and that the login can read the table Both HM5011 messages end with Database version: <n>, Required database version: <m>. On Windows the service reports itself running before this check, so a refused start leaves a service Windows calls Running with nothing listening: read the ERROR log. A 6.3.3 server against a 6.3.4 database is the too-new case on purpose: step 6041 to 6042 changes only the version, the fence that keeps a 6.3.3 server, which lets hMailServer.INI win, away from a database that is now the settings store. Resuming. DBUpdater picks up from whichever version the database actually reports, so a retry after a partial upgrade resumes rather than restarting. A failed step leaves PostgreSQL exactly as it was and SQL Server normally so; MySQL, MariaDB and SQL Server Compact commit DDL as it executes and keep the steps that ran. The same chain also runs: on Windows, since 6.3.4, as hMailServer.exe --upgrade-database with the service stopped, without DBUpdater's window or the administrator password; it exits 0 (done, or nothing to do), 1 (failed; the output names the step) or 2 (no [Database] configured); on Linux as hmailserver --upgrade-database, which the .deb and .rpm run after installing; at the service's own start with UpgradeOnStart=1 in [Database] (since 6.3.4, off by default): a failing step refuses the start with HM5011 naming the step, and the next start resumes there. It backs nothing up, and belongs on one node at a time (Warm standby). DBUpdater exits 0 on success, 1 when the upgrade failed, 2 on a configuration error, and 3 when authentication was cancelled or, under /silent, could not be satisfied: see HM_ADMIN_PASSWORD in Unattended installs. The installer fails with a non-zero exit code of its own; treat that, or a schema version still on the old value, as the failure: select value from hm_dbversion; Asking for help. Give the versions you started from, the step DBUpdater stopped on and the database's own error number; Read this before you post has the rest. Without a GitLab account, email the Service Desk address, contact-project+hmailserver-hmailserver-86730559-issue-@incoming.gitlab.com: GitLab files it as a confidential issue, and replies come by email. Rolling back from 6.3.4 Uninstall 6.3.4. Restore the pre-upgrade database backup. This is the essential step: the schema is at 6104, and the release you go back to refuses it. Put the right hMailServer.ini in place before the older installer runs, because its /Register reads the file. Which file depends on whether 6.3.4 sealed the stored secrets, that is, whether a stored-secrets key was made: Sealed: restore the pre-upgrade hMailServer.ini. 6.3.4 writes the [Settings] secrets into the file as HMK1: envelopes, and an older server reads them as they are: its /Register hands ServiceAccountPassword's envelope to Windows as the service account's password, and the service cannot log on. Its first moments also run SRS, BATV and OAuth2 on the envelopes. Not sealed: the 6.3.4 file can stay. Its [Settings] section is a complete copy of the stored settings, and an older server reads the file as the truth, so a setting changed after the upgrade survives, wherever the server could write the file, which a Linux package installation's unit does not allow. Delete the [SettingsStore] section, which older builds ignore. They ignore [SettingsOverride] too, so move any value only it supplied into [Settings]. Check PasswordPepper. Since 6.3.4 it is kept in the file only, never sealed and in no backup 6.3.4 writes. The file the older server starts with must carry the value the hashes were made with: no pepper, or a different one, refuses every account hashed with Argon2id or scrypt. PBKDF2, the default, is not peppered. Install the release you came from. Sealed, with no pre-upgrade file? Set ServiceAccountPassword, and any other of those secrets you use, again with the older version's Control Panel, then run hMailServer.exe /Register again. The wiki's and the documentation's 18.6 reinstall before they restore the database; Upgrading.md restores first. Follow Upgrading.md: the older installer runs DBUpdater, which refuses a database newer than its own build, and its /Register reads the file. The data directory normally stays. Upgrading.md and the wiki's 18.6 say it does not normally need restoring, because no upgrade step rewrites message files; the documentation's 18.6 says to restore it with hMailServer.INI. Left in place, mail that arrived after the backup exists on disk with no metadata row in the restored database, and is invisible. That is what a rollback costs. What it does not do The rollback above is the Windows one. Chapter 18 and Upgrading.md give no package command for going back on Linux; the database rule is the same. No backup carries a [SettingsOverride] value; it lives only in the file of the machine that has it. Moving to another machine is not an upgrade: Moving to new hardware. Where to read more Upgrading hMailServer, 18.5 and 18.6; the documentation's 18.6 Upgrading.md and its wiki copy, Upgrading Guide CHANGELOG.md, 6.3.4, and Changes Since 6.2.10, section 5 SecretsAtRest.md, "Rolling back", and Settings Overview SetupChecklist.md and AccountRecovery.md, for items 21 and 22 Troubleshooting, for a start that fails
  • 0 Votes
    1 Posts
    159 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.6 (6 October 2026) is signed by the GitLab pipeline at the group path and installs by the live update from 6.3.4 or 6.3.5; from 6.3.6 the Control Panel installs an update with one click where the service is not an administrator, and on Linux a 6.3.4 or 6.3.5 server installs 6.3.6 with its package manager rather than by the live update, whose apply step on those versions is the one 6.3.6 fixes. See the 6.3.6 announcement. hMailServer 6.3.7 (17 October 2026), a security release signed at the same group path, was what the feed offered before 6.3.8: from 6.3.6 the live update installs it, with 6.3.6's file as its rollback image and no schema step between them; on Windows a service running as LocalSystem installs it itself, and under NT SERVICE\hMailServer an administrator presses Install update on the Control Panel's Server status page on the server, one Windows prompt; on Linux 6.3.6's own helper applies it to the generic packages and both AppImages, while a server from a per-distribution package upgrades with its package manager. From 6.3.4 or 6.3.5 what 6.3.6's notes said still holds, and a server whose UpdateSigningIdentity, UpdateSigningIssuer and UpdateSourceRepository still name the project's first path refuses 6.3.7 until the three are cleared, on 6.3.6 by deleting their lines from [Settings] in hMailServer.ini with an editor run as an administrator (on Linux sudo hmailserver --set-setting <name>=) and restarting the service. In 6.3.7's Control Panel, Updates is a page of its own under Maintenance. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026), a security release signed at the same group path, with the project's id, 86730559, in the certificate, is what the feed now offers: from 6.3.7 or 6.3.6 the live update installs it, with the running version's own file as its rollback image and no schema step between them, a service running as LocalSystem by itself and one under NT SERVICE\hMailServer by Install update on the server; from 6.3.4 or 6.3.5 what 6.3.7's notes said still holds; a server from one of 6.3.6's or 6.3.7's per-distribution packages is offered the generic package, which apt refuses on Debian 12 and dnf on Enterprise Linux 9, so upgrade it with its release's own package of 6.3.8; the three settings that name the project's first path refuse 6.3.8 too until they are cleared; and a server from 6.2.28 to 6.3.3, or from 6.3.3's AArch64 packages or AppImages, installs 6.3.8 by hand, once. See the 6.3.8 announcement. This topic covers the update check and the live update as 6.3.4 has them. The one thing to know first: no live update installs 6.3.4. It carries an Authenticode signature and no Sigstore bundle, so a server of any version that is offered it says it cannot be verified and downloads nothing. Every server installs 6.3.4 by hand, as Upgrading to 6.3.4 describes. A server from 6.2.28 to 6.3.3 has a second reason to do it soon: its live update will refuse 6.3.5, the first release to be signed on GitLab. Four steps, and where each is done Each step is separate and opt-in, and only applying runs anything. Step Control Panel (Windows) REST COM (Windows) Check Check for updates on Server status POST /api/v1/update/check Status.CheckForUpdate Download and verify Download update POST /api/v1/update/download Status.DownloadUpdate Apply Install update POST /api/v1/update/install Status.InstallUpdate Read the verdict the Server card of Server status GET /api/v1/update Status.UpdateState, Status.AvailableVersion, Status.UpdateLastError, Status.UpdateApplyOutcome The Control Deck's Update view does all four on either platform; on Linux there is no Control Panel and no COM. The state is 0 not checked, 1 up to date, 2 a newer release exists, 3 downloaded and verified, 4 installing, or 5 the last step failed (lastError says why). An on-demand check reads the feed whether or not the scheduled check is on. Starting an install from the Control Panel closes it, because the installer replaces its files. Turning the check on UpdateCheckEnabled is 0 by default, because a server must not call out to anyone until its administrator says it may. At 1 the server reads the feed at startup and then every UpdateCheckHours (24; below 1 is taken as 1, and the server sets no ceiling although the Control Panel's label says "1 to 168"). UpdateChannel is stable by default; prerelease makes pre-releases eligible. What it sends. A plain GET of the feed with nothing but the User-Agent the server always sends: no identifier, no configuration, no counts. Since 6.3.4 it no longer sends GitHub's X-GitHub-Api-Version header. Where the result shows. The application log, the Control Panel's Server status page, the Deck's Update view, COM, and GET /api/v1/update, which adds the release's page and date, the installer's address, size and digest, and the last apply's outcome. Setting the keys since 6.3.4. Use the Updates card of the Control Panel's API & monitoring page (in 6.3.7 Updates is a page of its own under Maintenance, and Ctrl+K takes the old title to it), PUT /api/v1/settings/ini/{name} with {"value": "..."} (administrator password only), hmctl ini set, or on Linux hmailserver --set-setting; the Deck has no editor for these keys. Every key here applies when it is saved, but a value stored with --set-setting while the service runs reaches it only at its next save, reinitialise or restart. Do not edit the [Settings] lines in hMailServer.ini: the database is the settings store, and Settings: when a save takes effect explains what happens to a line edited in the file. curl -u Administrator:pw -X PUT -H "Content-Type: application/json" -d '{"value":"1"}' http://127.0.0.1:8443/api/v1/settings/ini/UpdateCheckEnabled curl -u Administrator:pw -X POST http://127.0.0.1:8443/api/v1/update/check The feed Since 6.3.4 a server reads https://updates.progressiverobot.com without being told: /releases/latest, the newest stable release, on the stable channel, and /releases.json, every release, on the pre-release channel. GitLab Pages serves it from the project's releases. For the rollback the server looks one release up at /releases/tags/v<version>. Every address a server builds is a file answered 200, and the server follows no redirect. A release has the shape of GitHub's Releases API, and each installer's Sigstore bundle is an asset of its own, named after its file with .cosign.bundle added. A download is held to the size and the digest the feed gives. Since 6.3.4, a version with a suffix (6.3.5-rc1, 6.3.5rc1) is a pre-release whatever the feed's prerelease flag says, so the stable channel passes over it. A mirror. UpdateFeedUrl points the server at another feed, for a network without Internet access; empty is the built-in feed. It must be https unless it is on this machine. It may serve one release or a list, and the rollback's lookup keeps everything up to /releases of the value and adds /tags/v<version>, so the mirror answers that path too. A mirror changes where the server looks, not whom it trusts: every installer is still verified against the signers compiled in. Through a proxy. HttpProxy=host:port (or [ipv6]:port) sends every web request the server makes as a client through a forward proxy: the feed, the installer and its bundle, and the JWKS and token-introspection fetches of OAuth 2. An https address is tunnelled with CONNECT, and the certificate is verified against the real host. There is no place for credentials; a proxy that demands them refuses. A refusal reads The proxy <host:port> refused CONNECT to <host:port>: <its status line>, and a value without a port fails with HttpProxy must be host:port (or [ipv6]:port)., never quietly going direct. ACME and the outbound-relay OAuth2 token request do not use it. Download and verification Download update, POST /api/v1/update/download, Status.DownloadUpdate or UpdateAutoDownload=1 fetches the installer and its bundle into the data directory's Updates folder (Data\Updates on Windows; on Linux the file is the .deb or .rpm this server was installed from) and checks them without cosign and without the network: the file's SHA-256 is the one signed and the one the transparency log recorded; the certificate chains to Sigstore's Fulcio authority at the moment the log recorded the signature; the certificate is one of this project's signers, whole; the signature verifies under the certificate's key, and the log vouches for the entry under its own key. A file that fails is deleted, and the reason is in Status.UpdateLastError and the log. Nothing is run. The two signers, since 6.3.4. A certificate must match one entry whole. The GitHub workflow The GitLab CI pipeline Signs Every release from 6.2.19 to 6.3.3 The releases from 6.3.5 on: 6.3.5 at the path the project began at, 6.3.6 and later at the group path hmailserver/hmailserver Identity begins https://github.com/Progressiverobot/hmailserver/.github/workflows/sign-release.yml@ https://gitlab.com/Progressiverobot/hmailserver//.gitlab-ci.yml@refs/tags/v for 6.3.5; from 6.3.6, https://gitlab.com/hmailserver/hmailserver//.gitlab-ci.yml@refs/tags/v, the path the project moved to on 29 September 2026 Issuer https://token.actions.githubusercontent.com https://gitlab.com Repository id 1267388815, required 86730559, checked when the certificate carries one Held to Certificates issued before 18 September 2026, and releases up to 6.3.3 The tag the certificate names The pipeline is also trusted at the path of the group hmailserver the project is to move to, where the id 86730559 is required whatever any setting says. A server from 6.2.28 to 6.3.3 trusts the GitHub workflow alone. Further checks since 6.3.4. A file signed for one tag is refused as any other release. On Windows the installer's version resource must name the release it is installed as; on Linux the update helper installs nothing that is not an upgrade. On Windows only SYSTEM, the Administrators and the service's account may change the Updates folder; one that is a link, owned by anyone else or beyond repair is refused with HM6894, and nothing is downloaded or applied: delete it, and the server makes it again. Authenticode. UpdateRequireAuthenticode=1 adds, on Windows only, a check that the installer carries an Authenticode signature Windows trusts (no revocation check, no publisher pin). The installers have been signed since 6.3.1; 1 refuses earlier ones. It is on top of the Sigstore check, which cannot be turned off. The trust settings UpdateTrustRootsFile, UpdateLogPublicKeyFile, UpdateSigningIdentity, UpdateSigningIssuer and UpdateSourceRepository are for a site that signs its own releases. Leave them empty; set, the last three replace their part of every signer. Applying an update On Windows, Install update, POST /api/v1/update/install, Status.InstallUpdate or the unattended window does this, in order: Verifies the downloaded installer once more. Fetches and verifies the running version's installer as a rollback image, where the feed still offers it. Issues a single-use token for the database upgrade: 32 random bytes in a file only the machine's administrators can read, good for one hour and one use, given to the installer as /upgradetoken=<hex> in place of the administrator password. Drains, since 6.3.4: the SMTP, IMAP, POP3 and ManageSieve listeners close at the socket, so senders retry, and the queue pauses. It refuses with already draining while somebody else's drain is in progress: leave it, or wait, and apply again. Hands the installer to hMailServer.Updater.exe, copied from Bin into Data\Updates because the installer replaces Bin. The helper runs it silently, and only with the SHA-256 the server read; waits UpdateServiceWaitSeconds (180) for the service; and if it does not come back, reinstalls the previous version. Reports the outcome: one line, in the log, Status.UpdateApplyOutcome, the status page and GET /api/v1/update; since 6.3.4, as soon as the service is back. If the helper finishes without stopping the service, the server leaves the drain itself after ten minutes at most (HM7151 when the helper wrote nothing); the helper's log is apply-<version>.log in the Updates folder. Set ShutdownDrainSeconds (30 is a reasonable figure) so the stop waits for what is in flight. What a rollback cannot do. It reinstalls the previous binaries; it cannot take the database back. When the new version had moved the schema and then failed to start, the previous version refuses the newer schema, and the outcome says so. Every release's notes say whether it moves the schema; before one that does, take a backup (Backup and restore). The rollback image is verified like any installer, and 6.3.4's has no bundle. UpdateFeed.md does not say what a 6.3.4 server's first live update does about that, so plan it as one without a rollback image, and take a backup first. In the one case UpdateFeed.md describes, an old server set to the GitLab signer (below), the install runs without a rollback image, the log says no rollback image ... could be had, and a new version that does not start has to be reinstalled by hand. Under NT SERVICE\hMailServer, the account a new 6.3.4 installation on Windows runs as, the apply is refused before anything happens, before the rollback image and the drain: the installer needs an administrator. The update is still checked, downloaded and verified. REST, COM and the Deck say so, and tell an administrator to download the installer from the release page, check its Authenticode signature (Get-AuthenticodeSignature reports it Valid) and run it; never the copy in Data\Updates, which the service can write. An open unattended window logs HM7463 once per process instead of taking a backup for nothing, and the setup checklist carries update_apply_by_administrator while the check is on. An upgraded installation that kept LocalSystem applies as before. Installing on Windows covers the account. On Linux, since 6.3.4, the service writes a request to /run/hmailserver and the root path unit hmailserver-update.path runs /usr/lib/hmailserver/hmailserver-update, which verifies the package and the rollback image again as root, installs, and rolls back when the service does not come back. No token is involved: the package's post-install step runs the schema upgrade. A server not under systemd is told so and left with the verified file to install by hand. The hmailserver command line on Linux has the helper in full. Linux builds from 6.3.0 to 6.3.3 answer This build cannot apply an update. Unattended updates Key Default What it does UpdateAutoDownload 0 1 downloads and verifies a newer release's installer as soon as a check finds it UpdateWindow empty, never When a verified update may be applied without a click UpdateBackupBeforeApply 1 An unattended apply backs up to the configured backup destination first, and does not go ahead without a destination or when the backup fails UpdateWindow takes 03:00 (every day from 03:00, for an hour), Sun 03:00 or Sat,Sun 02:00-05:00: English three-letter days, local 24-hour times, and a range that crosses midnight belongs to the day it starts on. An unparsable value is logged once per process and nothing is applied. The backup covers the unattended path only, so take one yourself before an apply you start. Under NT SERVICE\hMailServer a window applies nothing (HM7463). On Linux: sudo hmailserver --set-setting UpdateCheckEnabled=1 sudo hmailserver --set-setting UpdateAutoDownload=1 sudo hmailserver --set-setting "UpdateWindow=Sun 03:00" sudo systemctl restart hmailserver A server from 6.2.28 to 6.3.3 These versions read GitHub's Releases API, which has answered 404 since GitHub suspended the project's account on 18 September 2026, so their check says The update feed answered HTTP 404. Nothing else breaks. Pointed at the new feed, such a server trusts the re-hosted releases up to 6.3.3, which carry GitHub's bundles, but its check now offers 6.3.8, the newest stable release, signed by the GitLab pipeline, which it cannot verify either: its live update installs nothing until 6.3.4 or later is installed by hand. It will also refuse 6.3.5 (The certificate names https://gitlab.com/Progressiverobot/hmailserver//.gitlab-ci.yml@refs/tags/v..., not this repository's release workflow.). These versions read [Settings] from the file, and a change needs a service restart. Turn automatic download off. With UpdateAutoDownload=1 such a server would download a GitLab-signed installer, about 80 MB, at every check and refuse it every time, because the verification comes after the download. Set it to 0. Point it at the feed, with exactly this line under [Settings] in hMailServer.ini, then restart the service: [Settings] UpdateFeedUrl=https://updates.progressiverobot.com/releases.json Without .json the address is a directory, answered with a redirect, and the check says The update feed answered HTTP 302. On Windows set it on the Updates card and let the Control Panel restart the service; or add it to Bin\hMailServer.INI as an administrator and run net stop hMailServer and net start hMailServer from an elevated prompt. On Linux: sudoedit /etc/hmailserver/hMailServer.ini # add the line under [Settings] sudo systemctl restart hmailserver An AppImage keeps it in $HMAILSERVER_HOME/hMailServer.ini, or else $XDG_DATA_HOME/hmailserver/hMailServer.ini, normally ~/.local/share/hmailserver/hMailServer.ini; start it again after the edit. Check. The answer should be that the newest release, 6.3.8, is available. Still 404 means the service has not read the line: check the section, the spelling and the restart. The update feed could not be read: ... names what stopped it: no route out, a proxy (HttpProxy), or a certificate the machine does not trust. Install 6.3.4 by hand, following Upgrading to 6.3.4, with the backup Upgrading.md describes. The service must have been restarted after your last [Settings] change, or 6.3.4's first start treats that change as an edit (HM5804) and undoes it. 6.3.4 and 6.3.5 had no AppImage and no AArch64 package; 6.3.6, 6.3.7 and 6.3.8 have both again, and such an installation takes the newest release's, 6.3.8's, by hand, once. Afterwards, 6.3.4 reads the new feed without being told and trusts both signers. The UpdateFeedUrl line can go, although leaving it changes nothing: clear it in the Control Panel, with DELETE /api/v1/settings/ini/UpdateFeedUrl, or on Linux with hmailserver --set-setting UpdateFeedUrl=, not in the file. Turn UpdateAutoDownload back on if you want it. The other way, Windows only. UpdateFeed.md gives values for UpdateSigningIdentity, UpdateSigningIssuer and UpdateSourceRepository that let such a server install a GitLab-signed release. While set, they make it refuse every GitHub-signed release, its own rollback image included; they are proved only once a GitLab-signed release exists; and they must stay set until the new version runs, then be cleared as step 5 clears UpdateFeedUrl, or the new version refuses what is signed after the project's move. Never point them at the group's path: an old server checks no repository id. Installing 6.3.4 by hand avoids all of this. The download links, and checking a file by hand https://updates.progressiverobot.com/download/<name> always leads to a file of the newest stable release, never a pre-release, and /download/ to that release's page. GitLab's own /-/releases/permalink/latest follows the release published last, a pre-release included. A server does not read these links. <name> is a file's name without its version: hMailServer-x64.exe, hMailServer-arm64.exe, hmailserver_amd64.deb, hmailserver_arm64.deb, hmailserver.x86_64.rpm, hmailserver.aarch64.rpm, hMailServer-x86_64.AppImage and hMailServer-aarch64.AppImage, each with its bundle at the same name plus .cosign.bundle. A name the release does not carry answers 404, never another release's file. 6.3.4 carries the x64 installer, the amd64 .deb and the x86-64 .rpm, and no bundle. Checking 6.3.4. With no bundle to check, 6.3.4 is checked by hmailserver-6.3.4-SHA256SUMS.txt, whose signature hmailserver-6.3.4-SHA256SUMS.txt.sig is made with the key that signs the release tags, and on Windows by the installer's Authenticode signature, which Get-AuthenticodeSignature should answer Valid, signed by Progressive Robot Ltd. The 6.3.4 announcement has the commands and what each must answer. Other releases. Up to 6.3.3, cosign verify-blob checks a file against its bundle and the GitHub identity (Verifying a release in the Security Policy). From 6.3.5 a release has no .sig; its files are signed with Sigstore, and on Linux hmailserver --verify-update <file> checks a download the way the server does. What it does not do It does not install 6.3.4, and does not apply under NT SERVICE\hMailServer. A rollback does not take the database back; a backup does. It follows no redirect and sends no proxy credentials. It does not drain a warm-standby pair: the drain is per process, so a pair drains one node at a time (Warm standby and high availability). Where to read more UpdateFeed.md, ServiceAccount.md, Upgrading.md, SettingsApply.md, and the Update check section of the README. On the wiki: Upgrading hMailServer, Settings Reference, The REST API, Security Policy and Installing on Linux. The documentation page: Staying up to date and Self-update. On the forum: Upgrading to 6.3.4; Upgrading from 5.x, 6.2 or 6.3, for what 6.3.4 changes and rolling back by hand; and The Control Deck. Without a GitLab account, a question or a bug can go to the project's Service Desk, contact-project+hmailserver-hmailserver-86730559-issue-@incoming.gitlab.com. A suspected vulnerability goes only by the routes of SECURITY.md: a confidential GitLab issue or that same address, which GitLab files as a confidential issue.