Skip to content
hMailServer 6.3.3 — signed 15 September 2026, Windows and Linux, database schema 6040, and a drop-in upgrade from any 5.x install.Download 6.3.3 Documentation

Announcements & releases

33 Topics 33 Posts

Release notes, security advisories and forum notices from the maintainers. Read-only; questions belong in the categories below.

  • 0 Votes
    1 Posts
    7 Views
    P
    Every message over 60,000 bytes sent to a server advertising CHUNKING has stalled since outbound BDAT arrived in 6.2.25. Every release from 6.2.25 to 6.3.2 is affected. If your smart host or the destination offers CHUNKING, large mail has been failing, and OutboundChunking=0 is the workaround on any of them. 6.3.3 fixes it (issue #261). The SMTP client armed the read for the reply as soon as the BDAT command, or with PIPELINING the envelope, had been queued, and the chunk's second 60,000-byte buffer was queued behind that read in the operation queue, which starts only the operation at its head. The read could not complete while the remote waited for the bytes behind it, so nothing sent them, and the remote gave up on its own timeout. iCloud returned 421 after five minutes in the report. DATA never met it, because its body streams only after the 354. The queue now runs once more after a read has started. If you cannot upgrade yet, OutboundChunking=0 in hMailServer.ini is the workaround. Before you upgrade Two schema changes, both upgrade in place. Schema 6039 widens a domain's relay-password column: it held 255 characters and a DPAPI envelope is 314, so a relay password could not be saved on any Windows installation. Schema 6040 adds the CardDAV tables. On PostgreSQL the escaper doubled backslashes unconditionally, which is correct only while standard_conforming_strings is off, and that has been on by default since PostgreSQL 9.1. DKIM key-file paths, signatures, vacation messages and rules were stored doubled. Values already stored that way stay as they are. Edit and save them once. Also in this release The four [Settings] ini routes over REST answered to any api key. A read-only key could read the OAuth2 HMAC secret, the password pepper and the service account password, and a write key could set AutoBanCommand, which the firewall reconciliation runs as the service. They take the administrator password only now. A domain-scoped key is refused the eleven administrator-only fields on PUT /api/v1/domains/{domain} with 403. CardDAV (RFC 6352) for the account's address book, one book named Contacts, vCard 3.0 and 4.0, HTTP Basic over HTTPS only. The web services HTTPS listener has to be on (WebServicesHttpsPort). The webmail is rebuilt: inbox tabs, mute, pinning as $Pinned, follow-up dates as $FollowUp and $Due-YYYY-MM-DD, fourteen more search operators, twenty languages. The full-text indexer no longer reports an error for a message deleted before its terms were saved. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    2 Views
    P
    A SURBL lookup that failed was being read as a hit. The Spamhaus zones answer a query they refuse with a code in 127.255.255.0/24, and until now any answer at all counted as a listing. A server resolving through a public resolver such as 8.8.8.8, or sending too many queries, tagged every message carrying a link as spam (discussion #167). What the upgrade involved The database goes to schema 6038: steps 6032 to 6037 add contacts, account preferences, scheduled sends and snoozes, files sent as links, message keywords and S/MIME keys, and 6038 the SURBL expected result. 6.3.1 listed the 6029 to 6030 upgrade step as known and unfixed: on a database holding orphaned rows it could re-orphan rows it had already cleaned, then refuse its own foreign keys. It is fixed in all four backends. Changes Each SURBL server now has an expected result (SURBLServer.ExpectedResult, in the Control Panel's SURBL editor) in DNSBL syntax: 127.0.1.0-255, 127.0.0.2*, ranges and wildcards. With none set, any answer counts except the codes in 127.255.255.0/24. The debug log records what the zone answered and what was made of it. The portal at /portal is now a mail client, over /api/v1/me and the account's own credentials. Conversations by thread, search operators (from:, subject:, has:attachment, is:unread, label:), labels stored as IMAP keywords so every IMAP client sees them, undo send for up to thirty seconds, send later and snooze held on the server, oversize attachments sent as expiring links from /files/{token}, read receipts (RFC 8098) and one-click unsubscribe (RFC 8058). S/MIME runs in the browser on the Web Crypto API, the private key wrapped under a key derived from the account password. Not in this release: 3DES content, EC key agreement for encryption, legacy PKCS#12 encryption, OpenPGP. SASL GSSAPI (RFC 4752) on SMTP, IMAP and POP3, on Windows. Off unless GssapiEnabled=1 in [Settings]. Auto-ban can reach the firewall. AutoBanFirewall=1 writes an inbound block rule per banned address in Windows Defender Firewall, or keeps an nftables set on Linux. AutoBanCommand and AutoBanNeverBan go with it. All three are off as shipped. Making an app password now takes the account's own password, and an app password is never accepted for it. The 6.3.1 .deb depended on the builder's exact Boost sonames and would not install on Ubuntu 26.04. Boost is linked statically now. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    2 Views
    P
    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
    2 Views
    P
    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. (#156, #177) Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    2 Views
    P
    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 (#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
    2 Views
    P
    The DNSSEC validator that guards DANE and the SPF, DKIM and DMARC lookups treated a DS query answered with nothing as an unsigned delegation. That is exactly what an attacker stripping the DS in transit shows a resolver: a signed zone quietly became unsigned, and DANE and validated TXT went with it. Anyone relying on DANE or on DNSSEC-validated SPF, DKIM or DMARC was affected. What the upgrade involved Schema 6030 to 6031: one column on hm_fetchaccounts, added by the installer's database upgrade on every backend. From 6.2.25 or 6.2.26, run the installer. From earlier, read the 6.2.25 and 6.2.24 notes first. Security A missing DS is now proved missing (RFC 4035 §5.2, RFC 5155 §8). The resolver keeps the authority section of a negative answer and requires the parent's proof there: an NSEC at the delegation name with NS set and DS clear, an NSEC3 whose hashed owner matches with the same bits, or an Opt-Out NSEC3 covering the hash, each signed by the parent's key. A proof that fails to verify, has expired, claims a DS exists, or belongs to another name is no proof, and a delegation without one under a signed parent is now Bogus and blocked rather than Insecure. An unsigned parent, or a resolver that cannot be reached, still yields Insecure. The chain result is exposed as Diagnostics.DnssecChainStatus. Mail flow FetchAccount.MirrorFolders (schema 6031; "Mirror every folder" on an IMAP external account in the Control Panel) collects each remote mailbox into the local folder of the same name: every message byte for byte, with its \Seen \Flagged \Answered \Draft \Deleted flags, its internal date, and the remote hierarchy delimiter mapped to the local one. Nothing is delivered, so no rule, anti-spam or anti-virus touches a copy. Each folder records what it has collected, so a second poll takes only what is new. Days to keep messages 0 makes it a move. The Import Tool reads a Maildir: the INBOX and every Maildir++ folder beside it, with the flags the file names carry (;2, and !2, as well as :2,) and line endings made CRLF. An import into a folder a client has open now refreshes it, as a delivery does. Migration.md documents each route in and what it keeps: IMAP, mbox, Maildir, Outlook through IMAP (PST is deliberately not parsed), and bulk accounts. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    2 Views
    P
    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 (#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
    2 Views
    P
    ACME issuance and renewal ended the hMailServer process (#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
    2 Views
    P
    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 (#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
    2 Views
    P
    Inbound mail from a Postfix-based relay could hang forever. The connection logs 354 OK, send., stops dead, and the sender eventually gives up with "timed out while sending end of data", leaving a zero-byte file in the Data folder. Anyone taking mail from Postfix or a Proxmox Mail Gateway was affected, and a same-host relay hits it almost every time. Three previous releases claimed to fix it and did not. This one was settled by running a real Postfix 3.10 against the server and reading the bytes on the wire. What the upgrade involved Two known issues stand. Equal-preference MX records are not randomised (RFC 5321 5.1); the server always tries them in the order the resolver returned, and a comment and COM help string that claimed otherwise have been corrected. One-click unsubscribe (RFC 8058) is not implemented. RFC 2369 List-* headers are still emitted for distribution-list postings. Changes Postfix pipelines the terminating dot and QUIT into one segment, so the terminator sits mid-buffer and every tail-only end-of-data check missed it. The receive path now searches for <CRLF>.<CRLF> anywhere in what arrived and returns the remainder to the command parser. Bare-LF terminators are still recognised only at the very end of the buffer, with anything behind them discarded, which is the CVE-2023-51764 rule. SMTP dot transparency (RFC 5321 4.5.2) now carries line-start context across buffer boundaries in both directions. Previously a line-leading dot landing a byte or two into a chunk went unstuffed, silently truncating messages. Sieve scripts were left behind by domain and account renames and deletes. Recreating an address could reactivate the previous holder's filter, redirects included. Renames now move the Sieve tree, deletes remove it, and the Control Panel writes the script only after the save succeeds. Sieve body test (RFC 5173) implemented and advertised over ManageSieve, with :text, :content and :raw. SORT () US-ASCII ALL spun a connection thread at 100% of a core forever. Empty sort criteria are now rejected per RFC 5256. The 512 MB message-list cache never evicted and only counted upwards. Eviction now measures entries as they are. Malformed DNS answers are retried once over TCP. The Control Panel MX tool (#29) now uses the server's resolver via Utilities.ResolveMXRecords. Control Panel: seven Administrator functions restored, plus Welcome page icon alignment (#30). Everything in the 6.2.20 notes is in this release too. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    2 Views
    P
    6.2.20 fixes a fresh-install failure introduced in 6.2.19. Database creation failed on a new install, and the installer then hung instead of reporting the failure. Fresh installations of 6.2.19 on the built-in database, which is the default, were affected, and most likely fresh installations onto MySQL. What the upgrade involved Upgrades of an existing installation were never affected. Upgrades run the upgrade scripts, and those were clean, and existing servers already have their databases. Only fresh installs hit this. If an unattended 6.2.19 install is still sitting there doing nothing, it is waiting on a message box. What was wrong The SQL script runner splits a script into commands on blank lines. SQL Server Compact, the embedded database a fresh install uses, executes one statement per command and refuses a batch. A recent change added settings to the create scripts with a single newline between inserts, so three statements arrived as one command. Full SQL Server accepts that batch, so the development database and the 1,490-test regression suite saw nothing wrong. The same adjacency was in the MySQL and PostgreSQL create scripts. All three are fixed, and a mechanical sweep of all 199 SQL scripts confirms no multi-statement command remains in any create script or any SQL CE script. Five upgrade scripts from the 5.x era keep their batches for the full-server backends that accept them. The error raised a plain message box, and /VERYSILENT /SUPPRESSMSGBOXES suppresses only the suppressible kind. A silent install did not report the failure, it waited on a dialog with nobody at the keyboard. In CI that was ninety minutes until a person cancelled it. All 28 dialogs in the installer now take their default button under /SUPPRESSMSGBOXES, and the installer proceeds to an exit code a deployment script can read. Interactive installs see exactly the dialogs they always saw. Also in this release IMAP THREAD (RFC 5256), both algorithms, THREAD=ORDEREDSUBJECT and THREAD=REFERENCES, with real References-chain threading. It is bounded by the same per-command ceilings as SEARCH and SORT. An adversarial review found and fixed a stack overflow reachable through a deep reply chain, an uninterruptible header pass and a malformed-Date sort inversion. The installer smoke test now bounds the silent-install step at ten minutes, keeps the installer's own log, and on a database failure re-runs the setup tool and prints its stderr. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    2 Views
    P
    Fresh installations of this build failed. Database creation broke on the built-in SQL Server Compact backend, which is the default, and most likely on MySQL, and a silent install then hung on a hidden message box instead of reporting the failure. Upgrades of existing installations were unaffected. 6.2.20 fixed both. For anyone already running it: if a custom DNS server was configured, every DNS lookup hMailServer made had been failing since 6.2.16. This release fixed that. Installations with no custom DNS server were never affected, because the server list is only built when one is set. 6.2.16 moved name resolution onto the asynchronous DnsQueryEx and gave the custom-DNS-server entry a destination port of 53. A DNS_ADDR carries a full SOCKADDR, so setting the port looks correct. It is not: the DNS client supplies the port itself, and with port 53 every query returns status 87 and no records. MX lookups for outbound delivery, DNSBL, SPF and SURBL all failed. It surfaced loudest as HM5507 The IP address for SpamAssassin could not be resolved, which is how #25 came in. A regression test now points DNSServer at TEST-NET-1 (192.0.2.1) and requires the lookup to time out; a timeout proves a packet left the machine. What the upgrade involved The database schema moves from 6005 to 6011. DBUpdater applies it. Take a backup first. Settings are preserved. The [Settings] INI values move into the database for remote administration; the file still wins where both carry a value. Also in this release Active Directory can now create accounts, not just link them. Settings.PreviewDirectorySync and Settings.ApplyDirectorySync read an LDAP directory and create or update the mailboxes it says should exist, with a Control Panel page and an optional unattended schedule. A domain takes part only if its Active Directory domain name is set, so provisioning is opt-in per domain. Nothing is ever deleted. Sieve imap4flags now reaches the message. setflag, addflag, removeflag and the :flags tag were parsed and evaluated, then discarded at delivery. They are now applied to the stored message, and imap4flags has moved into the ManageSieve capability line. Only the five system flags can be stored; a keyword is logged rather than dropped in silence. GetUniqueMessageID could hand out the same UID twice, which makes a client show one message in place of another. An account address containing a colon accepted mail at RCPT TO, then failed when the message was filed: the local part becomes a directory name in the message store. Known issue: #26, partial FETCH BODY[]<offset.length> against 6.2.18, does not reproduce here against new tests that reassemble whole messages from chunks over FETCH and UID FETCH. If you can still reproduce it, post an IMAP protocol log. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    2 Views
    P
    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 (#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 (#23) is bounded and reports a timeout rather than holding the thread. DNS queries, event scripts and external scanner processes (#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
    3 Views
    P
    If your server accepts inbound mail from a trusted relay, a Proxmox/Postfix front end for example, and you run SpamAssassin, messages could stall after end-of-data and never get a 250. Reception was never the problem. The stall was in the accept/save work that runs after the terminating dot and before the reply. What the upgrade involved No database change. Schema version stays at 6005. The same audit found other unbounded waits, not fixed here: synchronous DNS lookups in the spam tests have no application-level timeout, the database connection pool has no acquisition deadline, event scripts have no execution limit, and the ClamAV read/write timeout on delivery is ineffective. Why it only ever hit relayed mail For a trusted incoming relay, hMailServer defers the whole spam battery to after end-of-data. For a direct or authenticated sender those tests run earlier, during MAIL FROM/RCPT TO, on the connection thread. The post-DATA work runs on a bounded pool, 15 threads by default, and holds the thread that sends the 250. SpamAssassin's wait had no overall ceiling: the connection's idle timeout is re-armed on every byte received, so a scanner that stalls or dribbles holds the thread indefinitely. Against a blackholed SpamAssassin endpoint, one message was acknowledged after 120 s. Eighteen concurrent messages produced zero acknowledgements: 15 workers blocked, the rest with no worker at all. The fixes SpamAssassin's wait is bounded. Hard ceiling of SAMaxTimeout + 30 s, after which the message is accepted without a verdict, the same outcome as spamd being down. New FinalizationTimeout, default 240 s, inside Postfix's 600 s data-done timeout, 0 disables it. Acceptance past that answers 451 4.3.1 and the sender retries. The check runs on the accepting thread and only before anything is saved, so it cannot duplicate mail. Acceptance is timed per stage and each spam test timed individually. A slow stage is logged at APPLICATION level, not only under debug: Spam test: SpamTestSpamAssassin, Score: 0, Time: 120031 ms. Upgrading is enough to turn silent stalls into either a completed delivery or a clean 451 retry. Enable debug logging and the per-stage timings name the scanner, DNS lookup or event script responsible. Also in this release: regression coverage for clients that vanish mid-operation (aborted DATA, truncated BDAT, IMAP APPEND literals cut short, POP3 disconnects during RETR), plus an installer smoke test on a clean machine. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    3 Views
    P
    The Control Panel raised an error dialog every time you dismissed the Ctrl+K settings palette (#21, reported by grumpymojo). It was present in both 6.2.14 and 6.2.15, and because choosing a result and pressing Esc both went through the same path, it appeared on essentially every search rather than on any particular search term or configuration. What the upgrade involved No server change and no database change. Schema version stays at 6005. Anyone coming from 6.2.14 or earlier should read the 6.2.15 notes as well, because everything in them applies here. Fixed Closing the palette moves the focus away, which raised the deactivation handler while the close was still in progress, and that handler closed the window a second time. WPF refuses that outright: System.InvalidOperationException: Cannot set Visibility to Visible or call Show, ShowDialog, Close, or WindowInteropHelper.EnsureHandle while a Window is closing. The deactivation handler now closes the palette only when a close is not already under way. Nothing was lost to this defect. The navigation had already happened by the time the dialog appeared, so no setting was misapplied. It was noise in the one feature added to make settings easier to find. Still open at this release Discussion #18, the stall after 354 when relaying from Postfix or Proxmox Mail Gateway, remained open and unreproduced. 6.2.15 added debug logging to the SMTP DATA path that distinguishes the three candidate stages, and that log is what will identify the cause. Tracked in #20. Validated by the full regression suite: 1040 of 1040 passing, zero failures. The download is hMailServer-6.2.16-x64.exe. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    2 Views
    P
    The IMAP sequence-set parsers only recognised * as the end of a range. Anywhere else it was parsed as zero, so UID STORE *:* +FLAGS (\Deleted) flagged every message in the mailbox, UID EXPUNGE * deleted every \Deleted message, and FETCH * returned nothing while answering OK. Any client using * outside a range was affected. What the upgrade involved No database change. The schema stays at version 6005. Issue #18 is not fixed and remains open, see #20. All four sequence-set parsers now resolve * on either side of a colon and normalise descending ranges, so 3:1 is the same set as 1:3, per RFC 3501. Twelve regression tests cover it, all twelve failing against 6.2.14. Also fixed: Restoring messages emptied the live data directory before checking the backup's message store existed. A settings-only backup restored with the messages option ticked, or a failed extraction, left an empty data directory and the only copy of the mail in a GUID-named temporary folder. It now checks first. A message whose file could not be read hung the outbound connection after the remote answered 354, idle until the client timeout of up to ten minutes, then re-queued and repeated. It now fails immediately. Only a genuinely missing file fails the delivery permanently. BDAT exact-length reads padded short chunks with NUL bytes. A sender announcing BDAT 100000 LAST that vanished after 40,000 octets had the truncated message delivered as complete. DKIM signing hashed the header name in lower case while writing it capitalised (upstream PR #530), so signatures using simple canonicalization failed strict verifiers. Several paths left files with no database row: rejected POP3 RETR, header rewrites leaving .eml.tmp, downloads with no local recipient, unsendable bounces. The account cache had no size cap. ManageSieve now disconnects after three failed authentication attempts and registers them with auto-ban. STATUS (RECENT) reported the selected folder's count for every folder. Settings configurable only in hMailServer.ini gained Control Panel pages: authentication, administrative access, DNS resolver, web services and autoconfiguration, and the consistency scan results. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    7 Views
    P
    A message file that could not be written was treated as success. IMAP APPEND answered OK [APPENDUID ...] for messages that were never stored, so Sent Items copies, drafts and migration uploads were lost while the client showed them saved. Anyone hitting a full volume, or a file locked by antivirus or backup, lost mail silently. A failed message copy killed the delivery task in local delivery, forwarding, Sieve redirect and mirroring, leaving the message locked in the queue to fail again on every restart. Both came from an adversarial audit that found and fixed 21 defects. No database change: schema version 6005, unchanged. The regression suite passed 1026 of 1026. Mail loss and stability Every string SQL parameter on MS SQL and SQL CE was bound from freed memory. A failed transaction start leaked its pooled connection, and after a few occurrences SMTP, IMAP and POP3 blocked until a service restart. A failed IMAP folder insert was reported as success, so messages filed into it were written to disk with nothing to find them by. Security DKIM test mode (t=y) turned a failed signature into a pass, which then satisfied DMARC alignment. A failure in test mode is now neutral, per RFC 6376. IMAP SASL credentials were logged verbatim: AUTHENTICATE PLAIN passwords and XOAUTH2/OAUTHBEARER tokens. Only the first DKIM key record at a selector was read, so roughly half of a rotating sender's mail failed verification. MTA-STS enforcement and MX failover were lost for recipients past the first batch. Protocol and Control Panel SELECT/EXAMINE report a sequence number in [UNSEEN], as RFC 3501 requires, not a UID. Reverse-DNS lookups for the Received header moved to their own thread pool, completing the 6.2.13 fix. Backup would not start (#19): a Control Panel call to a method the backup interface does not have. Ctrl+K now searches settings, all 227 indexed by label and INI key. Logging, scanner timeout, indexing and retry settings moved to the pages that own them, which is where #16 went. Full release notes, checksums and signatures
  • hMailServer 6.2.13: a DATA stall on relayed mail

    release bugfix smtp imap spam
    1
    0 Votes
    1 Posts
    2 Views
    P
    The headline fix is an SMTP DATA stall that only affected relayed mail. Relaying from Postfix or Proxmox Mail Gateway, the connection could hang after 354 OK, send. until the sending MTA gave up with "timed out while sending end of data", leaving a zero-byte spool file. The cause was a reverse-DNS (PTR) lookup on the network I/O thread while generating the Received header, so an internal relay with no reverse zone stalled the session through DNS retries. That lookup now runs on a worker thread and header generation never waits on it. Direct sending was unaffected. What the upgrade involved No database change. Schema version stays at 6005. Minimum OS is Windows 10 1607 / Server 2016, 64-bit, which the installer's version check now names. SMTP. A parse exception no longer wedges a connection, data pipelined in the same segment as DATA is consumed correctly, a rejected BDAT/CHUNKING command drains or terminates its payload instead of desyncing the session (it matters for Exchange), the EHLO SIZE keyword no longer overflows, and TCP_NODELAY is set on every connection. IMAP. A malformed partial-fetch range such as BODY[]<0.-1> could drive a near-SIZE_MAX allocation, or read heap memory from before the buffer and send it to an authenticated client. The octet range is now clamped and normalized. OnClientLogon now fires from every AUTHENTICATE mechanism (PLAIN, SCRAM-SHA-256, XOAUTH2/OAUTHBEARER). SpamAssassin. A malformed or truncated spamd response could spin a core and hang the session, write the raw SPAMD header into the message, or overwrite it with a zero-byte file. The 256 MB scan ceiling is now clamped to the 80 MB MIME parser limit, and the original message is preserved on any failure. Upgrade and installer. DBUpdater labels database versions 6002-6005, a failed database create or upgrade returns a real exit code instead of a false success, and a customised EventHandlers.vbs survives reinstall. Control Panel. Diagnostics no longer reports every test as FAILED, and restarting the service is elevation-aware. The regression suite passed 1026 of 1026 against the rebuilt 6.2.13 service. Full release notes, checksums and signatures
  • 0 Votes
    1 Posts
    2 Views
    P
    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
    2 Views
    P
    Two lists in the Control Panel announced their CLR type name to screen readers instead of their contents. The alias list on the Domains page read hMailServer.ControlPanel.Views.DomainsView+AliasRow for every row, and Live logs read LogsView+LogLine for every line. The live log is the worse of the two. It is the page an administrator is most likely to be reading with a screen reader when something has gone wrong. Both lists use an ItemTemplate, so the text a sighted user sees comes from a binding, while a ListViewItem's accessible name falls back to ToString(). Neither class overrode it. Scope is genuinely those two. Every other list in the application is a DataGrid, which builds a row's name from its cells. The Domains page now reports [email protected][email protected], and the live log reports 37 items, none announcing a type name. (16184ce) The regression suite now runs in full 27 of the suite's 1026 tests had never executed on the release machine. They reported inconclusive because SpamAssassin and ClamAV were not installed. Installing both ran them for the first time and two failed, both defects in the tests rather than the server. TestWithVirus put the EICAR string in the plain body of a non-MIME message. Current ClamAV does not extract a plain body as a scannable part, so the message scanned clean and was delivered, failing its own "no messages" assertion. It now sends EICAR as a base64 attachment and matches the signature family rather than one exact name. TestSANotRunning called ServiceController.Stop() and returned immediately. Stop() only asks, so spamd was still answering on port 783 and the message came back with the X-Spam-Status header. It now waits for the port to refuse connections. It also asserted error 5157, reported only when a connection is established then lost mid-read. With spamd stopped, only 5508 is reported. 1026 of 1026 now pass, zero inconclusive, with live SpamAssassin and ClamAV, DMARC against live DNS and TLS 1.2/1.3 handshakes. Drop-in over 6.2.10. No database change (schema version 6005), no configuration change, no server-core change. Full release notes, checksums and signatures