Accessibility
Two lists announced their type name to screen readers (16184ce)
The alias list on the Domains page exposed hMailServer.ControlPanel.Views.DomainsView+AliasRow as its accessible name for every row, and Live logs exposed LogsView+LogLine for every line.
Both lists use an ItemTemplate, so the text a sighted user sees comes from a binding — Display and Text respectively — while a ListViewItem's accessible name falls back to ToString() on the bound object. Neither class overrode it, so assistive technology received the CLR type name instead of the content.
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 at exactly the moment something has gone wrong.
Scope is genuinely these two. The domain, account and distribution-list views on the same page bind plain strings and were always correct, and every other list in the application — IP ranges, queue, routes, rules, certificates, TCP/IP ports — is a DataGrid, which builds a row's name from its cells rather than from ToString().
Verified through the same API that exposed the problem: the Domains page previously reported one item as DomainsView+AliasRow and now reports [email protected] → [email protected]; the live log reports 37 items, none announcing a type name.
The regression suite now runs in full
The suite has reported "green" for some time, but 27 of its 1026 tests had never actually 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 were defects in the tests, not the server. ClamAV: the virus test could not detect its own virus
TestWithVirus put the EICAR string in the plain body of a non-MIME message. ClamAV's EICAR signatures match a whole file, not a substring, and the boundary is easy to demonstrate over clamd's own INSTREAM:
Older ClamAV extracted a plain body as a scannable part; current ClamAV does not, so the message scanned clean and was delivered — and the test failed on its own "no messages" assertion.
hMailServer was never at fault. It connected, streamed the file and parsed the FOUND reply correctly, which the attachment case proves. The test now sends EICAR as a base64 attachment, which is how a virus actually arrives, and matches the signature family rather than one exact name — the name has already changed once across ClamAV releases and the test was still asserting the old one.
SpamAssassin: a race and a wrong expectation
TestSANotRunning called ServiceController.Stop() and returned immediately. Stop() only asks — it returns as soon as the request is accepted, while spamd is still up and still answering on port 783. The test then sent a message straight into a live spamd and got the X-Spam-Status header it was asserting could not be there. It now waits for the port to refuse connections.
It also asserted "There was a communication error with SpamAssassin." alongside the real error. That is error 5157, reported by SpamAssassinClient::OnReadError when a connection was established and then lost mid-read. With spamd stopped there is nothing to connect to, Connect() fails outright, and only error 5508 is reported. Asserting both demanded a different failure mode from the one under test.
Result
1026 of 1026 passing, zero failures, zero inconclusive — with live SpamAssassin and ClamAV, real EICAR detection, DMARC evaluation against live DNS, and TLS 1.2/1.3 handshakes end to end. Every test in the suite executes; nothing is skipped.
The README now documents the setup that makes this reproducible. It previously pointed at a JAM Software SpamAssassin download that no longer exists; it now describes Strawberry Perl plus CPAN, with spamd rebuilt via BUILD_SPAMD=yes because the Windows build skips it by default, and perl.exe copied to spamd.exe inside Perl's own bin so @INC still resolves. It also states the elevation requirement the suite has always had but never documented — it starts and stops Windows services, which a standard user cannot do.
Upgrading
Drop-in over 6.2.10. No database change (schema version 6005), no configuration change, no server-core change.