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
    92 Views
    chrisC
    This release is superseded by hMailServer 6.3.6, published on 6 October 2026, which fixes security flaws in every earlier version, 6.3.5 included. Read its announcement before upgrading. hMailServer 6.3.5 was published on 29 September 2026. It is the first release the project's GitLab CI made from its signed tag. The tag's pipeline built the Windows installer after the whole Windows suite had passed, signed it with Authenticode, signed every file of the release with Sigstore, and checked every signature with the server's own verifier before anything was published. A 6.3.4 server trusts that signer, and a 6.3.4 server has installed 6.3.5 by its own live update. The release also fixes two defects 6.3.4 has, and lets an administrator review the quarantine by the sender's domain and the HELO name. The schema moves from 6104 to 6105 in one step. Who is affected Every server on 6.3.4. Two of its defects are fixed: A mail flow rule with a Readable text or Sensitive content found condition, which 6.3.4 added, read a message's HTML part in time that could rise with the square of its size. 400,000 &amp; - two million characters - held the delivery for about a minute, and on a server with such a rule anybody could send one. Each entity is now unwrapped in one pass, with the same result. A server with no such rule was not affected. An invitation whose calendar part carries parameters in its Content-Type and has no .ics name - the shape Outlook sends - was never marked as an invitation, so the webmail showed no card for it. It now shows the card with Accept, Maybe and Decline. A server older than 6.3.4 gets everything 6.3.4 brought as well, including the fix for CVE-2026-100741. Read the 6.3.4 announcement first: all of its "Before you upgrade" applies. Before you upgrade Back up the database and the data directory first. The schema goes from 6104 to 6105 in one one-way step, which adds a column to the quarantine's table, hm_quarantine.quarantinehelo. From 6.3.3 or older the upgrade runs 6.3.4's steps first, and 6.3.4's notes apply: on MySQL and MariaDB, step 6102 rebuilds every table as utf8mb4, and at the first start the [Settings] section of hMailServer.ini moves into the database. A server from 6.2.28 to 6.3.3 cannot install 6.3.5 by its live update. It trusts only the GitHub workflow that signed the releases up to 6.3.3, and it refuses a file the GitLab pipeline signed: "The certificate names https://gitlab.com/Progressiverobot/hmailserver//.gitlab-ci.yml@refs/tags/v..., not this repository's release workflow." Nothing is installed and the server runs on. What to do: Install 6.3.4 or 6.3.5 by hand, once. On Windows run hMailServer-6.3.5-x64.exe over the existing installation; on Linux install the .deb or the .rpm with apt or dnf. After that the server reads the new feed without being told and trusts both signers. Until then, keep UpdateAutoDownload off. With it on, such a server downloads the whole installer, 84 MB, at every check and refuses it every time, since the verification comes after the download. Its update check works only once it is pointed at the new feed: under [Settings] in hMailServer.ini, UpdateFeedUrl=https://updates.progressiverobot.com/releases.json, then restart the service. On Windows only, there is a second way: three settings that make the old server trust the GitLab signer. They cost the rollback image, must be cleared afterwards in the Control Panel or over REST (not in the file), and must never name the group path hmailserver/hmailserver. UpdateFeed.md, "Having the live update make that upgrade anyway", gives the values and the costs. Installing by hand is simpler. The live update from 6.3.4 A 6.3.4 server reads https://updates.progressiverobot.com without being told, and trusts the identity the GitLab pipeline signs with; that verifier is unchanged in 6.3.5. On the Control Panel's Status page: Check for updates, Download update, then Install update; or POST /api/v1/update/install over REST, or Status.InstallUpdate over COM. With UpdateAutoDownload on and an update window open, the server does it by itself. It was tried on 29 September 2026 on a clean Windows Server 2025, against the published release and the live feed: A service running as LocalSystem found 6.3.5, downloaded and verified it, took its backup and installed it. The schema went from 6104 to 6105, mail was unavailable for about 24 seconds, and the domain, the account, its messages and the settings were intact. A server upgraded to 6.3.4 that kept LocalSystem runs this way. A service running as NT SERVICE\hMailServer does not install it itself. That is how a new 6.3.4 installation runs the service. Such a server found, downloaded and verified 6.3.5, then logged HM7463 and left the install to an administrator. Download the installer from the release, check that Get-AuthenticodeSignature says Valid, and run it as an administrator - not the copy the server downloaded, which is in a folder the service can write. There is no rollback image for 6.3.4. Before it installs, the server fetches and verifies the installer of the version it runs, to put it back if the new one does not start. 6.3.4 carries no Sigstore bundle, so that copy cannot be verified, and the application log says "Update: no rollback image for hMailServer 6.3.4 could be had (release 6.3.4 carries no x64 installer with a Sigstore bundle.); if 6.3.5 does not start, it will need a manual reinstall." Take the backup first. On Linux the live update was not part of that test. A server installed from the release's own amd64 .deb or x86-64 .rpm is offered the same file of 6.3.5. A server installed from a .deb or .rpm the CI builds for another distribution release is offered the release's file too, whose dependencies its distribution may not meet; apt or dnf then refuses it and the server stays as it was. One installed from an AArch64 package, an AppImage or the ARM64 installer is told that the release carries nothing for it to download. The test found three defects in code 6.3.4 and 6.3.5 share, to be fixed in 6.3.6: the outcome of an update is dropped by the check that runs one second after start-up, so Status.UpdateApplyOutcome is empty though the log has it; a first check on a new machine can fail with "The response carried no HTTP headers", which hides the real cause (on the test machine, probably a slow first certificate revocation check); and a service that cannot install downloads the installer again after every restart. What changes on upgrade without a switch The 6.3.5 section of CHANGELOG.md lists five. The Control Panel's sidebar is in a new order. Welcome and Dashboard come first, then a new group, Set up this server: the Setup checklist (it was External setup, under Monitoring & troubleshooting), Setting profiles and DNS records. TLS & certificates is now Certificates & encryption, and Access & abuse protection is Sign-in & access. Connections & protocols has a new Webmail page. Ctrl+K still finds the checklist as External setup. A page's nav-<key> UI Automation id is unchanged; the navgroup- and navrail- ids of the new and renamed groups follow their new headings, so a UI test that finds a group by its old id must be changed. The quarantine shows the HELO name, and groups. The Control Panel's Quarantine page and the Control Deck's Quarantine view have a HELO column and group held messages by the sender's domain unless told otherwise. Messages held before the upgrade have no HELO name recorded. The Deck now asks before a delete with a Yes or No of its own whose default is No; it used the browser's confirm(), whose default is OK. It offers whitelist and blacklist only to a credential holding manage_settings, and a held message's headers and preview only to one holding view_mailbox, as the server requires. The webmail's keyboard. The message list is one Tab stop, and its keys reach what a row holds. Enter on a button in the mail view presses the button; it used to open the message under the list's cursor. A letter typed into the formatted signature is text, where c opened a new message. Escape closes every modal dialogue as its Cancel does. The compose window's Plain is Remove formatting. Invitations. GET /api/v1/me/messages/{id} answers "invitation": true for the Outlook-shaped invitation above, where it answered false. What a script sees. GET /api/v1/quarantine gives each message three more fields - helo, sender_domain and helo_domain - and four routes are new. Over COM, Quarantine gains Bulk and QuarantinedMessage gains HeloName, SenderDomain, HeloDomain, ReadHeaders and ReadPreview, added to the existing interfaces; no existing member or dispid changes. A program built against 6.3.5's type library that calls one of them needs a 6.3.5 server. Also in this release Reviewing the quarantine: grouping by the sender's domain, by the HELO name's domain or not at all; release, delete, whitelist then release, and blacklist then delete, on one message, a group or the checked ones, with a dry run first; and a held message's headers and a plain-text preview read without releasing it. The Control Deck does the same as the Control Panel (SenderListsAndDigests.md). Every database setting that should have an editor has one in the Control Panel: 137 that needed one and had none, on new tabs and on the new Webmail page. 103 of them are reached over the REST API alone, which is off as shipped (RestApiPort 0); with it off, each such tab says so. The Control Panel and the webmail, audited in both themes, by keyboard and, for the webmail, with NVDA in English and German: contrast raised where it fell short, focus rings restored, and 82 texts that were English on a translated webmail page are now in all 23 languages. The packages for Debian, Ubuntu, Fedora, RHEL and openSUSE, for x86-64 and AArch64, the AppImages and both Windows installers are built on GitLab CI, on the project's own runners. Only the files listed below are in the release; the others are CI job artifacts, kept for 7 to 30 days, not signed and not offered by the update feed. Reproducible Linux packages: the server, the .deb and the .rpm are built a second time from a copy of the tree at another path, and the release waits until all three are byte for byte the same. How it was checked Every gate of the tag's pipeline passed: the Windows suite on the project's Windows runner, 3,828 tests, 3,753 passed, 0 failed, 74 skipped and 1 inconclusive; the Linux suite on the project's Linux runner, 2,213 tests, 1,892 passed, 0 failed, 321 skipped; linux-repro, which rebuilt the .deb and the .rpm byte for byte; the static analysis, Semgrep and the dependency scan. The signed installer then went through the installer smoke test on a clean Windows Server 2025: an upgrade from 6.3.4 passed 93 checks and a new installation 59, none failed. No ARM64 Windows installer in this release The pipeline has a job that builds the ARM64 installer, and it may fail without failing the pipeline. In 6.3.5 it fails: its toolchain check looks for Visual Studio's ARM64 C++ runtime by a path that finds it in no installation, so it stops on the Windows runner, which has the ARM64 tools, ATL and SDK libraries, and prints a command that changes nothing. The check is corrected for the next release. Even then, the ARM64 installer is a CI job artifact only, not signed and not in the release, and the ARM64 build has never been run on ARM64 hardware (WindowsOnArm.md). What 6.3.5 does not carry No ARM64 Windows installer (above). No AArch64 .deb or .rpm, no AppImage and no SLSA provenance. The pipeline builds the AArch64 packages and the AppImages as CI job artifacts only, and the provenance generator the releases up to 6.3.3 used is GitHub's. 6.3.3's AArch64 packages and AppImages are still the newest published. 6.3.6 is to carry all three. No container image. registry.gitlab.com/progressiverobot/hmailserver is empty: the pipeline pushes and signs the image only once the project has moved to the group hmailserver and the owner has switched it on. No apt or dnf repository yet: the job that makes them publishes nothing until the repository's signing key exists (PackageManagers.md). Not in winget or Chocolatey yet: the first submission to each is made by hand, and has not been made. Downloads, and how to check them The release carries nine files, each with its Sigstore bundle, <file>.cosign.bundle, beside it: hMailServer-6.3.5-x64.exe, the Windows x64 installer; hmailserver_6.3.5_amd64.deb for Ubuntu 26.04 and 24.04, and hmailserver-6.3.5-1.x86_64.rpm for Fedora 43 and 44 and Enterprise Linux 10. Their dependencies are 6.3.4's: the .deb asks for glibc 2.38 or later, so it does not install on Debian 12, and the .rpm does not install on Enterprise Linux 9. An SBOM for each of those three, <file>.cdx.json (CycloneDX 1.6), whose subject is that file by its SHA-256 and SHA-512; and the source tree's SBOMs, hmailserver.spdx.json and hmailserver.cyclonedx.json. hmailserver-linux-6.3.5-SHA256SUMS.txt, the SHA-256 of the two Linux packages. There is no SSH-signed sums file this time: the pipeline cannot hold the key that signs the release tags, so every file is signed with Sigstore instead. https://updates.progressiverobot.com/download/hMailServer-x64.exe, /download/hmailserver_amd64.deb and /download/hmailserver.x86_64.rpm always lead to that file of the newest stable release, never a pre-release's; add .cosign.bundle for its bundle. https://updates.progressiverobot.com/download/ leads to that release's page. To check a download with cosign, with the file and its bundle beside you: cosign verify-blob --bundle hMailServer-6.3.5-x64.exe.cosign.bundle \ --certificate-identity 'https://gitlab.com/Progressiverobot/hmailserver//.gitlab-ci.yml@refs/tags/v6.3.5' \ --certificate-oidc-issuer https://gitlab.com hMailServer-6.3.5-x64.exe It must succeed (exit status 0). The identity names the tag, so a file signed for another release does not pass. If your cosign has the --new-bundle-format option and does not use it by default, add it: the release's own signing job passes it wherever cosign offers it. On Linux, a server from 6.3.4 on makes the same check its live update makes: hmailserver --verify-update hmailserver_6.3.5_amd64.deb with hmailserver_6.3.5_amd64.deb.cosign.bundle beside the file. It takes any file of the release; the release's pipeline ran it on every one before publishing. It answers hmailserver_6.3.5_amd64.deb verifies: signed by https://gitlab.com/Progressiverobot/hmailserver//.gitlab-ci.yml@refs/tags/v6.3.5, recorded by the transparency log at ... and exits 0, and exits 1 for a file that does not verify. It does not check which release the file belongs to, so read the identity it prints: it must end in @refs/tags/v6.3.5. Then: sha256sum -c hmailserver-linux-6.3.5-SHA256SUMS.txt must say OK for each package (add --ignore-missing when you downloaded only one). On Windows, Get-AuthenticodeSignature .\hMailServer-6.3.5-x64.exe must answer Valid, with a signer certificate for CN=Progressive Robot Ltd. In a clone, git -c gpg.ssh.allowedSignersFile=.gitlab/allowed_signers verify-tag v6.3.5 must say Good "git" signature for [email protected]. The release's own notes, under Verification, give each file's SHA-256 and the certificate the pipeline was given. SECURITY.md, "Verifying a release" and "Software bills of materials", has the rest, including how to check that an SBOM describes your file. Reporting a vulnerability Not in a thread here, and not in a public issue. Report it privately, as SECURITY.md says: a confidential issue on GitLab - check that it is still marked confidential before you submit it, and choose the Security template - or an email to contact-project+hmailserver-hmailserver-86730559-issue-@incoming.gitlab.com, which GitLab files as a confidential issue, so no GitLab account is needed. Release notes, checksums and downloads · Newest stable release
  • 0 Votes
    1 Posts
    143 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) confines an account given the serveradmin role with a list of domains to those domains over COM as over REST, so it is no longer the server's administrator: give the role with no list to an account that is to administer the whole server, a script's or a Control Panel's account among them. Over COM, one given domainadmin with a list that leaves out its own domain no longer administers that domain's ordinary accounts; 6.3.4 to 6.3.6 allowed both where REST refused them. A role is given or taken away only by a credential that holds manage_roles in the account's domain and takes in what the account holds now and afterwards, and a credential confined to named domains is refused over COM, as over REST, a domain's rename, a domain alias, a relay host changed to an address that is not public and an action on a domain's or an account's rule that reaches one of the server's own addresses, a configured route or a function of the event script. Rule.Save and RuleAction.Save refuse, on a domain's or an account's rule, a Set header value of From, Sender, Resent-From, Resent-Sender or DKIM-Signature and a Reply from an address the owner may not send as, and on a rule of every owner a Set header value of the loop count; one stored before the upgrade is taken without that action, and the application log names it. For a rule of every owner they refuse a Run function that is not a plain function, which one stored before still meets when the rule fires, as since 6.3.4. Utilities.CheckSieveSyntax refuses a Sieve script that adds or deletes From, Sender, Resent-From, Resent-Sender, DKIM-Signature, Auto-Submitted or the loop count. Once the database has ended a Database object's transaction, every later statement is refused and Database.CommitTransaction fails: call Database.RollbackTransaction and run the whole transaction again, or stop. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026) signs a name in over COM, as at every other sign-in, only when it is the account's stored address, compared in lower case after a domain alias and the default domain: a mailbox address spelt otherwise, in more than the case of the letters A to Z, or with white space at either end, may no longer sign in; it fails as a name that does not exist fails, and is counted as a failure. See the 6.3.8 announcement. This topic covers the COM API of hMailServer 6.3.4: what a script connects to and how it authenticates, the object model and the shape every collection shares, working PowerShell examples, the change 6.3.4 makes to when a configuration change takes effect, what 6.3.4 adds to the object model, administrator roles over COM and why API keys are not there, the changed-from-stock document, the COM surfaces of distribution lists and the directory, and the Import Tool. The one thing to know first is that the COM API is Windows-only, and that an object you add to a collection, or an item of one you change, is not stored until you call its Save(); a few writes need none, among them an account's SieveScript and Settings.SetIniSetting, and an address saved or deleted through Route.Addresses needs no Save() of the route. Since 6.3.4 the running server's routes, relays and other shared configuration objects also wait for that Save(); up to 6.3.3 they changed the moment a property was set. What you are connecting to hMailServer exposes a full COM API. Almost anything the Control Panel can do, a script can do, because the Control Panel does its work through COM. The exceptions are the pages that edit a file on the server itself: REST API keys (described under roles below), the two directory pages' [LDAP] section, the sending limits on Server limits & expert settings, the [Database] rows of the Performance page, and the event script; and Discovery, which reads the REST listener because eDiscovery has no COM interface. The COM API and the Control Panel are both Windows-only: a Linux server is administered over REST, hmctl and the Control Deck (hMailServer on Linux: what you get and what you do not). One type library, hMailServer, with 94 coclasses in 6.3.3 and 100 in 6.3.4. The root is Application, ProgID hMailServer.Application. Every interface is a dual IDispatch interface, so late binding works without registering the type library. CreateObject, New-Object -ComObject and C# dynamic all work on a machine where only the server is installed. Early binding depends on vtable order, so new members are always appended, never inserted. An interop assembly built against 6.3.3 keeps working; recompile it to reach the new members, and on a hand-copied installation register the server again, elevated, so that the new interfaces are known to COM. Late-bound scripts need nothing. The installer's admintools component exists only to register the type library, so that scripts on another machine can administer this one. # Local $app = New-Object -ComObject 'hMailServer.Application' # Remote, over DCOM, against a machine where admintools is registered $app = [Activator]::CreateInstance([Type]::GetTypeFromProgID('hMailServer.Application', 'mail01')) Authenticating $app = New-Object -ComObject 'hMailServer.Application' $account = $app.Authenticate('Administrator', 'your-admin-password') if (-not $account) { throw 'Authentication failed.' } Authenticate returns an Account object, or $null on failure. Sign in as Gets Administrator with [Security] AdministratorPassword from hMailServer.INI server administrator A mailbox address whose AdminLevel is 2 server administrator A mailbox address whose AdminLevel is 1 domain administrator: their own domain only A mailbox address that holds a role (since 6.3.4) what the role's permissions reach, in the domains it reaches An empty administrator password is an open door. If the administrator password is empty, and no administrator TOTP secret is enrolled, every COM session starts already authenticated as a server administrator. This is the historical behaviour. A second factor changes the call you must make. With Settings.EnrolAdministratorTOTP() used, Authenticate refuses the administrator outright and AuthenticateWithCode is the only way in: if ($app.AdministratorTOTPEnabled) { # readable BEFORE authenticating $app.AuthenticateWithCode('Administrator', $password, $code) | Out-Null } else { $app.Authenticate('Administrator', $password) | Out-Null } Three things about that sign-in change in 6.3.4: Change, since 6.3.4 What a script sees A one-time code is taken once a TOTP code the server has accepted is refused if it comes again, for the administrator and for an account alike; the refusal is not counted as a wrong code A wrong code is counted AuthenticateWithCode checks the password first, and a wrong code after a right password counts against a budget of five in fifteen minutes, then no code is taken for fifteen An app password is not a COM logon Authenticate and AuthenticateWithCode answer an app password as they answer a wrong password; it still opens the mailbox over IMAP, POP3 and SMTP How a refusal reaches you. If you are not entitled to an object, every member returns an error HRESULT: a terminating exception in PowerShell, a trappable error in VBScript, a COMException in C#. Up to 6.3.3, seventy-two COM classes answered a refusal as a bare Exception from HRESULT: 0x800403E9. Since 6.3.4 a refusal arrives with the server's own sentence. The object model From Application What is there Domains Domain, and under each Accounts, Aliases, DistributionLists, DomainAliases and, since 6.3.4, Rules Account (under Accounts) Address, Password, Active, MaxSize, Size, AdminLevel; Messages, IMAPFolders, Rules, FetchAccounts, AppPasswords; SieveScript, TOTPEnabled Settings the server-wide properties and the sub-objects AntiSpam (which owns Quarantine), AntiVirus, Backup, Cache, Directories, Groups, IncomingRelays, Logging, MessageIndexing, PublicFolders, Routes, Scripting, SecurityRanges, ServerMessages, SSLCertificates, TCPIPPorts; since 6.3.4, RemoteDomainPolicies Rules the global rules Status UndeliveredMessages, StartTime, ProcessedMessages, RemovedViruses, RemovedSpamMessages, SessionCount Utilities helpers such as CheckSieveSyntax, CriteriaMatch, MakeDependent, PerformMaintenance, ImportMessageFromFileToIMAPFolder Database ExecuteSQL, ExecuteSQLWithReturn, RequiresUpgrade, IsConnected, DatabaseType BackupManager StartBackup, LoadBackup GlobalObjects DeliveryQueue, MessageTrace, Languages Links Domain(DBID), Account(DBID), Alias(DBID), DistributionList(DBID) Diagnostics DiagnosticResults, each a DiagnosticResult Every collection offers the same shape: Count, Item(index), ItemByDBID(id), Add(), Refresh(), Delete(index) and DeleteByDBID(id), with ItemByName or ItemByAddress where a name exists. Items have Save() and Delete(). Add() does not persist. It returns a new, unsaved object. Set the properties, then call Save(). A script that forgets Save() looks as though it worked and changes nothing. In PowerShell, keep the object in a variable rather than chaining. Working examples $app = New-Object -ComObject 'hMailServer.Application' $app.Authenticate('Administrator', 'your-admin-password') | Out-Null # Add a domain $domain = $app.Domains.Add() $domain.Name = 'example.com' $domain.Active = $true $domain.Save() # Add an account $account = $domain.Accounts.Add() $account.Address = '[email protected]' $account.Password = 'a-strong-password' $account.Active = $true $account.MaxSize = 1000 # MB, 0 = unlimited $account.Save() # Report on every mailbox foreach ($d in $app.Domains) { foreach ($a in $d.Accounts) { '{0,-40} {1,8} MB used' -f $a.Address, [math]::Round($a.Size, 1) # Size is already in MB } } Three units, three objects. Account.Size is megabytes. Dividing it by 1MB again, which older examples do, prints 0 for every mailbox. Message.Size is kilobytes, and the Message size rule criterion is bytes. Find one account without walking every domain: $domain = $app.Domains.ItemByName('example.com') $account = $domain.Accounts.ItemByAddress('[email protected]') Send a message from a script. Message is a creatable coclass in its own right, and Save() on a new one queues it for delivery: $m = New-Object -ComObject 'hMailServer.Message' $m.FromAddress = '[email protected]' $m.From = 'Postmaster <[email protected]>' $m.AddRecipient('Alice', '[email protected]') $m.Subject = 'Scheduled maintenance tonight' $m.Body = 'The server will restart at 22:00.' $m.Save() The queue, and a backup: $app.Status.UndeliveredMessages # tab-separated text, one row per message $app.GlobalObjects.DeliveryQueue.ResetDeliveryTime() $app.GlobalObjects.DeliveryQueue.StartDelivery() $b = $app.Settings.Backup $b.BackupDomains = $true; $b.BackupSettings = $true; $b.BackupMessages = $true $b.Destination = 'D:\backups' $app.BackupManager.StartBackup() The [Settings] keys are reachable generically: $app.Settings.IniSettingNames # every key the server knows $app.Settings.GetIniSetting('ManageSieveServerPort') $app.Settings.SetIniSetting('ManageSieveServerPort', '4190') Up to 6.3.3 a change this way usually needed a restart. Since 6.3.4 the keys are kept in the database, and Settings.IniSettingApplies(name) says whether a save applies a key at once, at a reinitialise or at a restart; Settings.PendingIniSettings lists the saved ones the server does not run on yet. Settings: when a save takes effect, and the three levels has the counts and what becomes of the file's copy. What changed in 6.3.4: a shared object takes effect at Save() Some collections are not loaded for your COM session alone: the running server reads the very same items while it works. They are the routes and their addresses, the incoming relays, the DNS black lists, the SURBL servers, the remote domain policies, the server messages, the blocked attachments, the SSL certificates and the groups. Up to 6.3.3, setting a property on one of those items wrote the live object every SMTP, IMAP and delivery thread was reading, which let a session read a string while it was being freed. Since 6.3.4: The first property you set makes a copy, held by your COM object, and every later set writes the copy. Reading a property back from the same object reads what you set. Nothing is in effect until Save(). Save() writes the copy to the database and the server reads the collection again. A property set and never saved changes nothing at all. Up to 6.3.3 it changed the running server until the next restart while the database kept the old value. A script that relied on that must now call Save(). An object read before the save keeps what it read. After a Save(), read the item again from its collection (ItemByDBID, ItemByName) to see the saved values. A route's addresses. A change to an existing address waits for that address's Save(), like every item here. An address saved or deleted through Route.Addresses reaches the running route at once, without the route's own Save(), as it always did. A RouteAddresses list read before the route's save is the old route's list, though an address saved or deleted through it still reaches the running route. A save the database refuses leaves the running item as it was, and your object keeps the refused values, to be corrected and saved again. A remote domain policy is the exception: it is read back as the database holds it. A save whose re-read fails still answers success, because the save succeeded, and is reported as error HM7390: the change is in the database and not yet in effect, until a reinitialise, a restart, or another save. The Control Panel reads each item fresh, sets, saves and reads again, so it is not affected. The other collections were never shared this way and behave as before: TCP/IP ports, security ranges, the white list, the greylisting lists, blocked senders, sender list entries, and everything loaded for the COM object itself (domains, accounts, aliases, lists, rules, fetch accounts, app passwords, folder permissions). What 6.3.4 adds to the object model Six new interfaces make 100 coclasses, and the IDL has 1,884 HRESULT declarations against 6.3.3's 1,375. The wiki page lists every member; this is the shape of it. Interface Added in 6.3.4 Application Roles, CurrentRole, CurrentPermissions, RoleAssignments, AssignRole, ResetPassword, UnlockAccount Settings RemoteDomainPolicies; GetChangedFromDefault, GetSettingDefault; IniSettingApplies, IniSettingAppliesAll, PendingIniSettings; the profiles (GetProfiles, ApplyProfile, RevertProfile and the rest) Domain Rules; the quota policy; the domain transforms and disclaimer; SenderList; the DKIM rotation members; SpamTraps Account MoveTo; GetDevices, RevokeDevice; RoleName, RoleDomains, RolePermissions; the nine Directory properties; ExportArchive; Kind (0 a person, 1 a meeting room, 2 a piece of equipment) Utilities among others GetAuditTrail, VerifyAuditTrail, RevertAuditedChange, GetSetupChecklist, MoveMailbox, RunDkimRotation DistributionList Membership, and the list manager's members BackupManager, BackupSettings LoadEncryptedBackup, RestoreMailbox, RestoreMessage; EncryptionPassphrase (write-only), EncryptionPassphraseSet New RemoteDomainPolicies and RemoteDomainPolicy; SenderListEntries and SenderListEntry; GreyListingBypassEntries and GreyListingBypassEntry eServerState gains hStateDraining (5). The rule criteria gain eFTAttachmentName (9), eFTSensitiveContent (10), eFTAttachmentType (11), eFTExternalRecipient (12) and eFTContent (13), and the rule actions eRAAddDisclaimer (11), eRAReject (12), eRARequireTLS (13), eRAQuarantine (14) and eRAWarnSender (15). Roles over COM, and why API keys are not Since 6.3.4, authority is a role: serveradmin, domainadmin, helpdesk, auditor or a custom one, given to an account for named domains. Nothing changes on the day you upgrade: an account with no assignment holds exactly what its AdminLevel has always given it. An account with a role signs in with its own address and password, and COM asks the same question REST asks. Application.CurrentRole and CurrentPermissions say what the session holds. Administrator roles end to end has the permissions, the domains a role reaches and the Control Panel pages each role sees. Giving a role over COM is Application.AssignRole("[email protected]", "helpdesk", "example.test"), with an empty role name to take it away. Account.RoleName, RoleDomains and RolePermissions read it back. Custom roles are made over REST (POST /api/v1/roles), and COM has no way to delete a role at all. A help desk and an auditor over COM. A help desk's script has Application.ResetPassword, UnlockAccount and GlobalObjects.MessageTrace; COM's settings objects answer only the server administrator, so an auditor reads the configuration through the Deck or REST. Refusals that do not give anything away. Application.ResetPassword and UnlockAccount answer No such account. alike for an account that does not exist and for one the role does not reach. Settings.ClearLogonFailureList answers the server administrator alone. The question is asked where the write is made, not where the object was reached. Account.Save, Account.Delete, Account.MoveTo, Application.ResetPassword, the app passwords, and every write to what is in an account (FetchAccount.Save, Rule.Save, IMAPFolder.Save, Message.Save and the rest) each ask that the credential reach the account and take in its authority. An event script's objects carry no credential and are left as they were. API keys are not a COM object. The API key store has never been COM-visible. The key store (/api/v1/apikeys) answers to the administrator password and to nothing else, and a key is given a role with POST /api/v1/apikeys and "role":"helpdesk". The Control Panel's REST API keys page does not go through COM either: it edits hMailServerApiKeys.ini directly. What this server has changed from stock Since 6.3.4, Settings.GetChangedFromDefault answers every setting whose value is not the one this version ships with, with the shipped value beside it: the same document, byte for byte, as GET /api/v1/settings/changed. Only the administrator password may read it; an API key of any scope and an account holding an administrative role are both refused. The settings topic says what each entry carries. Distribution lists and the directory A list that defines itself. Since 6.3.4, DistributionList.Membership is a string property, read and written like the moderator and bounce addresses, holding a membership query whose accounts are added to the list's own recipients. A domain administrator over COM may set domain, a pattern: in a domain it holds, or nothing; the server administrator may set any form, and a query the server cannot answer is refused when it is saved. Aliases, distribution lists and membership queries has the five forms and how a query is answered. The directory. Since 6.3.4 an account has Account.DirectoryTitle, .DirectoryDepartment, .DirectoryPhone, .DirectoryMobile, .DirectoryOffice, .DirectoryOptOut, .DirectoryNote, .DirectoryPhoto (base64) and .DirectoryPhotoType (read-only). The row is read at the first get and written by Account.Save() with the rest. A change of the opt-out through Account.Save() is recorded on the audit trail as directory-opt-out-changed. The Import Tool The Import Tool is a Windows program (Start menu > hMailServer > Import Tool) that works through the COM API: it brings mbox files into an account, handing each message to the server through Utilities.ImportMessageFromFileToIMAPFolder, reads a Maildir with its flags, and creates accounts in bulk from a text file. Bringing mailboxes in covers each of its jobs. The breach check applies to a COM script. It is off by default. Where it has been switched on, it runs whenever a password is set through COM Account.Password, the Import Tool's included, and a bulk operation makes one request per account: run a large import against a mirror, or with the check off. What it does not do The COM API and the Control Panel do not exist on Linux, and there is no Import Tool on Linux. The Import Tool does not read PST files. The file goes into the server's import directory, and REST, hmctl or the Control Deck start the job. COM has no API keys and cannot delete a role. These features have no COM surface at all and are REST only: SCIM provisioning, SAML and OpenID Connect sign-in, passkeys, the S/MIME authority, the send API, migrations, IP warm-up, eDiscovery, mail in to a webhook and mailbox encryption at rest, among others the wiki lists. Where to read more The COM API and Scripting, sections 23.1 to 23.5, and APIs Reference, sections 8 and 9. Roles.md, ChangedFromStock.md, DistributionLists.md and Directory.md. Migration.md for the Import Tool, and Upgrading.md for what an upgrader's scripts now see. The public documentation's COM API chapter and its Import Tool section. On this forum: Upgrading to 6.3.4, the 6.3.4 announcement, event scripts, and the REST API for what COM does not reach.
  • 0 Votes
    1 Posts
    138 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) refuses a state-changing REST request that carries a credential - HTTP Basic included, which a browser keeps once it has answered the sign-in box - when the browser reports it as cross-site (Sec-Fetch-Site, or an Origin that is not this server's), and holds the password-reset request to the same rule, so another site cannot have a current browser drive it; the webmail and the Control Deck act on their own origin, and scripts, hmctl and the PowerShell module send no such header, so none of them is affected. SMTP, POP3 and ManageSieve now refuse a SASL PLAIN sign-in that asks to act as another account. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026) signs a name in to an account only when it is the account's stored address, compared in lower case after a domain alias and the default domain, on every protocol, the webmail, the REST API and COM, and for an OpenID Connect or SAML sign-in, so that the per-name lockout and the compromised-account hold can no longer be got round with another spelling of the name: a client that signs in with another spelling, in more than the case of the letters A to Z, or with white space at either end, may no longer sign in, since such a name fails as a name that does not exist fails. A failed account sign-in at the REST listener through a reverse proxy on the same machine, like a failed CalDAV, CardDAV or Autodiscover sign-in from loopback or an address in WebServicesTrustedProxies, is counted against the name alone (AccountLockoutThreshold, off by default), never towards a ban of the proxy's address. See the 6.3.8 announcement. This topic covers how people prove who they are to hMailServer 6.3.4: what 6.3.3 already had, and what 6.3.4 adds. The one thing to know first is that there are two front doors. The mail protocols - IMAP, POP3, SMTP submission, CalDAV and CardDAV - take a password: the account's own, an app password, or an OAuth2 bearer token where that is switched on. The two pages - the webmail at /portal and the Control Deck at / - take the password as well and, since 6.3.4, a passkey or a sign-in at the organisation's identity provider. Operators upgrading should read the note on passwords with characters above U+00FF first. What 6.3.3 already had Feature What it is A second factor for an account A TOTP secret on the mailbox. Once one exists, the account's password stops being a credential wherever a code cannot be presented alongside it - every mail client, and the webmail's sign-in - and app passwords are what those use App passwords One per device, shown once, revocable one at a time; they work for directory-linked accounts too and are untouched by password expiry A second factor for the administrator Enforced by the server on every surface - COM, REST, the Control Panel The password policy Length, mixed case, digits, symbols, a common-password list, history and maximum age LDAP and Active Directory Passwords checked against the directory; provisioning from it on a preview-then-apply OAuth2 bearer tokens on the protocols SASL XOAUTH2 and OAUTHBEARER validated against an identity provider's published keys There is no self-service enrolment of an authenticator app in the webmail: an administrator sets and clears the second factor, over COM and the Windows Control Panel. Create the app passwords first and enrol the secret second, or every configured client stops working with no way back in. The breach check (since 6.3.4). A password being chosen, never at logon, can be refused because it is in the published corpus of breached passwords; the check is off by default, because it sends five characters of the password's SHA-1 hash off the server, and its settings are in Hardening a public mail server. Four more changes in 6.3.4. The administrator password, which the Windows installer wrote as an unsalted MD5 digest, is written again as PBKDF2 at the first successful administrator sign-in (a file the service cannot write keeps the old value and says so once, HM7494). An account's TOTP secret is sealed at rest once the installation has a stored-secrets key. A mailbox encrypted at rest takes its own password only: no TOTP secret can be enrolled on it, and its app passwords are refused. And a room or a piece of equipment cannot be signed into by any credential. Upgrading to 6.3.4: passwords with characters above U+00FF Before 6.3.4 every password hash was made over a conversion that gave NUL bytes on Windows from the first character above U+00FF on, and ? for each such character on Linux, so a password of Cyrillic, Greek or CJK letters could be opened by any other password of its length. Hashes are now made over UTF-8, which leaves every ASCII password's hash as it was. The consequence, item 24 of the CHANGELOG's upgrade list: a password hash stored before 6.3.4 of a password with a character above U+00FF is refused, to its own password too, and the application log names the account. An administrator sets such a password again, and soon: until then SCRAM-SHA-256, whose client derives its key itself, still opens such a PBKDF2 hash to the NUL bytes (Windows) or question marks (Linux) it was made over, which the server cannot tell from the password; and on Linux such a hash also still opens to the password written with ? for those characters. Every ASCII and Latin-1 password signs in as before. The same release fixed SCRAM-SHA-256 having accepted the account's own password for an account with a second factor enrolled, and a password past PasswordPolicyMaximumAgeDays; each is now a forced failure of the exchange. SCRAM is always the account's own password, since an app password's hash is not one SCRAM can derive from, so such an account cannot sign in over SCRAM at all. Passkeys A passkey (schema 6077) is a WebAuthn credential held by the person's own device, such as a phone or a security key. The private half never leaves it; the server keeps the public half. Passkeys are offered on a stock installation, and nobody has one until they enrol it. Enrolling. The webmail's Security page has a Passkeys card, and the Control Deck has a Passkeys view for the administrator's own. Both ask for the owner's password again, with the one-time code in X-hMailServer-OTP where a second factor is enrolled, or for an account one of its recovery codes in X-hMailServer-Recovery-Code; a request that was itself authenticated with an app password is refused outright. At most ten per owner. POST /api/v1/passkeys/options what the browser needs to make one POST /api/v1/passkeys the credential it made GET /api/v1/passkeys the ones this credential holds DELETE /api/v1/passkeys/{id} remove one Listing and removing are answered while passkeys_enabled is off as well. Signing in. POST /api/v1/passkeys/challenge hands out thirty-two random bytes, kept in memory for five minutes and spent on first use; the assertion goes to POST /api/v1/session, the one place this server mints a browser session, so the sign-in gets the same ceilings and a device-list entry marked passkey. Nobody types an address first. A passkey stands in for the one-time code: user verification - a PIN, a fingerprint or a face - is required at registration and on every assertion. It carries nobody past an inactive account or domain, the compromised-account hold or the domain's country policy. Behind several names. By default the relying party id is the Host header the page was served on. passkey_relying_party set to a registrable parent (example.com) lets a passkey made at mail.example.com work at webmail.example.com. With it set, passkey_allowed_origins must be set too, comma separated as the browser writes them (https://mail.example.com, https://webmail.example.com); until it is, no passkey is registered or taken. Not verified: the attestation statement, so an installation cannot say "only hardware keys of this make". Not in the backup: enrol the device again after a restore elsewhere. Registering and removing a passkey is on the audit trail. Single sign-on Since 6.3.4 a person can sign in at the organisation's identity provider instead, by OpenID Connect or by SAML 2.0 (for a provider such as ADFS that speaks only SAML). Once it is set up, both sign-in pages draw a button: Sign in with and the issuer's host name, or Sign in with SAML. It opens the webmail and the Control Deck and nothing else: IMAP, POP3 and SMTP still take the password or an app password. An identity provider that says somebody is an administrator is not obeyed; the Deck opens as the administrator only for an address listed in oidc_administrators or saml_administrators. There is no logout in either direction, so a person disabled at the provider keeps a session already started here until its own ceiling ends it, which is what the session policies below are for. The settings, the Entra ID, Okta and ADFS entries and the flows are in SCIM provisioning and single sign-on. Account recovery Three independent parts (schema 6076): a recovery address and ten one-time codes, which the person sets on the webmail's Security page, and the forgotten-password flow on the sign-in card. Setting either asks for the account's own password again - never an app password - and the second factor where there is one. What it needs. account_recovery_enabled is on by default and inert on a stock installation: links are written against the server's public base URL - confidential_base_url, falling back to quarantine_digest_base_url and then the import sign-in's import_oauth_redirect_base_url - and with none set POST /api/v1/password-reset answers 503. recovery_reset_link_minutes (30; 5 to 1440) is how long a reset link lives, and recovery_verify_link_hours (24; 1 to 168) how long the confirmation link lives. The recovery address counts for nothing until the link mailed to it is followed, on a page with a button rather than on the GET, which a mail scanner would follow first. It is never answered in full again, to anybody: [email protected] reads as [email protected]. The confirmation is metered at one a minute and six an hour for the address, and again for the asking account, answering 429 with retry_after. The ten one-time codes are made together, shown once and stored hashed. A code goes in X-hMailServer-Recovery-Code wherever an authenticator's code is asked for: POST /api/v1/session, POST /api/v1/me/password, POST /api/v1/me/app-passwords, PUT /api/v1/me/recovery and POST /api/v1/me/recovery/codes. The password is verified before the code is looked at, and the code is spent only once the whole attempt has been accepted. Every owner has a budget that needs no setting: five wrong codes in fifteen minutes, and for the next fifteen every code for that owner is refused - the right one too - with 429 and code second_factor_locked. And a code is taken once (RFC 6238, section 5.2): an accepted TOTP code is refused if it comes again within its window, without being counted as wrong. A script that sent the administrator's password and a code with every request signs in once instead, or uses an API key. Forgotten your password? on the sign-in card posts the address to POST /api/v1/password-reset, which takes no credentials and answers always the same - 202 and one sentence, in the same time - whether or not the address is a mailbox with a confirmed recovery address. Since 6.3.7 a request a browser reports as cross-site (Sec-Fetch-Site, or an Origin that is not this server's) is refused, so another site cannot have a current browser drive it. The limits are one request a minute and six an hour per address, and twenty an hour per client address; a loopback peer, such as a reverse proxy on the same machine, is held to thirty in any sixty seconds instead. The link goes to the confirmed recovery address and nowhere else, is good once, and dies after recovery_reset_link_minutes. Completing it applies the password policy, the reuse history and the breach check, ends every browser session of the account, tells the mailbox and the recovery address, and raises the account.password-reset alert. A used, expired or unknown token answers 410. The administrator can see whether an address is set and confirmed, its masked spelling and how many codes are unused - over REST, on the Deck's Recovery card and the Windows Control Panel's Recovery tab - and can clear either: DELETE /api/v1/accounts/{address}/recovery and DELETE /api/v1/accounts/{address}/recovery/codes. The administrator cannot read the address in full, read a code, set an address on somebody's behalf or generate codes for them. A recovery address is exactly as strong as the mailbox that receives it: a convenience, not a second factor, and an installation that cannot accept that sets account_recovery_enabled to 0. Recovery does not enrol a new authenticator either. Nor does a reset link open encrypted mail: for a mailbox encrypted at rest the link is refused before it is spent and the person is sent to their administrator, and for a zero-access mailbox the password it sets does not open the key, so at the next sign-in the page asks for the previous password or the recovery key. Devices and sessions Every client that has authenticated to an account is one entry of a list: the protocol (imap, pop3, smtp, web, dav, autodiscover or managesieve), the address it came from, the user agent where the protocol carries one, the credential it used, the app password's name where one was used, and when it was first and last seen. IMAP's ID command is deliberately not used, so two mail programs on one machine over IMAP are one entry. At most fifty entries are kept per account. Surface Read Revoke Webmail Settings → Security, the Devices card Revoke beside the entry; the box under the table adds the app password REST, the account GET /api/v1/me/devices DELETE /api/v1/me/devices/{id}, with ?credential=revoke and ?forget=true REST, an administrator GET /api/v1/accounts/{address}/devices DELETE /api/v1/accounts/{address}/devices/{id} COM (Windows) Account.GetDevices() Account.RevokeDevice(id, revokeCredential) Control Deck The Devices view Revoke, with the app password box hmctl hmctl device [email protected] list hmctl device [email protected] revoke ID [--credential] [--forget] PowerShell Get-HmDevice -Address [email protected] Revoke-HmDevice -Address [email protected] -DeviceId ID [-Credential] [-Forget] What revoking does, exactly. A browser session's token is invalidated, so the next request on that cookie is 401; a live IMAP, POP3 or SMTP connection is dropped where it stands; and with credential=revoke the app password is deactivated - not deleted, so the person can put it back if the phone turns up. CalDAV, CardDAV and ManageSieve clients have no connection to drop, so revoking one means revoking its app password. A revoke is not a ban: a client with a credential that still works signs in again and clears the mark. The account's own revoke is refused (403) to a request that came in on an app password, and an administrator's revoke is recorded in the audit trail. The list, hm_signins, is not in the backup. The session policies govern every signed-in browser - the webmail, the portal and the Deck - server-wide and per domain, and are re-read at every request. A mail program's connection is not a session in this sense. Policy Setting Unset means Idle timeout session_idle_seconds 1800 seconds; at most 2592000 (thirty days) Absolute lifetime session_lifetime_seconds 43200 seconds, twelve hours; at most 2592000 One session per device session_one_per_device (a domain's: 0 the server's answer, 1 on, 2 off) Off Bound to the address it began on session_bind_to_address (0, 1 or 2 as above) Off - it ends a phone's session when it moves from wi-fi to mobile hmctl settings set --set session_idle_seconds=900 --set session_bind_to_address=true hmctl domain update example.com --set session_lifetime_seconds=28800 --set session_one_per_device=1 A domain's value wins over the server's where it is set. Nothing changes on the day you upgrade: every policy reads 0, which means the ceilings the server has always had. The cookie, hmailsession, is HttpOnly and SameSite=Strict, and Secure whenever the browser came over HTTPS; a proxy that terminates HTTPS in front of the loopback listener should set X-Forwarded-Proto: https. Browser sessions live in the server's memory, so a restart ends every one, and a password change ends every session and drops every connection of the account. What none of this does It does not reach the mail protocols. A phone's IMAP and SMTP still take the password or an app password, and an account that only ever signs in through its identity provider needs a password set before its person can mint an app password. No password-less accounts: a passkey sits beside the password, and no policy forbids the password. Where to read more Wiki: Sign-in and Identity, Connecting a Mail Client, Security Hardening. Documents: PasskeysAndSingleSignOn.md, AccountRecovery.md, DevicesAndSessions.md, PasswordBreachCheck.md, and item 24 of the 6.3.4 section of the CHANGELOG. The public documentation: 17.2 Modern authentication. On this forum: Connecting a mail client for app passwords on a phone, Active Directory and LDAP sign-in, encryption at rest, Upgrading to 6.3.4, The Control Deck, The webmail portal at /portal and the 6.3.4 announcement.
  • 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.
  • 0 Votes
    1 Posts
    134 Views
    chrisC
    A password could run code inside the server (CVE-2026-100741, assigned through GitLab's CNA; the CVE record was not yet published when this was posted). On Windows, with event scripting switched on, the script language set to JScript and an OnClientValidatePassword handler in EventHandlers.js, any client that could reach a sign-in - SMTP AUTH, POP3, IMAP or anything else that checks an account's password - and name an existing, active account could have JScript of its own run inside hMailServer.exe, with the rights of the service's account, before it had authenticated. Before 6.2.25 that script could create any COM object, and from 6.2.25 it could with ScriptAllowedObjects at its shipped *, WScript.Shell among them, and so run any command the service's account may run. 6.3.4 fixes it. The flaw is in every release from 6.0.0 to 6.3.3: the escaping was checked at every one of those tags (GitLab issue 27). Treat any server older than 6.3.4 with event scripting on and JScript as its language as affected. Who is affected Only a Windows server whose administrator switched event scripting on. Scripting is off as shipped, the shipped language is VBScript, and no EventHandlers.js is installed. Through a password, a server whose script language is JScript and whose EventHandlers.js has an OnClientValidatePassword handler. The same flaw was open to a remote POP3 server through the UID it answers, on a JScript server with an OnExternalAccountDownload handler, and to a remote mail server through the error text it refuses a delivery with and the failed recipient's address, on a JScript server with an OnDeliveryFailed handler. A rule's Run function action wrote its function name into the call unescaped, in either language, so VBScript servers too. On a server with scripting on, whoever may edit a rule, a domain's own administrator included, could run code in the server's process. VBScript servers were not open through a password, a UID or an error text. The Linux builds before 6.3.4 had no script engine. The server built each handler call as source text and escaped the apostrophe but not the backslash before it. Every JScript value is now escaped in one helper, and a rule's function name must be a plain identifier: ASCII letters, digits, _ and $, not starting with a digit. On Windows any other name is refused as HM5018 each time the rule fires; on Linux, whose JavaScript engine looks a handler up by name instead of building a call, such a name finds no function and nothing is run (EventScripts.md). Until you can upgrade, switch event scripting off. A server that cannot do without its scripts should take the OnClientValidatePassword, OnExternalAccountDownload and OnDeliveryFailed handlers out of a JScript EventHandlers.js and reload the scripts, and, in either language, let nobody but the server administrator make or edit a rule with a Run function action. Before you upgrade Install 6.3.4 by hand, on every server. The Windows installer is Authenticode-signed by Progressive Robot Ltd through Azure Artifact Signing, but the release carries no Sigstore bundle, so a server's live update, of any version, that is offered 6.3.4 says it cannot be verified and downloads nothing. On Windows run hMailServer-6.3.4-x64.exe over the existing installation; on Linux install the .deb with apt on Ubuntu 26.04 or 24.04, or the .rpm with dnf on Fedora 43 or 44 or Enterprise Linux 10. The .deb needs glibc 2.38 or later, so it does not install on Debian 12, and the .rpm does not install on Enterprise Linux 9. A silent upgrade of a server with an administrator password needs it, as before: /adminpassword=<password>, or, new in 6.3.4, the environment variable HM_ADMIN_PASSWORD, set in an elevated prompt, because it does not cross the UAC prompt. A password with a double quote goes in the variable: Inno Setup drops every double quote from its command line. The installer now hands the password to the database tools in that variable too. It used to put it on their command lines unquoted, so a password with a space, a double quote or backslashes before one failed the database step with exit code 3. Back up the database and the data directory first. The schema goes from 6040 to 6104 in 64 one-way steps. On MySQL and MariaDB, step 6102 converts every table to utf8mb4 and rebuilds each one, which takes time on a large database. It needs MySQL 5.7.9 or MariaDB 10.2.2 or later - on an older server the upgrade stops at step 6041 with error 1071 and changes nothing - and the ALTER privilege on the database. Two rows the new collation no longer tells apart stop it with error 1062 until one of them is removed; a step stopped part of the way is finished by running it again. Step 6101 adds two columns to hm_messages, which has a row for every stored message, and on a large store is not instant on every backend. The database becomes the settings store. At the first start the [Settings] section of hMailServer.ini is taken into the database. A line edited after the old server last started, including one edited to prepare the upgrade, is put back, so make such a change after upgrading. From then on a line edited in the file is ignored and put back (HM5804 change settings in the Control Panel, over COM or REST, or on Linux with hmailserver --set-setting NAME=VALUE. A server from 6.2.28 to 6.3.3 still looks for updates at GitHub, which has answered 404 since 18 September 2026. For as long as it stays on that version, add this under [Settings] in its hMailServer.ini and restart the service, and its update check works again: UpdateFeedUrl=https://updates.progressiverobot.com/releases.json Keep UpdateAutoDownload off on such a server until it has been upgraded by hand. Once 6.3.4 is installed the server reads https://updates.progressiverobot.com without being told (the stable channel at /releases/latest), and the line can then be cleared in the Control Panel or over REST, not in the file. Linux packages for 6.3.4 are x86-64 only: a .deb and an .rpm. The AArch64 packages and the AppImages were last published with 6.3.3. Windows on ARM compiles but has never run, and there is no ARM64 installer. What changes on upgrade without a switch The 6.3.4 section of CHANGELOG.md lists 24 such changes. These are the ones most servers meet. SPF follows RFC 7208: mail from 127.0.0.0/8 and ::1 no longer passes unconditionally. The audit trail and the alerts are on, though nothing is mailed until AlertRecipient and AlertSenderAddress are set. Compromised-account detection runs in watch mode and holds nothing. A destination that answers 421 or a rate-limit code is paused, for 2 minutes at first and up to an hour (OutboundBackoffMinutes, OutboundBackoffMaxMinutes). MySQL and MariaDB connections use TLS whenever the database server offers it, without checking the certificate, and connect without it when it offers none. SQL Server sessions through MSOLEDBSQL 18 or SQL Native Client are encrypted whole, and tried once more without encryption when the failure reads as TLS unless TlsMode is require or verify-full; through SQLOLEDB, which the server uses where MSOLEDBSQL 18 or later is not installed and no failover partner is set, only the login is encrypted unless [Database] TlsMode is require or verify-full. verify-full checks the certificate. PostgreSQL is unchanged. The application log says at every start what the connection got (DatabaseTls.md). The administrator password is hashed again as PBKDF2 at the first administrator sign-in, and a browser session made under the old hash ends once. Where the service cannot write hMailServer.ini (the Linux packages, or a Windows service moved to NT SERVICE\hMailServer), the old value stays, HM7494 is logged once, and you set the password again with --set-admin-password. The Windows installer now writes it as PBKDF2 itself. A password hash stored before 6.3.4 of a password with a character above U+00FF is refused, and the application log names the account: that hash was made of NUL bytes on Windows or question marks on Linux, and any other password of that form opened it. Set such a password again, and soon: until then a SCRAM-SHA-256 client that derives its key from those NUL bytes or question marks still opens the PBKDF2 hash, and on Linux the password with ? in place of each such character still opens the account. ASCII and Latin-1 passwords sign in as before. A one-time code is taken once. A script that sent the administrator's password and a code with every REST request should sign in once (POST /api/v1/session) or use an API key; otherwise only its first request in each half minute is accepted. 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, now sends nothing: the delivery fails with a temporary 450 4.7.0 and waits for its retries, and HM5912 says to set the security to TLS or STARTTLS required. A domain can no longer be named as a directory the server keeps its own files in, such as protected, quarantine or files. One that already is can still be saved, and is named as HM7597 at every start and on the setup checklist: rename it before you rely on a backup of it. A COM change to a route, relay, DNS black list, SURBL server, remote-domain policy, server message, blocked attachment, SSL certificate or group takes effect only at Save(). Scripts that relied on the old way must save. IMAP answers as the RFCs say where Dovecot's imaptest found it did not: some answers change from BAD to NO, and an APPEND stores the literal byte for byte. A restore refuses an archive with an absolute path, a .. or a link in it, and the installer's 7-Zip is 26.03. Mail labelled ISO-8859-1 is decoded as windows-1252. Only a new installation is made secure before anyone configures it: a self-signed certificate, STARTTLS on 25, 587, 110 and 143, and TLS required for sign-in from the Internet IP range. The Windows installer does it; on Linux the service's first start under systemd within a day of --create-database does it, and with an AppImage or a container image, neither of which 6.3.4 ships, an administrator runs --apply-new-install-defaults by hand. A new Windows installation also runs the service as NT SERVICE\hMailServer, and a new installation gets a stored-secrets key, made by the Windows installer, and on Linux by the container's --create-database only; a new .deb or .rpm installation gets its key when an administrator runs sudo hmailserver --create-stored-secrets-key, which the setup checklist offers. An upgrade keeps its listeners, its service account and its secrets as they were: nothing is sealed until an administrator runs --create-stored-secrets-key, which the setup checklist offers. Fixed before release 6.3.4 was audited area by area before it was cut, and its code was scanned by GitLab's SAST. The defects they found are fixed in this release. Several of these were in 6.3.3 as well. Passwords outside Latin-1. Every password hash was made over a conversion that turned the first character above U+00FF and everything after it into NUL bytes on Windows, and each such character into ? on Linux, so a password of Cyrillic, Greek or CJK letters could be opened by any other password of its length and shape. Hashes are now made over UTF-8 (see the upgrade note above). Sign-in. SCRAM-SHA-256 accepted the account's own password for an account with a second factor, and a password past its maximum age (6.3.3 had both). A sign-in under a domain alias, or with a token, a certificate or a Kerberos ticket, escaped the country policy. One-time codes could be used again within their window, and at several places a wrong one was not counted. Single sign-on and passkeys. A single sign-on ticket could be redeemed in another person's browser. With a parent-domain relying party, a page on any sibling host could sign somebody in with their passkey (passkey_allowed_origins now names the origins). A switched-off domain still let its people in by passkey or single sign-on. Delegated administration. Where the server administrator's own mailbox is in a domain somebody else administers, that domain's administrator could become the server administrator through an app password on it, delete or rename it, or repoint its fetch account, over REST and COM. A credential confined to one domain could set another domain's webmail branding and declare spam traps in any domain. Keys. An app password or an administrator's support session could read the account's wrapped S/MIME, OpenPGP and zero-access keys. An app password could also replace the account's own S/MIME key and publish an OpenPGP key for the address, and a support session could change any of the account's keys or switch zero access off. Collecting mail. On a server that collects Microsoft 365 mail with its own OAuth2 token, any person could collect any mailbox the token reaches (a domain administrator over COM since 6.2.23 Alpha 1). A CR or LF in a fetch account's user name or password added commands, and a fetch account's host could be pointed inside the network through DNS after it was saved. Schema 6104 marks the fetch accounts made or changed from now on: one a person makes connects only to public addresses, unless the administrator allows private ones, and one made without the server's authority is never given the server's token. Accounts from before 6104, and an administrator's, are not marked, so review existing fetch accounts for hosts on FetchOAuth2Hosts after upgrading. IMAP. A heap-corruption abort when two sessions met on one message's keywords, flag changes lost when two arrived at once, an abandoned APPEND that left its file for good, an unbounded LIST pattern, and ENVELOPE and BODYSTRUCTURE values that broke the response. 6.3.3 had all of them. The REST listener and the webmail. Request headers were read from the body, which allowed a forged sign-in. One person could stall the webmail and the Control Deck for everybody. A Web Push endpoint could point inside the network. Large downloads were cut off and held whole in memory, and a request head that never ended could hold 16 MB. GitLab's SAST (Semgrep). Seven of its High findings were real, and are fixed: the crash-dump helper would load a dbghelp.dll put in Bin; the Control Panel's elevated service restart would run a cmd.exe left in its working directory; the installer handed the administrator password to DBSetupQuick.exe, and it to DBUpdater.exe, unquoted on their command lines; a malformed backup index was read past its end (two); and a test of the MIME parser compared pointers into two different arrays. 169 others were read and judged not exploitable, each with its reason in .gitlab/security-exceptions.yml (188 entries there, 19 of them re-reads of lines the fixes moved). Found beside them and fixed too: the MySQL client's DLLs were looked for in the current directory and along PATH, and a custom virus scanner whose command line holds a bare %FILE% was handed the path cut at its first space, scanned no file, and the message was delivered as clean. The first security scans. The installer's 7-Zip is 26.03 in place of 19.00, which predates the fixes for CVE-2023-31102 and CVE-2025-55188; a restore refuses an unsafe archive; MIME boundaries come from a generator seeded by the operating system; zlib is 1.3.2. The two static-analysis findings that were defects are fixed: on Linux the service account's name is read with getpwuid_r, and an inbound webhook's URL must be printable ASCII on both platforms. Also in this release Most of what is new is off until an administrator turns it on. Mail flow: remote-domain policies, per-destination throttling and IP warm-up, a send API for applications, DKIM key rotation, journaling, restricted delivery, message recall, and mail in to a webhook. Anti-spam: hardened greylisting, SMTP policy rules, allow and block lists with quarantine digests, mail flow rules with an outbound content policy, impersonation protection, attachment sandboxing, spam traps and country blocking. Webmail and clients: CalDAV and calendars with invitations, free-busy and delegation, rooms and equipment that answer bookings, contact groups and a directory, recover deleted items, expiring messages, offline mail, Web Push and OpenPGP in the browser. Identity: administrator roles, passkeys, OpenID Connect and SAML sign-in, SCIM provisioning, self-service password reset, sessions and devices, and breached-password checks. Encryption: zero-access mailboxes, mailbox encryption at rest, gateway encryption to partner domains, an organisation CA for S/MIME, Web Key Directory, and sealed stored secrets. Compliance and administration: eDiscovery with legal holds and verifiable exports, settings at server, domain and account level, profiles, hmctl and a PowerShell module, and a setup checklist. Migration: resumable migrations from IMAP, Google Workspace and Microsoft 365, and PST import with a reader of the project's own. No PST job runs until an administrator names PstImportDirectory, copies the file there and starts the job. Operations: storage compression and attachment de-duplication; object storage on an S3-compatible store or Azure Blob Storage, off until an administrator names a store (MessageStoreBackend is file as shipped); encrypted backups; event scripts on Linux in JavaScript (QuickJS); a read-only SNMPv3 agent, off, and answering nobody until a manager's address is in SnmpAllowedAddresses; and syslog. The full list, with the operator document for each item, is the 6.3.4 section of CHANGELOG.md. What 6.3.4 does not carry No Sigstore bundle, so no server's live update installs it. From 6.3.5 the GitLab pipeline is to sign every file with Sigstore; none of its release jobs has run yet. No AArch64 .deb or .rpm, no AppImage, and no ARM64 Windows installer. No container image. The Dockerfile, the Compose file and the Helm chart are in the tree, nothing is published at registry.gitlab.com/progressiverobot/hmailserver yet, and the images published on ghcr.io before the suspension answer 404. No apt or dnf repository, and no winget or Chocolatey package of this project's in the public repositories (the hmailserver package on the Chocolatey feed is the upstream 5.6.8, unlisted). Downloads, and how to check them The release carries ten files: hMailServer-6.3.4-x64.exe, the Windows x64 installer; hmailserver_6.3.4_amd64.deb and hmailserver-6.3.4-1.x86_64.rpm for x86-64 Linux. An SBOM for each of those three, <file>.cdx.json (CycloneDX 1.6), whose subject is that file by its SHA-256 and SHA-512; and the source tree's SBOMs, hmailserver.spdx.json and hmailserver.cyclonedx.json. hmailserver-6.3.4-SHA256SUMS.txt, which names the other eight with their SHA-256, and hmailserver-6.3.4-SHA256SUMS.txt.sig, its signature, made with the SSH key that signs the release tags. https://updates.progressiverobot.com/download/hMailServer-x64.exe, /download/hmailserver_amd64.deb and /download/hmailserver.x86_64.rpm always lead to that file of the newest stable release, never a pre-release's, and https://updates.progressiverobot.com/download/ to that release's page. To check a download, with OpenSSH 8.1 or later, in a clone of the repository (for .gitlab/allowed_signers) and with the downloads beside you: ssh-keygen -Y verify -f .gitlab/allowed_signers -I [email protected] -n file -s hmailserver-6.3.4-SHA256SUMS.txt.sig < hmailserver-6.3.4-SHA256SUMS.txt sha256sum -c hmailserver-6.3.4-SHA256SUMS.txt The first must say Good "file" signature for [email protected], and the second OK for every file (add --ignore-missing when you downloaded only some). On Windows, Get-AuthenticodeSignature .\hMailServer-6.3.4-x64.exe should also answer Valid, with a signer certificate for CN=Progressive Robot Ltd. The tag is signed with the same key: git -c gpg.ssh.allowedSignersFile=.gitlab/allowed_signers verify-tag v6.3.4. SECURITY.md, "Verifying a release" and "Software bills of materials", has the rest, including how to check that an SBOM describes your file. Reporting a vulnerability Not in a thread here, and not in a public issue. Report it privately, as SECURITY.md says: a confidential issue on GitLab - check that it is still marked confidential before you submit it, and choose the Security template - or an email to contact-project+hmailserver-hmailserver-86730559-issue-@incoming.gitlab.com, which GitLab files as a confidential issue, so no GitLab account is needed. Release notes, checksums and downloads · Newest stable release
  • 0 Votes
    1 Posts
    146 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.8 (2 November 2026) is the newest release, a security release: upgrade every server running 6.3.7 or earlier. It requires schema 6108 and adds no step of its own (from 6.3.5 or older the upgrade runs 6.3.6's three one-way steps, from 6.3.3 or older 6.3.4's steps first, so this topic still applies on the way); a server on 6.3.4, 6.3.5, 6.3.6 or 6.3.7 installs it by the live update, with the exceptions the announcement lists, one from 6.2.28 to 6.3.3 by hand, once, and an older one by the installer, as always. 6.3.8's Windows installer refuses an installation of the original hMailServer's 5.7 (5.7.0, its pre-release builds 2788 and 2843, 5.7.1 and 5.7.2), which this fork's upgrade chain has no step from, before it changes anything, and the installers of 6.3.7 and earlier must never be run over one: move such a server's mail over IMAP instead (Migration.md, "From the original hMailServer"). Read "Before you upgrade" in the announcement first: some changes alter what an upgraded server does without anything being switched on, above all for TlsMode=verify-full without TlsCaFile to a MySQL or MariaDB server on the same machine, for file names outside ASCII, and for sign-in names spelt otherwise than the stored address. See the 6.3.8 announcement. hMailServer upgrades in place. The installer stops the service, replaces the program files in Bin, upgrades the schema if needed, and restarts. Your data directory is untouched. The [Settings] section of hMailServer.INI is taken into the database at 6.3.4's first start (below). Every server installs 6.3.4 by hand. It is Authenticode-signed and carries no Sigstore bundle, so no server's live update installs it: run hMailServer-6.3.4-x64.exe on Windows, or install the .deb or .rpm on Linux (release page). Any 5.3 through 6.3.3 goes straight to 6.3.4. There are no intermediate steps. The upgrade chain is continuous on MySQL/MariaDB, MS SQL, PostgreSQL and SQL Server Compact, and DBUpdater walks whichever steps your database still needs. 6.3.4 needs schema 6104. A 6.3.3 database sits at 6040 and is walked through 64 steps. A 6.2.27 or 6.2.28 database sits at 6031 and is walked through 6.3.2's seven steps, 6.3.3's two and 6.3.4's 64. Older ones are walked the whole way. Path table: §18.2. Most of what 6.3.0 to 6.3.4 added is off by default. The REST API, the Control Deck and the portal all need RestApiPort set. What 6.3.4 changes on upgrade without a switch is listed first in its release notes. The ones you will notice: the database becomes the settings store, so after the first start a line edited in hMailServer.INI is put back (HM5804) and a setting is changed in the Control Panel, over COM or REST, or with hmailserver --set-setting on Linux; SPF follows RFC 7208, so mail from 127.0.0.1 or ::1 no longer passes it unconditionally; the audit trail and the alerts are on, though nothing is mailed until AlertRecipient and AlertSenderAddress are set; a COM script that changes a route, a relay, a DNS black list, an SSL certificate or a group must now call Save() before the change takes effect; some IMAP answers change from BAD to NO; and a MySQL or MariaDB connection uses TLS whenever the database server offers it, without checking the certificate, and a SQL Server session through MSOLEDBSQL 18 or SQL Native Client is encrypted whole, where through SQLOLEDB only the login is unless [Database] TlsMode is require or verify-full, which checks the certificate (DatabaseTls.md). An upgrade keeps its listeners, its service account and its secrets as they were; only a new installation gets STARTTLS with a self-signed certificate, the Windows service as NT SERVICE\hMailServer and a stored-secrets key. Edit hMailServer.INI after the upgrade, not to prepare it. At 6.3.4's first start a [Settings] line changed since the old server last started is taken for an edit and put back (HM5804). Set again every password with a character above U+00FF. 6.3.4 refuses a hash stored before 6.3.4 of such a password (Cyrillic, Greek or CJK letters, say) at every password sign-in, and the application log names the account. Set those passwords again soon after the upgrade: in the Control Panel, over COM or REST, and the administrator's own with hMailServer.exe --set-admin-password (hmailserver --set-admin-password on Linux). ASCII passwords are unchanged. Before you start Back up the database, the data directory and hMailServer.INI (chapter 15). Record your current version. Pick a quiet window; the service is down for a minute or two and senders retry. On a large store allow longer for the steps below. That backup is the rollback. The upgrade is one way: an older server refuses a newer database rather than misreading it. Rolling back means restoring the pre-upgrade database backup and then reinstalling your previous version, with the pre-upgrade hMailServer.ini put back beside the database if 6.3.4 had sealed the stored secrets (the older version's installer would otherwise hand Windows the sealed service-account password, and the service would not start) (§18.6). The steps that can take time, and the two that can stop Four schema steps want a maintenance window on a large database. 6024 to 6025 rewrites hm_messages.messageflags from tinyint to smallint: a locking table rewrite on your largest table, on every backend except PostgreSQL. 6029 to 6030 adds seventeen FOREIGN KEY constraints with ON DELETE CASCADE and reads every child table once. 6100 to 6101 adds two columns to hm_messages, which is not instant on every backend. 6101 to 6102, on MySQL and MariaDB, rebuilds every table as utf8mb4. 6029 to 6030 is one place an upgrade can stop. It sweeps orphaned rows before adding those constraints, and that sweep ran children before parents, so pruning an orphaned account, fetch account or distribution list could re-orphan rows nothing revisits, and the constraint that followed was refused. The reordering fix shipped in 6.3.2 and is in 6.3.3 and 6.3.4. It fires only from a schema below 6030, only against a database that already holds orphaned rows, on all four backends. No installation has reported hitting it. When that step fails it fails loudly, in the database engine's own words, and rolls back rather than doing anything quietly. The database is where it was, the error names the constraint it could not add, and those orphaned rows have to go before the upgrade will pass. 6101 to 6102 is the other. It needs MySQL 5.7.9 or MariaDB 10.2.2 or later, as 6040 to 6041 and 6100 to 6101 do, so on an older server the upgrade stops at 6041 with error 1071 and changes nothing; and it needs the ALTER privilege on the database. Two rows the old collation told apart and utf8mb4 does not, such as straße and strase in one address book on MariaDB 11.8, stop it with error 1062 until one of them is removed; a step stopped part of the way is finished by running it again. SQL Server, SQL Server Compact and PostgreSQL only move the version number at that step (Upgrading.md). On 6.3.1 or 6.3.2 6.3.2 could not upgrade a database older than its own schema; those attempts stopped with The server has not loaded its configuration and changed nothing. The Control Panel's live update to 6.3.2 failed with installer exit code 5, because the Control Panel that started it held its files open. Both are fixed in 6.3.3. No live update installs 6.3.4 on any version, so close the Control Panel and run the installer by hand. On Linux the package replaces the binary and its post-install step runs hmailserver --upgrade-database. 6.3.4's packages are x86-64 only; the AArch64 packages were last published with 6.3.3 before 6.3.6, and 6.3.8 carries hmailserver_6.3.8_arm64.deb and hmailserver-6.3.8-1.aarch64.rpm, which a server from 6.3.3's AArch64 packages installs by hand, once. Servers you are not upgrading yet A server from 6.2.28 to 6.3.3 still looks for updates at GitHub, which answers 404. Under [Settings] in its hMailServer.INI, add UpdateFeedUrl=https://updates.progressiverobot.com/releases.json, then restart the service, and its update check works again. Keep UpdateAutoDownload off on such a server until it runs 6.3.4 (UpdateFeed.md). Downloads and release notes · Chapter 18, upgrading
  • 0 Votes
    1 Posts
    58 Views
    ProgressiverobotP
    Nothing in the server changes. The compiled server differs from 6.3.0 by its version stamp and one comment line. What changes is the installer: the Windows installer is now Authenticode-signed with Azure Artifact Signing, against a certificate profile issued to Progressive Robot Ltd. If you run with UpdateRequireAuthenticode=1, which has existed since 6.2.28, the server's own update path has been refusing every release of this project, because none carried a signature. From 6.3.1 the installer it downloads carries one. What the upgrade involved The orphan sweep in the 6029 to 6030 upgrade step runs children before parents. Before it adds seventeen foreign keys it deletes rows whose parent is gone, and three of those parent tables are pruned by the same deletes, so pruning an orphaned account, fetch account or distribution list re-orphans rows nothing revisits and the constraint that follows is refused. It affects only an upgrade from a schema below 6030 on a database that already holds orphaned rows, in all four database backends. No installation has reported hitting it, and when it fires it fails loudly with the engine's own words and rolls back. The fix is held for 6.3.2. The rest Only the Windows installer is signed. There is no Authenticode for a .deb, an .rpm or an AppImage. The elevation prompt now reads the publisher's name. SmartScreen still warns. Microsoft flags a signed installer as unrecognised until reputation accumulates. An EV certificate would not help; Microsoft removed EV's SmartScreen bypass in 2024. The UpdateRequireAuthenticode check is WinVerifyTrust on the downloaded installer, and it is Windows-only. On Linux the server says so rather than reporting a pass, and updating is the package manager's job. The signing gate asked for four of the six settings it guards and never asked about ARTIFACT_SIGNING_ENDPOINT or ARTIFACT_SIGNING_PROFILE. Three outcomes now: none of the six set is a silent no-op, all six signs, anything in between stops and names what is missing. 6.3.0's tagged run attached no Linux packages because the package-install check ran without sudo against /etc/hmailserver, which the package makes 0750 root:hmailserver. It runs under sudo now. Documentation: the README offers the Linux packages on its download line, and two files that named 6.2.29, a version that does not exist, now say 6.3.0. Full suite on the stamped binary: 2,175 tests, 2,166 passed, 0 failed, 9 skipped. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    54 Views
    ProgressiverobotP
    hMailServer 6.3.0 runs on Linux. Every core translation unit compiles there, counted file by file by build/linux-tu-census.sh under clang on x86-64 and AArch64, with a separate job linking the core with GCC. The Windows build is the same MSVC project it was and behaves as it did. What the upgrade involved No schema change. The schema is 6031, as in 6.2.28, so the installer's database upgrade has nothing to do. On Windows, run the installer over the existing installation. Nothing this release adds is on by default: the REST API needs RestApiPort, and a server upgraded without touching its settings behaves exactly as 6.2.28 did. Per-domain DKIM cannot be configured on Linux. There is a read route and no write route, and a PUT answers 404. A domain that must sign its outbound mail with DKIM is not one to run on Linux today. Packaging. A .deb and an .rpm for both architectures, a PKGBUILD for Arch, and an AppImage: a systemd unit running the server as its own user, the configuration under /etc/hmailserver, and --create-database, --upgrade-database and --set-admin-password. Proven against PostgreSQL 18 and MariaDB 11.8, and against a real slapd over StartTLS and LDAPS. REST API. PUT /api/v1/settings and its anti-spam and logging groups write 108 settings, each through the same setter the Control Panel calls, applied only when every key in the request is accepted. Global rules, SMTP routes, aliases, accounts, certificates and listeners too, plus POST /api/v1/server/reinitialize, so a new listener takes effect without stopping the process. Control Deck and /portal. The administration page no longer stores the administrator password: POST /api/v1/session exchanges it once for an HttpOnly, SameSite=Strict cookie that ends when that password changes. /portal is a webmail now, polling GET /api/v1/me/changes every six seconds. Fixes. On Linux, IMAP's modified UTF-7 was broken in both directions, so non-ASCII folder names were not stored correctly, and CStdString stopped converting at the first byte above 127, cutting short IMAP SEARCH CHARSET UTF-8 and MAIL FROM under SMTPUTF8. A TLS key-exchange group list OpenSSL rejects is now reported once, not once per listener and per delivery: on the OpenSSL Debian and Ubuntu ship, hundreds of errors an hour. The Control Panel sign-in box no longer translates the administrator user name, which made a fresh installation in Chinese, German or Swedish refuse the credential it had just asked for. (GitHub issue 156, #177) Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    51 Views
    ProgressiverobotP
    6.2.28 is the first release that can update itself. A scheduled task reads this project's release feed and the Status page reports what it found; fetching an installer and applying it are two further, equally opt-in steps. The upgrade to 6.2.28 itself is manual. What the upgrade involved No schema change: 6031, as 6.2.27. The installer's database upgrade has nothing to do on a 6.2.27 database. Everything this release adds is off by default. UpdateCheckEnabled, RestApiPort (which the portal and the Control Deck need), IMAPCompressionEnabled and HttpProxy are all opt-in. A server upgraded without touching its settings behaves exactly as 6.2.27 did. Known and unfixed: the Control Deck reads but does not write, and holds the administrator password in sessionStorage while it is open. The regression suite runs on Windows only. What is in it Updates. UpdateCheckEnabled=0 is the default and nothing happens until it is set: no request, no identifier, no counts. Turned on, the feed is read every UpdateCheckHours (24 by default). An installer is verified against its Sigstore bundle before it runs: the certificate chains to Fulcio, the identity and issuer are this project's release workflow, and the entry is in the public transparency log. These releases are not Authenticode-signed, so UpdateRequireAuthenticode=1 refuses every one of them, and the Sigstore check cannot be turned off. hMailServer.Updater.exe stops the service, waits UpdateServiceWaitSeconds (180) for it to come back, and reinstalls the previous version if it does not. Webmail. /portal on the REST listener, with /api/v1/me behind it. It answers to the account's own credentials only: no administrator password, no API key. Read, send, search, attachments, the account's own quarantine, Sieve script and password change. A real HTTP server. The REST API and web services move off a single-threaded HTTP/1.0 loop onto HttpServer: HTTP/1.1 on Boost.Asio with keep-alive, chunked bodies, and header and body deadlines. IMAP COMPRESS=DEFLATE (RFC 4978). Advertised until compression is on and refused afterwards, as the RFC requires. STARTTLS is refused once a session is compressed. HttpProxy=host:port sends every web request the server makes as a client through a forward proxy. CONNECT for https, with the same certificate verification as a direct connection. No proxy credentials. Fixed (GitHub issue 156). A masked password in the Control Panel was typed backwards from the second character: 12345678 became 18765432. It hit IME commits and some keyboard layouts. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    50 Views
    ProgressiverobotP
    If you run hMailServer on SQL Server Compact, the 6.2.25 installer told you the database could not be upgraded. It had been upgraded. Every Compact Edition upgrade through schema 6030 was reported as failed after it had succeeded (GitHub issue 114), and two seconds later the service ended and service recovery started it again. What the upgrade involved If the 6.2.25 installer failed on your database, that database is at schema 6030 with its foreign keys in place, and this installer finds nothing left to upgrade. If you restored a backup from before the attempt, the whole chain runs and the verification passes. From 6.2.24 or earlier, the 6.2.25 notes and the 6.2.24 notes before them describe what changes on the way, and everything there still applies. What was wrong After each upgrade script the database updater proves the schema changed by running a probe statement, and reads a failed probe as a missing object. The four probes for schema 6030, the foreign keys, used case when exists (subquery) in the SET expression. That is valid on SQL Server, MySQL and PostgreSQL. On SQL Server Compact it is an access violation inside the OLE DB provider, on a correct database with every constraint present. The server reported HM10045 Unknown error, the updater declared that Upgrade6029to6030MSSQLCE.sql had not created fk_hm_accounts_domain and blamed an [IGNORE-ERRORS] marker the statement does not carry. The fix The probes now read update hm_dbversion set value = value / (value - value) where not exists (select 1 from information_schema.table_constraints where constraint_name = '...' and constraint_type = 'FOREIGN KEY'). With the constraint present no row matches and nothing is evaluated. With it absent the one row matches and the division by zero fails the statement on every backend, leaving hm_dbversion untouched. The updater's message no longer asserts a cause it cannot see. It gives the backend's own words and says how to read them. This was reproduced from a Compact Edition database created at schema 6011 and upgraded with the shipped scripts: it reaches 6030 with all seventeen foreign keys, and the probe then faults the provider. build/check-db-scripts.ps1 now runs every probe through the provider the server uses, with a negative control that must fail, and a regression fixture runs them through the same COM path the updater takes. Both fail on the 6.2.25 statement. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    52 Views
    ProgressiverobotP
    ACME issuance and renewal ended the hMailServer process (GitHub issue 93). Anyone running automatic certificates on 6.2.24 lost the service on every issuance and every renewal. Two calls in the ACME client handed the OpenSSL DLL a FILE* opened by the server's own C runtime: the DANE TLSA line logged straight after issuance, and the re-read of the existing private key at the start of every renewal (the default, AcmeReuseKey). With no OPENSSL_Applink export in the executable, OpenSSL does not return an error. It writes OPENSSL_Uplink(...): no OPENSSL_Applink to the Windows Application log under the source "OpenSSL" and calls TerminateProcess. The symptoms: an OpenSSL event whose message looks blank, a 7031 from the service control manager in the same second, no crash dump, and no "ACME (automatic)" certificate record. Both calls now go through OpenSSL's own file I/O, and the deployment runs before the TLSA line. If 6.2.24 issued you a certificate before it died, the files under Data\ACME are valid. 6.2.25 deploys them at its first ACME check after start-up and logs "issued but never deployed". What the upgrade involved The schema moves from 6025 to 6030 in five steps, one way. DBUpdater runs them in order and resumes from a partial upgrade; there is no downgrade. The 6029 to 6030 step adds seventeen FOREIGN KEY constraints with ON DELETE CASCADE and removes the orphan rows they would refuse. On a large database it reads every child table once, so plan for it like an index build. If you are on 6.2.21 or a 6.2.22/6.2.23 pre-release, read the 6.2.24 notes first. Everything there still applies. Behaviour that changes without a switch The Apple .mobileconfig profile is served over HTTPS only. Plain HTTP gets a 301 to the WebServicesHttpsPort listener, or a 403 when none is configured. A TLS-terminating proxy must send X-Forwarded-Proto: https. A Message-ID is added only to submissions (upstream #552). Relayed mail keeps its headers, so a filter counting on the header will now see messages without one. IMAP sequence numbers are stable within a session (upstream #602). Another session's expunge no longer renumbers a client's messages under it. Also fixed: two restarts at once, one over COM and one from an ACME deployment or backup restore, rebuilt the same queues under each other and could end in an access violation. Restarts now run in sequence. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    52 Views
    ProgressiverobotP
    6.2.24 is the stable release of the work carried by the 6.2.22 pre-releases and the 6.2.23 alphas. If you are on 6.2.21, all of it arrives at once. The headline is mail that was being lost silently. A delegated IMAP APPEND, COPY or MOVE filed the bytes under the wrong account, and a delegated MOVE destroyed the only readable copy. Anyone using shared or delegated mailboxes was exposed. Thunderbird also had every Sent copy refused once UTF8=ACCEPT was enabled (GitHub issue 53). What the upgrade involved The schema moves from 6011 to 6025 in fourteen one-way steps. DBUpdater runs them in order and resumes from wherever a partial upgrade stopped. There is no downgrade: an older server refuses a newer database rather than misreading it. Take a database backup and a data-directory backup with your backend's own tools first. Step 6024 to 6025 rewrites hm_messages.messageflags from tinyint to smallint on MS SQL, SQL Server Compact and MySQL/MariaDB. That is a table rewrite on the largest table you have, holding locks for its duration, so size the maintenance window by your message count. PostgreSQL is already smallint and unaffected. Changes that take effect without a switch MAIL FROM or AUTH straight after the STARTTLS handshake, with no second EHLO, now gets 503 Bad sequence of commands. RFC 3207 has always required that EHLO. A home-grown submission script will find out here. For mail arriving through a relay or fetched from an external account, the DNSBL, SPF and HELO tests now run against the address the relay observed, not the first bracketed value in the Received header, which the sender could set. If you tuned scores around the old behaviour, expect verdicts to move. Mail is refused with a temporary error when free space falls below 100 MB (MinimumFreeDiskSpaceMB, Server settings). Set it to 0 for the old behaviour. Per-account out-of-office now honours the RFC 3834 suppressions that previously applied only to the domain-wide reply. Early-bound COM clients built against a 6.2.22 pre-release interop assembly must be recompiled. Anything built against 6.2.21, and all late-bound scripts, are unaffected. Two further anti-spam bypasses are closed. A forged header could steer a per-account spam override into un-marking the sender's own mail. RSET before EHLO, or STARTTLS without a fresh EHLO, opened a transaction with an empty HELO host, skipping the HELO-host test and the script events. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    57 Views
    ProgressiverobotP
    This was an alpha. Everything in it shipped in 6.2.24. Nothing here should be installed today. Local delivery could lose a message with no trace. When the account-level copy could not be written, LocalDelivery reported HM5209 and returned, but the recipient row was deleted anyway and the queued message with it. The sender had already been given 250 and the recipient never heard of it. Anyone running a message store near full was exposed. The sender is now told. This is an alpha. Do not put it on a production mail server. What the upgrade involved The schema moves 6022 to 6025 in three registered steps, and it is one way. An older server refuses to run against a newer dbversion, so rollback needs a pre-upgrade database backup and a data-directory backup. The 6024 to 6025 step widens hm_messages.messageflags from tinyint to smallint on MS SQL, SQL CE and MySQL/MariaDB. That is a table rewrite on your largest table, holding locks throughout. Size the maintenance window to your hm_messages row count. PostgreSQL is unaffected. Silent upgrades with /VERYSILENT previously hung forever on a modal password dialog. Fixed. Five COM properties added during the 6.2.22 pre-releases were declared mid-interface, shifting the vtable on AntiSpam, Account, Application and GlobalObjects. They are appended now, restoring binary compatibility with 6.2.21. Late-bound scripts were never affected. Recompile anything early-bound against a 6.2.22 pre-release. Three new defaults change behaviour. MinimumFreeDiskSpaceMB=100 refuses new mail below the floor, 452 4.3.1 at MAIL FROM and NO [UNAVAILABLE] at IMAP APPEND. WindowsEventLogEnabled=1 forwards errors to the Windows Application log under the source hMailServer. DatabaseStatementTimeout=30 is untested on MySQL and PostgreSQL, the two backends it was built for. Existing per-account out-of-office replies now apply RFC 3834 suppression and stop answering bounces, list traffic and anything carrying Auto-Submitted or List-* headers. Also in this release PROXY protocol v1/v2 and XCLIENT in front of SMTP, so DNSBL, SPF, greylisting and auto-ban see the real client. Both ship off with empty trust lists. Shared and delegated IMAP mailboxes at #[email protected], gated on RFC 4314 ACLs. On by default, enableimapacl ships as 1. RFC 3030 BINARYMIME. Relay of a binary message is refused 554 5.6.3 rather than converted. RFC 3464 bounces. Every NDR is now multipart/report. Re-check anything parsing whole bounce bodies. External HTTP filtering hook (FilterHookUrl, FilterHookTimeoutSeconds default 10), plain HTTP only. Sender blacklist, per-account spam thresholds, distribution-list moderation, domain-wide out-of-office, IPv6 on the REST and metrics listeners. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    52 Views
    ProgressiverobotP
    This was the third pre-release in the 6.2.22 line. Everything in it shipped in 6.2.24. Nothing here should be installed today. Per-account two-factor authentication now works at the server. TOTP has been in this product for years and protected exactly one thing: the Control Panel's own logon, checked after the server had already accepted the password. The server had no idea the feature existed. It does now (schema 6017). Once a secret is enrolled, the account password stops being a mailbox credential and an app password becomes the only one. What the upgrade involved Upgrading from pre2 requires DBUpdater. The database schema moves from 6015 to 6019 in four steps. Password expiry ships with a caveat: this server has no self-service password change, so an expired password can only be reset by an administrator. Existing app passwords keep working, Active Directory accounts are exempt, and an unreadable stamp is never treated as expired. App passwords (schema 6016). A per-account credential, revocable on its own, that authenticates over IMAP, POP3 and SMTP alongside the account's own password. 20 symbols from a 30-character alphabet, about 98 bits, from OpenSSL's CSPRNG. They are tried only after the account password has failed. Password policy. IsStrongPassword has existed for years and nothing in the server has ever called it. Every mailbox on every installation could be test. Five settings now decide, plus one rule that is always on: a password may not contain the account name. Enforced where a password is chosen, never where an existing one is verified. Quarantine (schema 6018). Refused messages can now be held in a store an administrator can list, read, release or delete, with a review queue in the Control Panel. Quarantining answers 250 instead of 550, so the sender will not retry and this store is the only place the message exists. A quarantine that fails to store falls through to refusing. Off by default. IMAP and POP3. FETCH BINARY on a composite section returned an empty literal and BINARY.SIZE agreed with it. Documented as a limitation in pre2, fixed here. BINARY now announces content with literal8 (~{n}) as RFC 3516 requires. POP3 answers EXPIRE with NEVER and can enforce LOGIN-DELAY (RFC 2449). Off by default. OAuth2. ES256 tokens now verify. JWS carries an ECDSA signature as a raw R||S pair while OpenSSL verifies X9.62 DER. A key that does not match the algorithm named is refused on the key type. A valid ES256 token is still refused while the allow-list omits it. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    58 Views
    ProgressiverobotP
    A recipient lookup that failed because the database did not answer returned 550, exactly as a lookup that found nothing did. The two cases were indistinguishable inside the server, so a database briefly locked by a backup told the sending server that a valid mailbox did not exist and the mail was bounced instead of retried. That is mail loss with a delivery receipt. Anyone running against a database that stalls under backup, maintenance or load was affected. Those lookups now return 451. What the upgrade involved DBConnectionAcquireTimeout now defaults to 60 seconds rather than 0. It shipped disabled in 6.2.17 precisely because timing out an acquisition turned a slow database into a bounce. The 451 fix is what made it safe to turn on, but the pool deadline is live after this upgrade, so check the value if you set it explicitly. Bounded waits (GitHub issue 23, #24) Outbound delivery sessions get an absolute ceiling, ClientSessionCeiling, 30 minutes, separate from the idle timeout. The idle timeout re-arms on every byte received, so a peer dribbling one byte at a time held a delivery thread indefinitely. ClamAV on the delivery path (GitHub issue 23) is bounded and reports a timeout rather than holding the thread. DNS queries, event scripts and external scanner processes (GitHub issue 24) are bounded by DNSQueryTimeout (10s), ScriptTimeout (60s) and ExternalProcessTimeout (300s). Work queue saturation is reported on a schedule and names the task holding each thread, with its session and peer IP. Pre-authentication IMAP command buffering is capped at 11 MB. An unauthenticated peer could previously buffer without limit. Backup restore validates the source archive before deleting the target. It deleted first, so a corrupt archive destroyed the data it was restoring over. Other A first static analysis pass fixed a buffer overrun on long paths in GetExecutableName and two MySQL path helpers, and a shadowed fileExists in Logger::WriteLogFile that made rotation test an uninitialised value. A correction to the roadmap: ARC sealing is narrower than previously described. Arc::Seal sits after every early return in DKIMSigner::Sign, so relayed third-party mail is never sealed. Discussion #18 is fixed and bounded, but not yet confirmed against the original reporter's Postfix/PMG setup. If you are affected, the per-stage timings in the troubleshooting guide will name the culprit in one log line. Please post it on the discussion. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    53 Views
    ProgressiverobotP
    The .NET modernisation of the tooling is finished. Every C# component now targets .NET 8. There are no server-core changes and no database change: the schema stays at 6005. What the upgrade involved The supported-OS floor moved to Windows 10 1607, the .NET 8 runtime's own minimum, and the obsolete .NET Framework 4.5 gate is gone. The .NET 8 Desktop Runtime became a server-component prerequisite, not just a Control Panel one, and its exit code is checked before the database tools run at post-install. Changes DBSetup, DBSetupQuick, DBUpdater, DataDirectorySynchronizer and the Shared library moved from .NET Framework 4.8.1 to SDK-style net8.0-windows. The COM API is consumed through a checked-in tlbimp wrapper in source/Tools/Interop/, so the tools build with plain dotnet build and no registered typelib. The silent command-line contract the installer depends on is unchanged. The five VB6 migration wizards are gone. None could be built, their shared VB6 sources were never in the repository, and three migrated from products dead for two decades. The two worth keeping return as one .NET 8 Import Tool under Addons. Accounts from a comma-separated text file get per-line validation and a created/updated/failed summary instead of a crash on the first malformed line. Messages from mbox files stream through the supported COM API, Utilities.ImportMessageFromFileToIMAPFolder, one IMAP folder per file, rather than raw MySQL INSERTs. The silently dropped last message, CRLF mailboxes parsing as one giant message, mboxrd >From quoting and SMTP dot-stuffing corrupting stored messages are all fixed. CI now builds every C# project, with warnings-as-errors on the tools solution. Previously only the Control Panel was built, which let the NUnit 4 bump break the test and tool projects invisibly. The test suite runs on NUnit 4.6.1, with the 2,200+ classic assert call sites kept compiling through NUnit 4.6's C# 14 extension members. Local-address selection now probes for an address the server answers on instead of trusting interface enumeration order, which broke under a connected VPN. The full regression suite passed 1026 of 1026 against the rebuilt service, with live SpamAssassin and ClamAV. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    53 Views
    ProgressiverobotP
    This was a beta build of the 6.0 line. 6.0.0 was the production release. Nothing here should be installed today. This is the first build of the modernised 6.0 line to clear the full regression suite: 898 tests, 895 passed, 0 code failures. What the upgrade involved Database version was 6001. Upgrade from 5.7 was supported via DBUpdater. Toolchain for this build: VS2026 (v145), OpenSSL 4.0.1, Boost 1.91, PostgreSQL 18.3 libpq, .NET Framework 4.8.1. What 6.0 brings in: MTA-STS and DANE/DNSSEC outbound TLS policy, TLS-RPT reporting, TLS 1.2/1.3 defaults. ARC sealing, DMARC, Ed25519 DKIM. ACME (Let's Encrypt) with auto-apply. REST admin API, and an Administrator dashboard with TOTP 2FA. MTA-STS, autoconfig and autodiscover hosting. Prometheus metrics and JSON logging. PBKDF2 password hashing with transparent rehash. IMAP MOVE, ID and SPECIAL-USE, plus 8BITMIME. Fixed in this build: a latent CStdStr::FormatV buffer-count bug that crashed the service. Validation ran with live SpamAssassin (JAM Windows build), ClamAV 1.5.2 and all optional features enabled. The three non-passing tests are environment-bound rather than code defects. Two require an unfiltered DNS resolver for SURBL test queries, and one requires the service-based SpamAssassin variant. Installation is via the installer, against the internal database (SQL CE 4.0) or an external MySQL, MSSQL or PostgreSQL instance. IMPLEMENTATION-NOTES.md carries the feature and INI reference. Licensed AGPLv3. Based on hMailServer by Martin Knafve. Full release notes, checksums and signatures