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
    181 Views
    ProgressiverobotP
    Every documentation topic on this forum, by the category it sits in. Each one is written from the project's wiki and the operator documents at the release tag, for hMailServer 6.3.4, and links the pages it was written from. The long tail is in the wiki and the operator documents; the public documentation is the same material as one long page. A question that none of these answers belongs in the category it is about, as a new topic; Read this before you post says what a support request needs. Running hMailServer General support Read this before you post: what a support request needs Where to post what: a map of the forum categories Diagnosing stalled mail: a sender that times out, and a message that never leaves Reading the logs: levels, files, the Logs page, following a connection, and fail2ban Backup and restore: what is in the archive, what is not, and restoring one mailbox Settings: what is not stock, when a save takes effect, and the three levels The Control Panel on Windows: every page, what it writes, and what applies when IMAP and POP3 on the server: capabilities, switches, shared mailboxes, search limits Troubleshooting by symptom: no mail in, no mail out, a service that will not start Every port hMailServer listens on or connects to, and the firewall rules to match Installation, migration & upgrades Upgrading to 6.3.4: any 5.3 or later goes straight there Moving to new hardware, and why Windows to Linux is a rebuild Installing on Windows: wizard pages, service account, profile and the first hour Choosing a database, creating it, encrypting the link and leaving the built-in one Your first domain and mailbox, and the DNS records your domain needs Bringing mailboxes in: IMAP mirror, Google, Microsoft 365, mbox, Maildir and PST Unattended installs, winget and Chocolatey, and configuration from the environment Warm standby and high availability: what a second machine can and cannot do Message storage: compression, de-duplication, object storage and encryption at rest The update check and the live update: feed, verification, window and rollback Upgrading from 5.x, 6.2 or 6.3: the 24 changes without a switch, and rolling back Linux hMailServer on Linux: what you get and what you do not First install on Linux: the order of operations, Ubuntu to Enterprise Linux The hmailserver command line on Linux: every verb, who runs it, the files, the unit In a container or on Kubernetes: the image, Compose, Helm and the environment Databases on Linux: PostgreSQL or MariaDB, the client, TLS and the upgrade floor Webmail, portal & Control Deck The webmail portal at /portal The Control Deck: browser administration at / Calendars, contacts, the directory and shared address books over CalDAV and CardDAV Signing in: passwords, second factor, passkeys, single sign-on, recovery, devices The webmail in depth: search, offline mail, expiring messages, send-as and recovery Connecting a mail client: IMAP, POP3, SMTP submission, app passwords and the ports TLS, certificates & deliverability Let's Encrypt certificates are automatic: the built-in ACME v2 client Being trusted by the servers you send to TLS on the listeners: your own certificate, versions, ciphers and client certificates Requiring TLS: MTA-STS and TLS-RPT, DANE with ACME, and remote domain policies DKIM rotation, DMARC and TLS reports, complaints, bounces and the reputation watch Outbound shaping and IP warm-up: one slow destination must not stall the queue End-to-end encryption: S/MIME authority, OpenPGP and WKD, zero access, sealed mail Anti-spam & message filtering The anti-spam stack end to end: score, greylisting, SPF, DKIM, DMARC, DNSBL, SURBL Allow and block lists, digests, spam traps, country blocking and impersonation Viruses and dangerous attachments: ClamAV, custom scanners, the sandbox, sealed mail Mail flow rules, the outbound content policy and what a domain does to a message Guides & tutorials Quotas, retention and the archive: how much mail the server keeps, and for how long Administrator roles end to end: the 27 permissions, giving a role, where each works How the service is built and what runs out first: pools, connections, large folders IP ranges, auto-ban, lockout, tarpits, sending limits, send-as and password storage Behind a gateway, load balancer or reverse proxy: relays, PROXY, XCLIENT and HTTPS Hardening a public mail server: secure defaults, checklist, sealed secrets and roles Compliance: eDiscovery, legal holds, personal data, erasure and the audit trail How email works, and what hMailServer is and is not Relocating an installation to another drive, and moving or renaming a mailbox Automation & integration Scripting & the COM API Event scripts: every event and its arguments, the limits, and the 6.3.4 security fix The COM API on Windows: object model, Save() since 6.3.4, roles and the Import Tool REST API & integrations The REST API: turning it on, credentials, roles, one-time codes, OpenAPI and examples Active Directory and LDAP sign-in, directory synchronisation and OAuth2 bearer tokens hmctl and the PowerShell module: shell administration and accounts from a CSV file Integrating applications: the send API, mail in to a webhook, and outbound webhooks SCIM provisioning from Entra ID and Okta, and single sign-on for the organisation Rules, Sieve & routing Rules and Sieve: what runs when, vacation replies and the Run function action Routes, relays and smart hosts, OAuth2 relaying, restricted delivery and recall Aliases, distribution lists, membership queries, mailing lists and public folders Journaling and dual delivery: a compliance copy, and what a journal rule does not see Monitoring, metrics & logs Monitoring and health: Prometheus metrics, health probes, Grafana, OTLP and SNMPv3 Alerts, the audit trail, syslog and the journal, and per-domain reports Releases The current release, its announcement and the release history are in Announcements & releases.
  • 0 Votes
    1 Posts
    147 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) accepts the UTF8 that classic Outlook for Windows (Outlook 2016 to 2024) sends after the POP3 login, at which its downloads had stopped; SMTP, POP3 and ManageSieve refuse a SASL PLAIN sign-in that asks to act as another account, and IMAP takes an authzid naming the client itself as none; IMAP's COPY and MOVE by message number read their set in the client's numbering and refuse one that names a message another session has just expunged (NO [EXPUNGEISSUED]), FETCH BODY[N.MIME] and BODY[N] of a multipart are the stored octets, and a refusal by the access control is NO [NOPERM]; and the IMAP and POP3 listeners can take the client's address from a PROXY protocol header, as the SMTP listener does, off by default. An authenticated submission is DKIM-signed as another hosted domain only when the account may send as the address its From names. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026) signs a client in only when its user name is the account's stored address, compared in lower case after a domain alias and the default domain. A user name that differs from it in more than the case of the letters A to Z, or has white space at either end, may no longer sign in: such a name fails as a name that does not exist fails, so correct the user name in the client. See the 6.3.8 announcement. This topic covers connecting a mail client to hMailServer 6.3.4: ports, authentication, folders, automatic configuration, app passwords and devices. The one thing to know first: a new installation of 6.3.4 refuses a password from any machine but itself until the session is encrypted, and an upgraded server is not changed. On either, the TLS ports 465, 993 and 995 exist only once you create them. The settings your users need Setting Value Why, and what goes wrong Incoming server (IMAP) mail.yourcompany.com, port 993, SSL/TLS Implicit TLS: the handshake comes before the greeting. On a port not configured as SSL/TLS the client hangs, then times out Incoming server (POP3) mail.yourcompany.com, port 995, SSL/TLS The same. Only use POP3 if you have a reason to Outgoing server (SMTP) mail.yourcompany.com, port 587, STARTTLS Port 25 is for other servers, not for your users; many ISPs block outbound 25 from residential lines User name The full email address, [email protected] A bare name works only with Maintenance → Advanced → Default domain (for unqualified logons) set Password The account's password, or an app password if the account is enrolled in TOTP See the app passwords section below Encryption Never "none", never "auto-detect" "Auto-detect" is how a client ends up sending a password in the clear The ports, and what 6.3.4 changes on a new installation A new database is seeded with four rows - SMTP 25, SMTP 587, POP3 110 and IMAP 143 - and up to 6.3.3 all four were without encryption. Add 465, 993 and 995 yourself under Connections & protocols → TCP/IP ports in the Windows Control Panel, or on the Control Deck, once you have a certificate of your own. Connection security What the server does None (0) Plain text; STARTTLS is not advertised. Everything, including the password, is in the clear SSL/TLS (1) Handshake first, banner after. Correct for 465, 993 and 995 STARTTLS optional (2) Advertises STARTTLS and accepts both. The right setting for port 25 only: on a submission port it lets a misconfigured client send its password in the clear STARTTLS required (3) Answers 530 5.7.0 Must issue STARTTLS first. to every command except NOOP, EHLO, STARTTLS and QUIT. Right for 587, and for 143 and 110 if you keep them; on port 25 it silently refuses mail from every server that cannot do TLS With TLS chosen and no certificate selected the listener does not start at all: HM5113, Error initializing SSL. Certificate not set., in the application log, connection refused, nothing in the SMTP log; pick a certificate on the port. A port already in use is HM4316, and the rest of the server starts normally. A new installation of 6.3.4 has all four seeded listeners at STARTTLS optional with a self-signed certificate, which a mail client warns about until it is replaced, and the Internet IP range requires TLS for authentication; My computer (127.0.0.1) is left as it was. So from another machine, until the client sends STARTTLS: SMTP AUTH is not offered, and is refused with 530 A SSL/TLS-connection is required for authentication. if it is sent; IMAP advertises LOGINDISABLED, and LOGIN and AUTHENTICATE answer BAD A SSL/TLS-connection is required for authentication.; POP3 USER and AUTH answer -ERR. After STARTTLS every one of them works: the range's rule, not the port's, is what protects the password. When ACME's first certificate arrives it is given to every listener holding the self-signed one: see Let's Encrypt certificates are automatic. An upgraded or attached database is never changed. On Linux the defaults are applied at the unit's first start only when it comes within a day of --create-database. Which databases get them, the verb that applies them by hand and the checklist item that judges an upgraded server are in Hardening a public mail server. The IP range, not the port. RequireTLSForAuth lives on the IP range (Access & abuse protection → IP ranges, the Require auth tab). A range that requires TLS is offered no authentication mechanism at all on a cleartext connection, and IMAP additionally advertises LOGINDISABLED, so a client learns before it sends the password. DisableAUTHList is a comma-separated list of local ports on which SMTP AUTH is neither advertised nor accepted; use it to keep authentication off port 25. Since 6.3.4 such [Settings] keys are kept in the database: change them in the Control Panel, over REST (PUT /api/v1/settings/ini/{name}) or on Linux with hmailserver --set-setting NAME=VALUE. The database's value is the one used; where the service can write hMailServer.ini, a line edited there is put back (HM5804). Which port, decided once. For sending, 587 with STARTTLS required, or 465 if the client does not do STARTTLS properly; for receiving, 993, or 995 for POP3 on exactly one device. Never 143 or 110 without STARTTLS required, and deny 143 and 110 at the firewall once no client is left on them. What the server will actually accept Protocol Mechanism Advertised when Default on a fresh install SMTP AUTH LOGIN AUTH is enabled on the port Yes SMTP AUTH PLAIN Allow plain-text authentication is on No - authallowplaintext is seeded 0 SMTP AUTH SCRAM-SHA-256 Always, when AUTH is enabled Yes SMTP AUTH SCRAM-SHA-256-PLUS On a TLS connection Yes, on a TLS connection SMTP AUTH XOAUTH2 / OAUTHBEARER OAuth2 is enabled, and by default over TLS No SMTP AUTH EXTERNAL The handshake verified a client certificate on that port No IMAP LOGIN command Unless the port or the IP range requires TLS on a cleartext connection Yes IMAP AUTH=PLAIN, AUTH=SCRAM-SHA-256 Allow SASL PLAIN authentication is on No - EnableImapSASLPlain is seeded 0 IMAP SASL-IR Allow SASL initial client response is on No POP3 USER/PASS, SASL PLAIN, SASL SCRAM-SHA-256 Unless authentication is refused on this cleartext connection Yes The switches are on Connections & protocols → Protocols, the SMTP and IMAP tabs. Two consequences look like client bugs when they are not. On a default install, an IMAP client that insists on AUTHENTICATE PLAIN finds no AUTH= capability at all and must fall back to LOGIN. And SCRAM is always the account's own password, so an account with a second factor enrolled, or whose password has passed PasswordPolicyMaximumAgeDays, cannot sign in over SCRAM at all. Outlook on the desktop will not use SCRAM: it needs LOGIN or PLAIN. What the conversation looks like An extract of IMAP on a default install: * OK IMAPrev1 a002 LOGIN alice secret a002 NO Invalid user name or password. Please use full email address as user name. a003 LOGIN [email protected] secret a003 OK LOGIN completed The hint is given because the user name has no @. SMTP submission on 587, STARTTLS required: 220 MAIL01 ESMTP EHLO laptop.example.net 250-MAIL01 250-SIZE 20971520 250-8BITMIME 250-PIPELINING 250-CHUNKING 250-BINARYMIME 250-SMTPUTF8 250-ENHANCEDSTATUSCODES 250-DSN 250-STARTTLS 250 HELP MAIL FROM:<[email protected]> 530 5.7.0 Must issue STARTTLS first. STARTTLS 220 Ready to start TLS There is no AUTH line in that first answer, because the port requires TLS. After the handshake the client must send EHLO again, since the session starts afresh (RFC 3207 section 4.2). The second answer carries 250-AUTH LOGIN SCRAM-SHA-256 SCRAM-SHA-256-PLUS. Folders your users will look for A brand-new mailbox contains INBOX and nothing else. Drafts, Sent, Trash and Junk are created only when Create Drafts, Sent, Trash and Junk for new accounts is switched on (Connections & protocols → Protocols → IMAP), and the setting is seeded off. That is the usual explanation for "my sent mail is not on the server": the client fell back to a local folder because it found nothing designated \Sent. Fact Value Hierarchy delimiter ., so a subfolder of Work is Work.Invoices Public folders namespace #Public Other users' folders namespace #Users, only when ACL (shared folder permissions) is on - it is on by default Special-use designations \Drafts \Sent \Trash \Junk, advertised as SPECIAL-USE and CREATE-SPECIAL-USE IMAP or POP3. hMailServer advertises EXPIRE NEVER, so "leave mail on server" means for good, and a second POP3 session on the same mailbox gets -ERR [IN-USE]. What 6.3.4 changed in IMAP's answers Dovecot's imaptest was first run against this server on 25 September 2026: 31 of its 71 scripts failed, and 4 after 6.3.4 made the server answer as the RFCs say. The capability list is unchanged. A client that relied on the old answers may notice these: When the client 6.3.4 answers Names a mailbox that does not exist, or needs a right the account lacks NO, where it used to answer BAD; a failed SELECT or EXAMINE leaves no mailbox selected Sends an unknown LIST selection or return option BAD Fetches any BODY[<section>] without .PEEK Sets \Seen, BODY[HEADER] and BODY[1.MIME] included Appends a message Stores the literal byte for byte, where it used to add a CRLF, so RFC822.SIZE of a newly appended message is two octets smaller Pipelines a command behind an APPEND with a non-synchronising literal Answers it; it used to be thrown away, which stopped mbsync after one message Sorts, or threads Uses every criterion and builds the RFC's trees, so either can order messages differently Is the first session to be told of new messages Counts them as \Recent, where it said * 0 RECENT Automatic client configuration The server can configure clients, so users type only their address and password. AutoconfigEnabled is already 1; giving the web-services listener a port is what turns it on (WebServicesHttpPort=80, WebServicesHttpsPort=443), at the next reinitialise or restart, since the listener binds when it starts. Both port keys default to 0. Then point autoconfig.yourcompany.com (Thunderbird) and autodiscover.yourcompany.com (Outlook) at the server; both are ordinary host records. URL path Format Fetched by /mail/config-v1.1.xml, /.well-known/autoconfig/mail/config-v1.1.xml Thunderbird autoconfig XML Thunderbird and its relatives /autodiscover/autodiscover.xml Outlook POX autodiscover XML Outlook /email.mobileconfig, /mail/config.mobileconfig Apple configuration profile iOS and macOS Mail Which port ends up in the answer. The server reads your actual port rows and picks the best one per protocol: Rank Port configuration socketType written 100 SSL/TLS (implicit) SSL 90, 80 STARTTLS required on port 587; on any other port STARTTLS 70, 60 STARTTLS optional on port 587; on any other port STARTTLS 10 No encryption plain A protocol with no port at all is omitted. The host name is AutoconfigClientHost if set, otherwise the server's configured host name; with both empty the endpoint answers 404. Delegated mailboxes (since 6.3.4). The Outlook answer also names an AlternativeMailbox for every account that has opened a folder to the address asked about, but only to a request with HTTP Basic credentials, over HTTPS, for that very address. An Outlook IMAP profile never sees it: Outlook reads the element only for an Exchange account, and sends credentials only after a 401, which this server never returns here. What puts a delegated mailbox into a client's folder tree is the IMAP #Users namespace. None of this has been measured in Thunderbird or Outlook. Accounts with a second factor: app passwords A mail client has nowhere to type a six-digit code. Once a TOTP secret exists on an account, the account password is no longer a mailbox credential, and an app password is the only one. The order matters, and the Windows Control Panel puts the tabs in that order on purpose: Open the account: Accounts & domains → Domains → your domain → Accounts → the account. App passwords tab: create one per device, and write down the generated value; it is shown once. Two-factor tab: enrol the secret. Do it the other way round and every configured client stops working with no way back in. App passwords work for Active Directory accounts too, and are unaffected by password expiry, so enabling PasswordPolicyMaximumAgeDays does not silently break configured clients. A person makes their own on the webmail's Security page, which asks for the account's password again. Passkeys and single sign-on do not reach a mail client (since 6.3.4). They sign a person in to the webmail and the Control Deck and nothing else. An account that single sign-on or SCIM made has a random password nobody was told, so it needs a password set by an administrator before its person can make an app password for a phone. A recovery code is not a mail-client credential either. A mailbox encrypted at rest takes its own password only (since 6.3.4). It cannot enrol a TOTP second factor; on IMAP and POP3 its app passwords, an OAuth2 token, a client certificate and a Kerberos ticket are refused, and SCRAM does not open a key that is closed, so the client signs in with IMAP LOGIN or AUTHENTICATE PLAIN, or POP3 USER/PASS or AUTH PLAIN; and a client that was signed in when the switch was made is disconnected once. Devices: what revoking does Every client that has authenticated is one entry on the account's Devices list. Revoking a mail client's entry drops a live IMAP, POP3 or SMTP connection where it stands; a CalDAV, CardDAV or ManageSieve client has no connection to drop, so revoking one means revoking its app password. A revoke is not a ban: a client whose credential still works signs in again, so turn off its app password too, or change the account's password, which drops every connection of the account. Where the list is and what revoking does exactly are in Signing in. When it does not work What the user sees What the server said Cause Fix "Invalid user name or password", with a hint NO Invalid user name or password. Please use full email address as user name. Bare user name, no default domain Use the full address "Invalid user name or password", no hint NO Invalid user name or password. Wrong password, inactive account or domain, a TOTP-enrolled account given its account password, or, since 6.3.8, a user name that differs from the stored address in more than the case of the letters A to Z or has white space at either end Check both are active; issue an app password; give the address as stored "Authentication required" on sending 530 5.7.0 SMTP authentication is required. The client is not logged in for outgoing mail, or is on port 25 Tick "my server requires authentication"; move to 587 "Must issue STARTTLS" 530 5.7.0 Must issue STARTTLS first. Client encryption set to none on a STARTTLS-required port Set the client to STARTTLS A new 6.3.4 installation refuses the password from another machine 530 A SSL/TLS-connection is required for authentication. The Internet range requires TLS for authentication Set the client to STARTTLS, or use 465, 993, 995 once created Client hangs on connect, then times out Nothing: no session is created Implicit TLS expected on a STARTTLS port, or the reverse Match the port's connection security Repeated logon failures, then silence NO Too many invalid logon attempts. and a BYE Ten failures on one connection, the per-name lockout, or the per-IP auto-ban Access & abuse protection → Auto-ban Large attachment rejected 552 5.3.4 Message size exceeds fixed maximum message size The maximum message size, default 20480 KB Max message size, or the domain's own limit While diagnosing on Windows, look at Monitoring & troubleshooting → Live logs and Server status, which lists the listeners the service actually brought up. Per client: if Thunderbird offers "no encryption" it found a plain port, so fix the port, not the client. Where to read more Wiki: Connecting a Mail Client, Ports Reference, Encryption and Certificates, Sign-in and Identity. Documents: SecureDefaults.md, DevicesAndSessions.md. The public documentation: 7. Connecting a mail client, 7.2 Automatic client configuration, 22. Ports reference. On this forum: Let's Encrypt certificates are automatic, IMAP and POP3 on the server for shared mailboxes, when a saved setting takes effect, First install on Linux, Upgrading to 6.3.4 and the 6.3.4 announcement.
  • 0 Votes
    1 Posts
    145 Views
    ProgressiverobotP
    Written at 6.3.4, when no image was published. hMailServer 6.3.6 (6 October 2026) publishes the first: registry.gitlab.com/hmailserver/hmailserver:6.3.6, also tagged 6.3 and latest, one index over linux/amd64 and linux/arm64, signed with cosign as the release's pipeline; the Helm chart is a file of the release, and the packaging Compose file now runs PostgreSQL 18. See the 6.3.6 announcement and ContainerImage.md at the v6.3.6 tag. hMailServer 6.3.7 (17 October 2026), a security release, is registry.gitlab.com/hmailserver/hmailserver:6.3.7, for linux/amd64 and linux/arm64; in the container the update check names the image to pull and installs nothing, and the schema stays at 6108, so a container recreated on it from 6.3.6 changes no table. Its IMAP and POP3 listeners take the client's address from a PROXY protocol header, as the SMTP listener does, each from the peers on a list of its own, both off by default. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026), a security release, is registry.gitlab.com/hmailserver/hmailserver:6.3.8, and 6.3 and latest now name it; the schema stays at 6108. Its image carries MariaDB Connector/C, so HM_DB_TYPE=MySQL reaches a MariaDB server, where the images of 6.3.7 and earlier stopped at the first start, and its entrypoint secures a new installation at its first start by itself, whatever the container's command, so the run by hand below is left for a database its --create-database made more than a day before. The Helm charts of 6.3.6 and 6.3.7 never started a pod; 6.3.8's runs it as 999:999, fills new volumes in an init container and leaves database.port to the type's own port. Move a release of the older chart with helm repo update, helm upgrade <release> hmailserver/hmailserver --reset-then-reuse-values (Helm 3.14 or later) and then kubectl delete pod <release>-hmailserver-0, since the StatefulSet never replaces the stuck pod by itself (--reuse-values would keep the old chart's fsGroup 1000 and database.port 5432); where a cluster's policy refuses every sysctl, set unprivilegedPortsSysctl: false. For a Compose deployment made from an earlier Compose file, keep its HM_REST_CERTIFICATE_FILE, HM_REST_PRIVATE_KEY_FILE and ./certs mount in the new file, the key readable by 999, or its REST API does not start. See the 6.3.8 announcement. The Linux server is also a container image: the x86-64 .deb installed on Ubuntu 24.04 and run as the hmailserver user, with the database connection, the REST listener, the administrator password and, since 6.3.4, every other setting taken from the environment at start. This topic describes the image, the Compose file and the Helm chart as they are in the tree at the v6.3.4 tag, and the HM_* variables the entrypoint reads. The one thing to know first, from the 6.3.4 changelog: no container image of 6.3.4 is published. The images published on ghcr.io/progressiverobot/hmailserver before GitHub's suspension answer 404, and registry.gitlab.com/progressiverobot/hmailserver, which the Compose file and the chart now name, holds nothing. Meanwhile, build the image from the release's .deb and use your own tag wherever the files say registry.gitlab.com/.... What a Linux server is and is not is in hMailServer on Linux. Building the image yourself Use the docker directory of the same tag as the package: 6.3.4's entrypoint runs verbs a 6.3.3 binary does not have. git clone https://gitlab.com/hmailserver/hmailserver.git cd hmailserver git checkout v6.3.4 cd hmailserver/source/Server/platform/packaging/docker mkdir packages curl -L -o packages/hmailserver_6.3.4_amd64.deb \ https://gitlab.com/hmailserver/hmailserver/-/releases/v6.3.4/downloads/hmailserver_amd64.deb docker build -t hmailserver:6.3.4 . The Dockerfile copies packages/hmailserver_*_amd64.deb (the HM_DEB build argument names another path) and pins its Ubuntu base by digest. 6.3.4's package carries no Sigstore bundle to check it against, as 6.3.3's did. The image is x86-64 only: the Dockerfile takes the amd64 package. What is in the image, and what is not In: /usr/bin/hmailserver, the packaged hMailServer.ini at /etc/hmailserver/, the database scripts, the Control Deck, the fail2ban filter and jail the package carries, ca-certificates for the TLS the server does as a client, and an entrypoint. About 40 MB. The process runs as hmailserver; ports below 1024 are bound through cap_net_bind_service on the binary, not through root. Since 6.3.4 the Dockerfile installs the package's two Recommends, 7zip and python3: without them a backup failed with "Could not add the backup settings to the archive", and hmctl had no Python 3. Not in: the database, and it never will be. Point the image at a PostgreSQL or MariaDB server, in another container or anywhere else; on first start the entrypoint creates the schema there, and on every later start upgrades it if it is behind. Also not in: curl, an editor, or a shell of any consequence beyond bash. There is no Control Panel and no COM; the REST API is the administration. The variables the entrypoint reads itself Sixteen of these are older than 6.3.4 and keep their names and meanings. Variable Writes Notes HM_DB_TYPE [Database] Type PostgreSQL or MySQL (MariaDB is MySQL). Setting this is what makes the section be written at all HM_DB_HOST, HM_DB_PORT Server, Port Defaults db, and the type's port (5432 or 3306) HM_DB_NAME, HM_DB_USER, HM_DB_PASSWORD Database, Username, Password Defaults hmailserver, hmailserver, empty. The user needs the right to create the database on first start HM_DB_TLS_MODE, HM_DB_TLS_CA TlsMode, TlsCaFile Since 6.3.4. disable, prefer (empty, the default), require or verify-full, and the path of a PEM file of CA certificates mounted into the container HM_ADMIN_PASSWORD [Security] AdministratorPassword Through the server's own --set-admin-password: the file holds a PBKDF2 hash, never the password. Without one the REST API refuses to start HM_REST_PORT RestApiPort The packaged file has 0, which is off; 8045 is the conventional port HM_REST_BIND_ADDRESS RestApiBindAddress The packaged file has 127.0.0.1, which inside a container is the container's own loopback HM_REST_CERTIFICATE_FILE, HM_REST_PRIVATE_KEY_FILE RestApiCertificateFile, RestApiPrivateKeyFile Paths inside the container, readable by the hmailserver user. Paths the server reads, not _FILE forms HM_DB_PASSWORD_FILE, HM_ADMIN_PASSWORD_FILE the same two secrets Read from a file: a Docker or Compose secret. Setting both a variable and its _FILE is refused HM_CREATE_DATABASE, HM_UPGRADE_DATABASE nothing 0 skips --create-database or --upgrade-database at start. Both are no-ops when there is nothing to do HM_INI which file is written Default /etc/hmailserver/hMailServer.ini HM_PROFILE, HM_PROFILE_CONFIRM nothing Since 6.3.4: the setting profile applied once, and its confirmation On 6.3.3 and earlier the entrypoint writes these into hMailServer.ini on every start, and every other setting is the packaged file in the /etc/hmailserver volume. Since 6.3.4 the database is the settings store, so the four HM_REST_* variables are aliases of HM_SETTING_RestApiPort and its three neighbours, stored like any other setting; [Database] is still written into the file at every start, because it says where the database is. The image's /etc/hmailserver is owned by the hmailserver user, so there, unlike on a package installation, the server keeps its copy of each stored value in the file, and a --create-database that creates the schema also makes the stored-secrets key. Every setting from the environment (since 6.3.4) After --create-database and --upgrade-database, and before the server, the entrypoint runs the server's own verb, hmailserver --apply-environment, whenever there is anything for it to do. HM_SETTING_<key> sets a [Settings] key and HM_PROPERTY_<name> a database setting (HM_SETTING_MaxSubmissionsPerIPPerMinute=30, HM_PROPERTY_maxmessagesize=20480), and either with _FILE reads the value from a file, a Compose secret or a Kubernetes Secret mounted as one. The environment wins, at every start. An administrator cannot change a setting the environment names until the variable is unset and the container restarted, and a ConfigMap change, too, is applied by a restart and not live. Everything is checked before anything is stored. When anything is refused, nothing is stored and the container does not start; docker compose logs or kubectl logs says which variable and why. The naming rule, every refusal, what the REST API and the Control Deck show for a setting the environment manages, and how a value from a file stays secret are in configuration from the environment. HM_PROFILE names one of the four setting profiles, office, gateway, relay or sender, which the entrypoint applies once, with --apply-profile NAME --once, after the environment's settings and before the server starts. HM_PROFILE=none records that none is wanted. A profile that closes a listener, trusts an address range, turns a filter or a check off or weakens it, or shortens a window of days needs HM_PROFILE_CONFIRM=yes, and without it the container does not start. A profile skips a setting the environment manages, naming its variable. Not yet run in a container. The verb has been run as hMailServer.exe --apply-environment on Windows, and its POSIX half compiles; the entrypoint as a whole, the POSIX verb against a database, the chart and the Compose file have been read and not executed. HM_PROFILE is in the same state. Try it on a scratch database first. Reaching the API The server requires TLS on a REST listener that is not bound to loopback. A listener left at the packaged bind address answers only processes inside the container, which is none, since the image carries no client. Two ways out; either will do: Bind it and give it a certificate. HM_REST_BIND_ADDRESS=0.0.0.0, with HM_REST_CERTIFICATE_FILE and HM_REST_PRIVATE_KEY_FILE pointing at a certificate and key mounted into the container, and the port published. Publish it on the host's loopback (127.0.0.1:8045:8045) unless the certificate is one clients will trust. Host networking (--network host). The container's 127.0.0.1 is the host's, the packaged bind address is right as it is, no certificate is needed, and the API is at http://127.0.0.1:8045 from the host and through an SSH tunnel from elsewhere. The mail ports are then the host's ports directly. First start, with Compose The file to use is in the repository, at hmailserver/source/Server/platform/packaging/docker/docker-compose.yml. It reads the two passwords as Compose secrets from files, mounts the REST certificate and key in, and carries the HM_SETTING_ and HM_PROPERTY_ examples commented out. A workflow resolved it with docker compose config on every change until 18 September 2026, so it is known to parse. Below is the mail service of the wiki's shorter example, which puts it under services: beside a postgres:16 service named db and declares the named volumes. It names the image built above, not the empty registry: mail: image: hmailserver:6.3.4 depends_on: - db environment: HM_DB_TYPE: PostgreSQL HM_DB_HOST: db HM_DB_NAME: hmailserver HM_DB_USER: hmailserver HM_DB_PASSWORD: change-me HM_ADMIN_PASSWORD: change-me-too HM_REST_PORT: 8045 HM_REST_BIND_ADDRESS: 0.0.0.0 HM_REST_CERTIFICATE_FILE: /certs/rest.pem HM_REST_PRIVATE_KEY_FILE: /certs/rest.key volumes: - ./certs:/certs:ro - hm-data:/var/lib/hmailserver - hm-logs:/var/log/hmailserver - hm-etc:/etc/hmailserver ports: - "25:25" - "587:587" - "993:993" - "127.0.0.1:8045:8045" restart: unless-stopped restart: unless-stopped matters on the first start: depends_on starts the database container first but does not wait for it to accept connections, so the entrypoint's --create-database fails and the container exits if the database is not there yet; the restart tries again a moment later. The first start logs the [Database] section written, the administrator password hashed and the database created at schema 6104, and also what --create-database did about the stored-secrets key and one line per HM_SETTING_ or HM_PROPERTY_ variable stored. The first domain is then one request away (First install on Linux). Passwords in a Compose file are passwords in a file: for anything beyond a first look, use HM_DB_PASSWORD_FILE and HM_ADMIN_PASSWORD_FILE with Compose secrets. The secure defaults of a new installation are not applied in a container by themselves. On a package installation the systemd unit's first start gives a database --create-database made a self-signed certificate, STARTTLS and TLS required for authentication on the Internet IP range. The image has no unit, so that step is run by hand, as the service's user, with the server stopped. SecureDefaults.md gives the verb and no container command for it, and lists its refusal of a running service (exit 4) for Windows only: hmailserver --apply-new-install-defaults A run by hand has no one-day deadline, so an image first booted days after its --create-database is secured this way. What it changes, its exit codes and the checklist item that says what is left are in Hardening a public mail server. Kubernetes, with the chart Since 6.3.4 the chart is at hmailserver/source/Server/platform/packaging/helm/hmailserver. It is not published to a chart repository; install it from a checkout. It renders a StatefulSet of one, because a message store is not something two pods may share: the three volumes the image declares become claim templates, and the database is pointed at, never bundled. The chart refuses to render without database.host. Its image.repository names the empty registry, so set it to the image you built, pushed to a registry the cluster's nodes can pull from: helm install mail ./hmailserver \ --set image.repository=<your registry>/hmailserver \ --set database.host=postgres.databases.svc.cluster.local \ --set database.password=... \ --set administrator.password=... \ --set rest.tlsSecretName=mail-tls Value What it is image.repository registry.gitlab.com/progressiverobot/hmailserver as shipped, which holds no image: set it to where you pushed the image you built database.host, .type, .name, .user The PostgreSQL or MariaDB the server uses; required. database.create and database.upgrade make the schema on first start and move it forward on an upgrade database.password, administrator.password Go into a Secret the chart makes. Point existingSecret at a Secret you made and the chart writes none; its two keys are named by existingSecretKeys rest.enabled, .port, .tlsSecretName The one listener that serves the REST API, the Control Deck and the webmail. Off loopback the server requires TLS, so without a kubernetes.io/tls Secret named here the listener will not start; the chart's notes say so on install settings, properties, settingsFrom Since 6.3.4: any [Settings] key (rendered as HM_SETTING_<key>), any database setting (HM_PROPERTY_<name>), and a key of a Secret you made, projected into /run/secrets/hmailserver-settings/<n> and named through _FILE, so a secret value is in no environment variable, rendered manifest or log line service.type, .ports, .externalTrafficPolicy A LoadBalancer with the mail ports, and the REST port when the listener is on. Local keeps the client's address, which auto-ban, greylisting and the Received header all need persistence.* The message store, the logs and the configuration, one claim each Probes Port 25, as the image's own health check is, or the metrics listener's /livez and /readyz when that listener is on settings, properties and settingsFrom look like this in a values file; a settingsFrom entry says setting: in place of property: for a [Settings] key: settings: MaxSubmissionsPerIPPerMinute: "30" properties: maxmessagesize: "20480" settingsFrom: - secretName: mail-relay key: password property: smtprelayerpassword A switch is 1 or 0 for a [Settings] key; true, false, yes, no, on and off are taken as well for a setting whose REST settings row is a switch, and only there: maxmessagesize=off is refused rather than stored as 0, which is "no limit". Volumes, ports and the health check Path What lives there /var/lib/hmailserver The mail store, and .hmailserver-secret-key, the key under which this machine's stored secrets are protected. The key travels with this directory: a database restored beside a fresh data volume cannot open the secrets it holds /var/log/hmailserver The logs. Bind-mount it to a host path if fail2ban on the host is to read it /etc/hmailserver hMailServer.ini; since 6.3.4 the only home of PasswordPepper and [Security] StoredSecretsKey, which no database and no backup holds The image exposes 25, 110, 143, 465, 587, 993, 995, 4190 (ManageSieve) and 8045; publish the ones you serve. The health check opens a connection to the container's own port 25 every 30 seconds after a 60-second start period, and three failures in a row mark the container unhealthy. Upgrades, backups and auto-ban Upgrading is building the image of the new tag, as no 6.3.4 image is published to pull, and recreating the container: the entrypoint runs --upgrade-database on every start, so a schema that is behind is brought forward before the server opens a port. On MySQL and MariaDB the 6102 step rebuilds every table as utf8mb4, which takes time on a large database and needs the database server version that Databases on Linux gives. An upgraded database gets no stored-secrets key until one is made with hmailserver --create-stored-secrets-key, and never the new installation's defaults. Take the backup first (Upgrading to 6.3.4). Backups are three things together: the database, the /var/lib/hmailserver volume, and /etc/hmailserver. Two things are only in /etc/hmailserver/hMailServer.ini: a PasswordPepper, if one is set, without which a restored database refuses the password of every account hashed with Argon2id or scrypt, and the stored-secrets key, without which a restored database opens no account's second factor and no [Settings] secret. Export the key once, and keep the file with the database backups, apart from them: docker exec <container> hmailserver --export-stored-secrets-key /var/lib/hmailserver/stored-secrets.key docker cp <container>:/var/lib/hmailserver/stored-secrets.key ./stored-secrets.key A replacement container takes it back with --import-stored-secrets-key FILE. Auto-ban works as everywhere: an address that fails to log on repeatedly is refused by the listeners. The hook that adds the address to the host's firewall cannot run from inside a container, so run fail2ban on the host instead: bind-mount /var/log/hmailserver, copy the filter and jail out of the image, point the jail's logpath at the mounted directory, and enable it. What was proven, and what has not been Until 18 September 2026 the image job of the GitHub workflow built the image on every release tag, pushed it, and smoke-tested the pushed image as the example above runs it: the container healthy, the SMTP banner and the API answering, and the administrator password in no file in clear. Nothing has run it since. GitLab CI's linux-image job is written to build the image from the .deb with kaniko and inspect it; it neither pushes nor runs the image, so the smoke test has no replacement yet. The chart-and-compose job is written to lint and render the chart and resolve the Compose file. Neither had run when ContinuousIntegration.md was written, on 25 September 2026. The changelog's 6.3.4 section records the first full pipeline the day after: it finished failed, the image job among those that passed, and no pipeline has run on the fixed tree since. 6.3.4 was made by hand. Where to read more Running in a Container and Profiles and Environment on the wiki. EnvironmentConfiguration.md for the naming rule and every refusal, Profiles.md for every entry of the four profiles, SecureDefaults.md for the verb run by hand, and DatabaseTls.md for HM_DB_TLS_MODE. The 6.3.4 section of CHANGELOG.md for the state of the image. On this forum: the 6.3.4 announcement, hMailServer on Linux, First install on Linux and Upgrading to 6.3.4; configuration from the environment for HM_SETTING_ and HM_PROPERTY_ in full, and the hmailserver command line on Linux for the verbs the entrypoint runs.
  • 0 Votes
    1 Posts
    125 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.6 (6 October 2026) carries Linux packages for x86-64 and AArch64 and one for each of ten distribution releases, both AppImages, an ARM64 Windows installer (a preview) and the first container image. See the 6.3.6 announcement. hMailServer 6.3.7 (17 October 2026) is a security release: mail from outside whose From names a domain hosted here is no longer signed with that domain's DKIM key, an authenticated submission is signed as another hosted domain only when its account may send as the address its From names, and a forward of outside mail is given an envelope sender in the forwarding domain's organisation only when the message passed DMARC for it on arrival. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026), the current release, is a security release: it fixes vulnerabilities the project found in its own code, so upgrade every server running 6.3.7 or earlier. See the 6.3.8 announcement. This tutorial is for someone who has not run a mail server before. It follows a message from one person to another, shows where hMailServer sits on that journey, and says what the software does and does not do. The one thing to know first: port 25 has no password, and it has to be that way. Any server on the internet may connect to your port 25 and offer you mail for your own domains, or nobody could write to you. Your own users send through a different door, port 587, which requires a login. Most of what follows is about keeping those two doors apart. What hMailServer is hMailServer is a mail server: the software that owns an email domain. When someone sends a message to [email protected], their mail server looks up where yourcompany.com receives mail and delivers it to whatever is listening there. If you run hMailServer, that is your machine. Progressive Robot Ltd forked hMailServer in 2026 and maintains the hMailServer 6 line; the current release is 6.3.8, of 2 November 2026. Job Protocol What it means Accept mail from the world SMTP Other mail servers connect and hand you messages for your users Let your users read mail IMAP and POP3 Outlook, Thunderbird, Apple Mail and phones connect to fetch messages Let your users send mail SMTP submission Your users hand you messages and you deliver them onward Where it sits, and what is not yours Running your own mail server means owning the middle of three boxes. DNS is your registrar's, and the mail clients are your users'. The wiki puts it plainly: almost every problem people describe as "hMailServer is broken" turns out to be in one of the two boxes it does not own. You provide hMailServer provides A machine reachable from the internet The SMTP, IMAP and POP3 servers, and the whole delivery pipeline A host name with an A record, and an MX record pointing at it The MTA-STS policy derived from that MX, and a live check of every record A PTR record, which only your ISP can set Nothing can substitute for it SPF, DKIM and DMARC records in your zone The DKIM key generation with a copyable record, the signing, and the inbound evaluation of everyone else's Port 25 reachable inbound, and outbound (many consumer ISPs block outbound 25) Nothing can work around a blocked port; a smart host is the usual answer A certificate, or nothing, and let ACME get one Built-in Let's Encrypt issuance and hourly renewal Somebody who will read a log occasionally The logs, the diagnostics, the message trace and the metrics to read A message's journey You send mail to [email protected]. This is what happens: Your mail client submits the message to your hMailServer on port 587. You log in first. hMailServer answers 250 Queued. It asks DNS who receives mail for example.com. The MX record answers: mail.example.com. It looks up the A and AAAA records for that host, plus TLSA and the MTA-STS policy. It delivers the message by SMTP on port 25: no login, TLS if offered. The recipient's server answers 250 OK and stores the message in Alice's mailbox. Alice's mail client reads it over IMAP. An open relay is the thing to avoid. Never let an unauthenticated stranger send mail through you to the outside world. The wiki's warning is that it will get your server blacklisted within hours. hMailServer refuses this by default. A note on ports. A fresh install seeds ports 25, 587, 110 and 143. The TLS ports 465, 993 and 995 exist only after you create them on the TCP/IP ports page. A submission, and the checks in the order the server runs them The order matters, because it decides when a sender is told no: before the message body is transferred, or after. Stage What is checked Reply when it fails Any command On a STARTTLS required port, everything but NOOP, EHLO, STARTTLS and QUIT 530 Must issue STARTTLS first. MAIL FROM Free disk space: MinimumFreeDiskSpaceMB, default 100 452 4.3.1 Insufficient system storage MAIL FROM Send-As, only when SmtpAuthenticatedSenderCheck=1 (default 0) 550 5.7.1 Sender address rejected MAIL FROM Per-IP rate: MaxSubmissionsPerIPPerMinute (default 0, unlimited) 421 Too many messages from your IP address MAIL FROM Declared SIZE against the domain's maximum message size (default 20480 KB) 552 5.3.4 Message size exceeds fixed maximum message size RCPT TO Is the address deliverable at all? 550 Unknown user, or 451 4.3.2 Unable to verify the recipient at the moment RCPT TO Mailbox full 452 4.2.2 RCPT TO Relay permission for this IP range 550 Delivery is not allowed to this address. RCPT TO Authentication required and not supplied 530 SMTP authentication is required. RCPT TO Greylisting, when it is on (default off) 451 Please try again later. end of data Actual size, bare LF check, post-transmission spam tests 552 5.3.4, 554 5.6.0 Rejected - Message containing bare LF's, 554 5.7.1 4xx and 5xx. A 4xx reply always means "come back later", while a 5xx means "never". The difference decides whether a legitimate sender's message waits in their queue or is destroyed, which is why a full mailbox is 452 and not 550. Refusing early. Every check at MAIL FROM and RCPT TO happens before a single byte of the message crosses the wire. Refusing early costs the sender nothing, and it generates no bounce to an address a spammer only claimed to be. The timing in the last reply is real. A submission ends with a line such as 250 2.0.0 Queued (0.412 seconds): the server times the accept-and-save stage and reports it. A number that climbs into whole seconds is the first sign of a slow spam test, a stalled virus scanner or a saturated work queue. Since 6.3.4 the same session has more places to say no, each of them off until an administrator sets it: country blocking, a domain white and black list, restricted delivery, mail flow rules and others. One thing differs without a switch, and only on a new installation, not an upgrade: the Internet IP range requires TLS for authentication, so from another machine AUTH is not offered before STARTTLS. Who may send through you This is the decision that separates a mail server from an open relay, and hMailServer makes it per IP range. Mail from other domains to yours is taken on port 25 without a password, or nobody could write to you. From the Internet range, mail that gives one of your own domains as its sender needs a login, whoever it is for, and relaying from one remote address to another is allowed on both shipped ranges only with authentication: a stranger who has not logged in is answered 530 SMTP authentication is required. A range that allows relaying without authentication must never exist (the Control Panel's status page warns of one as an open relay). Ranges are matched by priority, highest first, so a narrow range for your own network can sit in front of the broad Internet range; IP ranges, auto-ban, lockout and the rest has the whole grid and the shipped values. After "250 Queued": the delivery pipeline Acceptance and delivery are separate. The 250 means the message is on disk and in the database; delivery happens on the delivery threads afterwards, in this order: The OnDeliveryStart script event. Virus scanning. Global rules. The OnDeliverMessage script event. DKIM signing, then mirroring, each on the first attempt only. Local delivery: account rules, Sieve, forwarding, distribution lists, public folders. External delivery for any recipient outside this server: routes or an MX lookup, MTA-STS, DANE, TLS, then SMTP. A temporary failure is rescheduled: 4 tries, 60 minutes apart by default. A permanent failure, or retries exhausted, produces a delivery status notification to the sender. Where the filters sit Anti-spam runs in two phases, before and after the message is transmitted, and a test's phase is fixed by the test. Two thresholds decide what a score means: mark (default 5) adds spam headers, and delete (default 20) refuses the message, or quarantines it when the quarantine is on. On a fresh install almost every test is off. zen.spamhaus.org, bl.spamcop.net and multi.surbl.org are seeded but inactive; the HELO, PTR, MX and SPF tests are off; SpamAssassin is off; greylisting is off. DMARC is on (ASDMARCEnabled 1), and it evaluates SPF and DKIM itself for its own purposes. Anti-spam does not run at all for an authenticated session, for a whitelisted sender, or for an IP range with spam protection switched off. Reading mail back: IMAP or POP3 IMAP POP3 Mail lives on the server on one device Folders yes, and shared/public folders too INBOX only Read/unread, flags shared across devices per device New-mail notification IDLE pushes it polling only Server-side search yes no Concurrent sessions many one at a time; a second gets -ERR [IN-USE] Default ports here 143, and 993 once you create it 110, and 995 once you create it The wiki's advice is short: use IMAP. The three records that make mail arrive SPF: a list of the servers allowed to send mail for your domain. DKIM: a cryptographic signature proving the message really came from you and was not altered. DMARC: a policy saying what to do when SPF and DKIM disagree, and where to send reports. Without them your mail will go to spam. The wiki calls this the most common reason a new mail server "doesn't work". Note the asymmetry: hMailServer signs your outgoing mail with DKIM as soon as you configure a key, but checking SPF on incoming mail is off by default. Being trusted by the servers you send to has the detail. What hMailServer is not It was not a webmail client; since 6.3.2 it is one. The page at /portal on the REST listener became a mail client in 6.3.2, and a separate webmail such as Roundcube is no longer needed, though it still works over IMAP. Of 6.3.4's paging of a folder of a hundred thousand messages, the wiki says: built, and not yet measured. See The webmail portal at /portal. It is not a spam filter you can point at someone else's mail. It filters mail it receives, for domains it hosts. It is not Exchange. There is no ActiveSync, no MAPI and no Teams integration, so Outlook connects over IMAP and SMTP like any other client. Since 6.3.4 it carries the pieces of groupware that ride on standards, such as calendars over CalDAV. Who should run it: a small business that wants its own mail on its own server; a developer who needs a real SMTP/IMAP endpoint for testing; a hosting provider running mail for many domains. Who should not: if nobody in your organisation is comfortable editing DNS records and watching a log file occasionally, a hosted mailbox provider will serve you better. What you run it on Windows Linux Platform 64-bit Windows 10 1607 / Server 2016 or later Since 6.3.0. 6.3.4's packages are x86-64 only: a .deb for Ubuntu 26.04 and 24.04, an .rpm for Fedora 43 and 44 and Enterprise Linux 10 Administration The Control Panel, the COM API, the Control Deck and the REST API The Control Deck and the REST API. The Control Panel and the COM API are Windows-only Event scripts VBScript or JScript JavaScript, since 6.3.4 The AArch64 packages and the AppImage were last published with 6.3.3. 6.3.4 is installed by hand; no live update installs it. hMailServer on Linux: what you get and what you do not and First install on Linux go further. "Additive and off by default" The design rule is that an existing installation upgrades without behaving differently until you turn something on. Category State on a fresh install Optional listeners: the REST API and /portal, web services, metrics, ManageSieve Off. Each stays inert until its port setting is non-zero Optional features: quarantine, message trace, full-text index, archive Off Outbound transport security: MTA-STS, DANE, DNSSEC validation On (MtaStsEnabled, DaneEnforcementEnabled, DnssecValidationEnabled). Each can be switched off A new installation of 6.3.4, not an upgrade A self-signed certificate, STARTTLS offered on 25, 587, 110 and 143, TLS required for authentication from the Internet range: see Hardening a public mail server Since 6.3.4 the database is the settings store: a [Settings] line edited in hMailServer.ini is ignored in favour of the stored value, and put back where the service can write the file. Words you will meet Term Meaning MTA Mail Transfer Agent: a mail server that accepts and forwards messages. hMailServer is one MSA Message Submission Agent: the server your own users hand mail to, normally on port 587, normally with authentication MUA Mail User Agent: the mail client Relay Accepting a message for a domain you do not host and passing it on Smart host Another server you send all your outbound mail through, often your ISP's STARTTLS Upgrading a plaintext connection to an encrypted one, in-band Implicit TLS TLS from the first byte, no upgrade step: ports 465, 993, 995 Envelope vs header The MAIL FROM/RCPT TO addresses the servers use, versus the From:/To: a person reads. They need not match Deferral Holding a message for a later attempt after a temporary failure Backscatter Bounces sent to a forged sender address MX record The DNS record saying which server receives a domain's mail PTR record Reverse DNS: maps an IP back to a host name Where to read more Wiki: How Email Works, What hMailServer Is and Is Not and the Glossary. The public documentation: chapter 1, chapter 2 and the glossary. On this forum: Read this before you post and Where to post what; for the next steps, Your first domain and mailbox, and the DNS records your domain needs, Connecting a mail client, The anti-spam stack end to end and Every port hMailServer listens on.
  • 0 Votes
    1 Posts
    140 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.6 (6 October 2026) publishes the first container image, registry.gitlab.com/hmailserver/hmailserver:6.3.6; its installer exits 10 or 11 when a step after its files did not complete (it exited 0), and it makes the data, log, temp, database and event folders private to the administrators and the service. See the 6.3.6 announcement. hMailServer 6.3.7 (17 October 2026), a security release, publishes registry.gitlab.com/hmailserver/hmailserver:6.3.7 (also tagged 6.3 and latest); its Windows installers carry the .NET Desktop Runtime 10.0.13, installed only where no .NET 10 Desktop Runtime is installed at all, so an upgraded server keeps the one it had; at every installation and upgrade /ProtectFolders hardens the program folder, Bin and ControlPanel, since an installation in a folder that took its permissions from the root of a drive let any account that could sign in to the computer replace the programs (CVE-2026-107571): before upgrading one, follow ServiceAccount.md's steps, and where other accounts could sign in while it was so installed, reinstall into a new folder only the administrators may change, given to setup with /DIR=, since over an installation setup installs into the folder it finds; and setup waits ShutdownDrainSeconds plus 90 seconds for the service's stop, where it waited plus 30. Chocolatey and the apt and dnf repositories still publish nothing: no channel is live as 6.3.7 is made, and 6.3.7 is not on the Snap Store. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026), a security release, publishes registry.gitlab.com/hmailserver/hmailserver:6.3.8, now the image tagged 6.3 and latest, which reaches a MariaDB database, where the images of 6.3.7 and earlier carried PostgreSQL's client alone, and whose entrypoint takes the database and administrator passwords out of the environment before it runs any program; and its Helm chart starts a server, where the charts of 6.3.6 and 6.3.7 never started a pod. Its Windows setup ends with exit code 7 where another account than SYSTEM, the Administrators and TrustedInstaller controls the program folder, Bin or ControlPanel, or a folder or a link on the way to them, naming the icacls that deals with it; with exit code 12, and the service set not to start until setup runs again, where something is not as setup left it after the files; and with exit code 1 for an installation of the original hMailServer's 5.7, the reason in its /LOG and in hMailServer-setup-refused.txt in %TEMP%. Chocolatey's install now passes the installer /LOG, and that log records setup's command line, so give the administrator password in HM_ADMIN_PASSWORD, set in the elevated prompt, rather than with /adminpassword in --install-arguments. Once 6.3.8 is published, jobs started by hand send it to the Ubuntu PPA (add-apt-repository ppa:hmailserver/hmailserver), Fedora Copr (dnf copr enable progressiverobot/hmailserver), Docker Hub, Chocolatey (hmailserver-progressiverobot, listed once its moderators approve it), PyPI and the PowerShell Gallery; the signed apt and dnf repositories this topic describes are still not published (Channels.md). See the 6.3.8 announcement. This topic covers installing hMailServer 6.3.4 without a wizard: the Windows installer's silent switches and what a silent install does with the administrator password; where the winget and Chocolatey packages stand; the signed apt and dnf repositories and why they are not live; and, since 6.3.4, every setting from the environment and the four setting profiles, the two ways a deployment shapes a server before it starts. The one thing to know first: an unattended install leaves the administrator password unset unless you pass it, and 6.3.4 is installed by hand from the release page, because neither package manager carries it and no live update installs it (the 6.3.4 announcement). The Windows installer's switches The installer is Inno Setup, so it takes the standard switches and a few of its own. Switch Effect /SILENT No wizard; progress window only /VERYSILENT No wizard and no progress window /SUPPRESSMSGBOXES Suppress message boxes; some failure paths still raise one without it /LOG="<path>" Write an install log; it is the only record of what happened /DIR="<path>" Installation directory /COMPONENTS="server,admintools,controlpanel" server is the service; admintools registers the COM type library; controlpanel installs the Control Panel, which does not need admintools /adminpassword=<password> Custom: sets the administrator password (at least 5 characters) and hands it to the database tools /upgradetoken=<hex> Custom: the single-use token of a live update; not for people to type /useinternaldbms=true\|false Custom: true (the default) uses the bundled SQL Server Compact database /serviceaccount=virtual\|localsystem\|keep Custom: virtual is NT SERVICE\hMailServer, the default for a new installation; keep is the default for an upgrade /profile=NAME Custom, since 6.3.4: the setting profile a new installation applies, or none. Written and read, and not run (below) hMailServer-x.y.z-x64.exe /VERYSILENT /SUPPRESSMSGBOXES /LOG="C:\Temp\hmail-install.log" ^ /COMPONENTS="server,controlpanel" /useinternaldbms=true Treat a non-zero exit code as a failed install and read the log. The installer checks both that the database tool launched and its exit code, so a failed or cancelled schema step fails the install rather than passing silently. The log has the tool's code: from DBSetupQuick.exe, 0 is a database created or already up to date, 1 a failed create or a DBUpdater.exe that would not start, 3 a wrong or missing administrator password, and any other DBUpdater.exe's own code. A hm_dbversion still on the old value afterwards is the same failure. A silent installation does not approve folders or key files the configuration names outside the program folder, and leaves such a service on LocalSystem rather than moving it to the virtual account. The administrator password, silently A fresh silent install leaves the administrator password unset unless you pass /adminpassword=<password> or set HM_ADMIN_PASSWORD: without either, the AdministratorPassword key is left out of hMailServer.ini entirely. Set it afterwards with hMailServer.exe --set-admin-password, new in 6.3.4, from an elevated prompt, then restart the service. It takes the password from HM_ADMIN_PASSWORD or, when that is not set, from one line of standard input when that is a pipe or a file, and never from an argument. Prefer the variable: a pipe from Windows PowerShell 5.1 turns every non-ASCII character into ?, storing a password nobody typed. On Linux the command is hmailserver --set-admin-password. ServiceAccount.md and Upgrading.md write the Windows step as hMailServer.exe /SetAdministratorPassword. The Control Panel and COM are refused under the virtual account. A new 6.3.4 installation runs the service as NT SERVICE\hMailServer by default, and under that account hMailServer.ini is read-only to the service: the Control Panel's Administrator password card and COM's Settings.SetAdministratorPassword are each refused with a sentence. They set the password only where the service may write the file, as it may under LocalSystem, which an upgrade keeps unless it is answered otherwise. A silent upgrade of an installation that has a password still needs it for the database upgrade, and cannot prompt. Without it the database upgrade fails and the installer reports a non-zero exit code rather than waiting. With the password empty, a silent upgrade works. Since 6.3.4, HM_ADMIN_PASSWORD is the safer of the two. Inno Setup drops every double quote from its command line, so /adminpassword=ab"cd sets abcd, and anybody listing processes while setup runs can read the switch. The variable takes any character. Setup reads it only when neither /adminpassword= nor /upgradetoken= is given. Set the variable in an elevated prompt. Setup started without administrator rights elevates itself through the UAC prompt, and the variable does not cross it. Until 6.3.4 the password went unquoted on the database tools' command lines, so one with a space, a double quote or backslashes before one failed the database step with exit code 3. It now goes in HM_ADMIN_PASSWORD. winget and Chocolatey: not in the public repositories yet The manifests exist and are validated for each release, from the release's own Authenticode-signed installer. They are not in the public repositories: neither winget install ProgressiveRobot.hMailServer nor choco install hmailserver installs this fork until a first submission has been reviewed and merged. Do not run choco install hmailserver expecting this fork. PackageManagers.md records none on 15 September 2026, but on 27 September 2026 the community feed held an unlisted hmailserver package: the original project's 5.6.8, not this fork's. What the packages are built to do, once accepted: Both run the signed installer the release page offers with /VERYSILENT /SUPPRESSMSGBOXES /NORESTART. /SUPPRESSMSGBOXES is not optional: without it a database-setup failure shows a message box, silent mode answers it with the default button, and a broken install reports success. /TYPE=full is deliberately not passed, so an upgrade keeps the components already installed and does not put the Control Panel back on a server where it was left out. MinimumOSVersion: 10.0.14393.0 is Windows 10 1607, the floor of the .NET 10 Desktop Runtime the Control Panel needs. The administrator password is left unset, and neither package invents one. Set one before the server is reachable from anywhere but the machine itself. Uninstalling runs the installer's own uninstaller, which does not delete the message store, the database or hMailServer.ini. A pre-release is never submitted. apt and dnf on Linux: written, tested in a lab, not live The project keeps signed apt and dnf repositories on the update feed's site, https://updates.progressiverobot.com. They are not live. The job that makes them, package-repos, was tested on the lab machine on 26 September 2026 with a throwaway key and dummy packages, and publishes nothing until the owner has made the signing key. This is what a Debian or Ubuntu user will type once it is live; on a release with no suite, apt update answers 404 for its InRelease. sudo install -d -m 0755 /etc/apt/keyrings sudo curl -fsSLo /etc/apt/keyrings/hmailserver.asc https://updates.progressiverobot.com/hmailserver-repository-key.asc gpg --show-keys /etc/apt/keyrings/hmailserver.asc # compare the fingerprint with the one below echo "deb [signed-by=/etc/apt/keyrings/hmailserver.asc] https://updates.progressiverobot.com/apt $(. /etc/os-release && echo "$ID$VERSION_ID") main" \ | sudo tee /etc/apt/sources.list.d/hmailserver.list sudo apt update sudo apt install hmailserver The fingerprint does not exist yet: PackageManagers.md records it as (not made yet). There is no dnf repository at all until a stable release carries .rpm files built for each distribution, and 6.3.4 carries the generic one alone. Once one does, on Fedora and Enterprise Linux it is sudo curl -fsSLo /etc/yum.repos.d/hmailserver.repo https://updates.progressiverobot.com/rpm/fc44/hmailserver.repo and then sudo dnf install hmailserver, with fc44 replaced by the release's directory. What 6.3.4 carries limits what the repositories could hold. Its Linux packages are one generic x86-64 .deb and one generic .rpm, neither built for one distribution; hMailServer on Linux: what you get and what you do not says where each installs. In the repositories as PackageManagers.md describes them, the .deb belongs in the ubuntu26.04 suite, and the .rpm, built on Ubuntu 26.04, goes in no repository. On 26 September 2026 dnf install of the .rpm built from master that day resolved its dependencies on Fedora 43 and 44 and AlmaLinux 10, and was refused on AlmaLinux 9, whose glibc and libstdc++ are older than it asks for. Packages built for each distribution come from the release after 6.3.4. The packages carry no RPM signature of their own: the signed repository metadata carries every package's SHA-256. Not tried: the job on GitLab's runners, HTTPS end to end, arm64 and aarch64. Until it is live, First install on Linux is the walk. Every setting from the environment Since 6.3.4. Every [Settings] key and every hm_settings row the server reads has a name in the environment. Variable Sets HM_SETTING_<key> The [Settings] key, one of 241: HM_SETTING_MaxSubmissionsPerIPPerMinute=30 HM_PROPERTY_<name> The hm_settings row: HM_PROPERTY_maxmessagesize=20480 HM_SETTING_<key>_FILE, HM_PROPERTY_<name>_FILE The same, read from the file the variable names, such as a Kubernetes or Compose Secret; UTF-8, at most 64 KB, trailing line breaks stripped The prefixes and _FILE are written in capitals; the name after the prefix is matched without regard to case, and a key is stored in its own spelling. What is refused, before anything is stored: a name that is not a setting of the store its prefix names (MaxMessageSize after HM_SETTING_ is refused naming HM_PROPERTY_maxmessagesize); a misspelt prefix such as HM_SETTINGS_; a read-only property such as WebPushVapidPublicKey; the plain and the _FILE form of one setting together; a _FILE naming a directory, a missing path or a file over 64 KB, refused naming the path, never the content; the _FILE form of a setting a domain or an account may hold its own value of; and a value the setting's own REST check would refuse, in that check's words. maxmessagesize=off is refused rather than stored as 0, which is "no limit". The verb. hmailserver --config /etc/hmailserver/hMailServer.ini --apply-environment hMailServer.exe --apply-environment on Windows is the same verb from the same code. It opens the configuration and the database as the service does, so run it as the user the service runs as. It checks every value first and exits 1 having changed nothing when any is refused, then writes each through the setter PUT /api/v1/settings/... uses and prints a line per variable: set, unchanged or refused. A secret's value is never printed. Exit 2 is a configuration file that names no database. The verb's writes are not rows in the audit trail: its own output, in a container the container's log, says what it changed. Who runs it. No container image of 6.3.4 is published: the image is one you build yourself, from the Dockerfile in the tree. Its entrypoint runs the verb after --create-database and --upgrade-database and before the server. On Windows nothing runs it for you: a Windows service has no environment of its own that anything sets, so the verb is there for a script or a deployment tool. Run beside a running server, its values reach that server at the next reinitialise (Apply now), or the next start for a key marked restart. The environment wins, every start. The server records the managed names in the hm_settings row EnvironmentManagedSettings and refuses an administrator's change to one of them. Where What happens REST A PUT that would change a managed key is 409, with a sentence naming the variable; GET /api/v1/settings/environment lists every managed setting with no value COM (Windows) Every setter refuses with the same sentence Control Deck Set by the environment beside the key, with its value and no control Control Panel (Windows) The same mark, with the field disabled hmctl hmctl config changed prints (set by the environment); hmctl config export leaves managed settings out Unset the variable and restart to manage the setting in the server again. A value a _FILE supplied stays withheld after the variable is gone: REST answers (set), the Control Panel leaves the field empty, and it is never on a command line or in a log. The environment sets the server level only, and the two [SendingLimits] keys have no environment name. The container's own variables are not settings: the database's HM_DB_*, TLS included; HM_ADMIN_PASSWORD and HM_ADMIN_PASSWORD_FILE; HM_INI; HM_CREATE_DATABASE and HM_UPGRADE_DATABASE; HM_PROFILE and HM_PROFILE_CONFIRM. The four REST ones are aliases: HM_REST_PORT stands for HM_SETTING_RestApiPort. The Helm chart takes settings, properties and settingsFrom. In a container or on Kubernetes has the table, the chart, and the stored-secrets key a first start makes, to export at once. What has not been run. The verb has been run as hMailServer.exe --apply-environment on Windows only. Its POSIX half compiles; the image's entrypoint as a whole, the POSIX verb against a database, the chart and the Compose file have not been executed. There is no live reload from a ConfigMap change: a restart applies it. Profiles: the shape a new server starts in Since 6.3.4. A profile is the thirty or so settings that make a server the kind it is, each with a reason written from what the setting's reader does. Four ship as reviewed documents; there is no route that makes one of your own. Profile For What you would notice office One server that receives an office's mail and holds its mailboxes SPF, the MX check, DKIM and DMARC scoring; greylisting; the quarantine; auto-ban and lockout; a password policy and the breach check (31 entries) gateway Behind a filtering gateway that has already judged the mail Greylisting off; XCLIENT and an ARC seal trusted only from the gateway and sealer you name (17 entries) relay An outbound relay that holds no mailbox anybody reads IMAP and POP3 closed at the next restart; hard bounces suppressed; the trace kept three months (24 entries) sender A high-volume sender judged on its bounce and complaint rates The relay's shape, more deliveries at once, the feedback loops, the trace kept six months (32 entries) Every surface shows a diff first, then saves what it replaces, then writes, all or nothing. An entry that closes a listener, trusts an address range, turns a filter off or weakens a check, or shortens a window of days asks for a confirmation. A profile never touches a port, a path, a bind address, the database connection, a password or any secret, an IP range, Incoming relays, a DNS block list, a listener's TLS or a domain's own settings. What only you know, such as the gateway's addresses, is a step listed under the diff. Revert puts back each value the profile replaced and leaves alone one an administrator changed since. It puts back settings, not data: where a profile shortened a window of days, what the sweep deleted under the shorter window stays deleted, and a listener a profile closed opens again only at the next restart. There is one snapshot: a second apply waits for the first to be reverted or discarded. Where a profile is chosen at install time: The Windows installer offers the four on a page of their own, after the administrator password and before the service-account page, for a new installation only, with "None" chosen until another is. No diff is shown there: each profile's sentence names the listener, filter or trust it changes, and choosing it is the confirmation, so relay and sender close IMAP and POP3 with no further question. After the database step it runs hMailServer.exe --apply-profile NAME --once --if-new --confirm before it starts the service. Silently, that is /profile=NAME. Every failure is said, and the installation still succeeds with the shipped settings. The container applies HM_PROFILE once, before the server starts; HM_PROFILE_CONFIRM=yes confirms an entry that asks, and HM_PROFILE=none records that no profile is wanted. The verb itself: hmailserver --apply-profile NAME [--confirm] [--once] [--if-new] hmailserver --revert-profile Exit Meaning 0 Done, or nothing to do 1 Refused or failed 2 No such profile, or no database 3 An entry needs --confirm 4 The service is running 5 --if-new, and the server is in service On Windows the verbs refuse while the service runs (exit 4). On Linux nothing says whether a server is running, so run them with the server stopped, as the container's entrypoint does. --if-new does nothing on a server of ten accounts or more. A setting the environment manages is skipped, with its variable named. Afterwards a profile is chosen in the Control Panel's Maintenance, Setting profiles (Windows), the Deck's Checklist, COM's Settings.ApplyProfile (Windows), REST or hmctl. Read the diff at GET /api/v1/settings/profiles/{name}, or with hmctl settings profile NAME, which prints a diff_token. Apply with {"confirm": true, "diff_token": ...} on POST /api/v1/settings/profiles/{name}/apply, or hmctl settings apply-profile NAME with --confirm TOKEN: a diff that has moved since it was read is refused (409) and nothing is written. The way back is POST /api/v1/settings/profiles/revert; POST /api/v1/settings/profiles/discard drops the snapshot. The installer page with its /profile=NAME switch, the container's HM_PROFILE and the Linux verbs have been written and read, and not run: the installer was not built and the Linux server not compiled for this change, and no container was started. What it does not do No package configures the server: no password, no domain, no firewall port. No export of the configuration as an environment. Four profiles, no parameters, no profile per domain. Where to read more The wiki pages: Profiles and Environment and Running in a Container winget, Chocolatey, apt and dnf: PackageManagers.md The naming rule and every refusal: EnvironmentConfiguration.md Every entry of the four profiles: Profiles.md The silent upgrade: Upgrading.md The documentation page: Run the installer On this forum: Upgrading to 6.3.4, Installing on Windows for the wizard's pages, and Behind a gateway for the gateway profile's steps.
  • 0 Votes
    1 Posts
    146 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026), a security release, has installers that carry the .NET Desktop Runtime 10.0.13 and install it only where no .NET 10 Desktop Runtime is installed at all; at every installation and upgrade /ProtectFolders hardens the program folder, Bin and ControlPanel, because in a folder that took its permissions from the root of a drive any account that could sign in to the computer could replace the programs the service runs (CVE-2026-107571; the default under Program Files was never affected); setup waits ShutdownDrainSeconds plus 90 seconds for the service's stop, where it waited plus 30; and the x64 installer's MySQL and MariaDB client is MariaDB Connector/C 3.4.11. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026) is the release to install today, a security release: a new server runs hMailServer-6.3.8-x64.exe, Authenticode-signed and with its Sigstore bundle beside it, and 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. Its setup makes or hardens the program folder, Bin and ControlPanel before it copies a file or runs a program of the installation, and ends with exit code 7 where another account than SYSTEM, the Administrators and TrustedInstaller controls one of them, a folder or a link on the way to them, or a program, library or script in them (step 2 below; the four narrower cases of work item 78 that 6.3.7's notes left open); and it refuses an installation of the original hMailServer's 5.7 before it changes anything. See the 6.3.8 announcement. This topic walks through a new installation of hMailServer 6.3.4 on Windows: what the installer checks before it shows a page, each page of the wizard, the two pages 6.3.4 adds (the setting profile and the service account), what runs after the files are copied, and the first hour after it. The one thing to know first: 6.3.4 is installed by hand on every server. It carries an Authenticode signature and no Sigstore bundle, so no server's live update installs it; you download the installer, check it and run it yourself. If you already run hMailServer, read Upgrading to 6.3.4 instead. Before you download The installer enforces a floor rather than advising one: MinVersion=10.0.14393 and ArchitecturesAllowed=x64. On anything older, or on 32-bit Windows, setup stops with "hMailServer requires Windows 10 version 1607 (build 14393) / Windows Server 2016 or later, 64-bit." It needs an administrator, because it creates a service and writes to HKLM. The .NET 10 Desktop Runtime, which the database tools need, is installed automatically when missing; 6.3.7's installers carry 10.0.13, Microsoft's security release of 13 October 2026, and install it only where no .NET 10 Desktop Runtime is installed at all, so an upgraded server keeps the one it had. RAM is guidance only: 2 GB minimum, and nothing enforces it. Decide four things first, because the wizard asks for them: The administrator password. At least five characters. It is the master password for the whole server, not an email password. The database. The wizard asks only "built-in or external". If in doubt take the built-in one; Choosing a database covers the rest. The kind of server it is (since 6.3.4): the setting profile, below. The account the service runs as (since 6.3.4): NT SERVICE\hMailServer, unless something it would need, such as a data or backup folder outside the program folder or SQL Server with Windows authentication on the same machine, is planned for first. Plan antivirus exclusions for Data\, Database\ and Temp\, and somewhere to keep the exported stored-secrets key, apart from the database backups. Getting the installer and checking it Get hMailServer-6.3.4-x64.exe from the latest release on GitLab, or from https://updates.progressiverobot.com/download/hMailServer-x64.exe. Both now give 6.3.8, the newest stable release: hMailServer-6.3.8-x64.exe, SHA-256 4b9b9c3102cbed743f6c826289c54cec25c395d02208e55cdd3219187fbf8654, with its .cosign.bundle beside it; 6.3.4's own files are on its release page. 6.3.4 carries no .cosign.bundle. It was built and Authenticode-signed by hand, after GitHub suspended the project's account on 18 September 2026 and before the project's GitLab CI signing job existed. Its SHA-256 sums are in a file signed with the release tags' SSH key: the 6.3.4 announcement has the two commands that check a download against it. Then check the installer's own signature: Get-AuthenticodeSignature .\hMailServer-6.3.4-x64.exe | Format-List Status, SignerCertificate Status must be Valid, and the signer's subject names Progressive Robot Ltd. SmartScreen still warns: expect Windows protected your PC with the publisher's real name on it. winget install hMailServer and choco install hmailserver do not install this fork (Unattended installs, winget and Chocolatey). What the installer checks before it shows a page Choose Run as administrator. InitializeSetup() runs first: Check Result /adminpassword, or HM_ADMIN_PASSWORD (since 6.3.4), shorter than 5 characters Setup stops A window titled hMailServer Control Panel, hMailServer Administrator, hMailServer Database Setup, hMailServer Database Upgrader or DBSetup is open Setup stops: "…You must close down this application before starting the installation." Ports 25, 110 or 143 in use while the hMailServer service is not running Warning only: "…This indicates that there already is an email server running on this computer." Ignore the port warning and two servers will fight over port 25. The wizard, page by page Licence agreement. hMailServer is AGPL-3.0. Destination folder. C:\Program Files\hMailServer is fine. Since 6.3.7 setup's /ProtectFolders hardens the program folder, Bin and ControlPanel at every installation and upgrade: in a folder that took its permissions from the root of a drive, any account that could sign in to the computer could replace the programs the service runs (CVE-2026-107571, every version from 6.0.0 to 6.3.6); the default folder under Program Files was never affected. Since 6.3.8 setup makes or hardens them before it copies a file or runs a program of the installation: one of them, a folder or a link on the way to them, or a program, library, script or settings file in them, that another account than SYSTEM, the Administrators and TrustedInstaller controls, and a program folder on a share or on a volume that keeps no permissions, end the installation with exit code 7, each named with the icacls that deals with it and, where setup says so, a restart of Windows before it runs again (ServiceAccount.md). Components. server is the mail server, the database tools and the DB scripts. controlpanel is the administration application; without it you have no GUI. admintools, Remote administration support, registers the COM type library on a machine that is not the server, for your own scripts; the Control Panel does not need it. Database type. Use the built-in database engine unless you decided otherwise. If you choose external, DBSetup.exe runs after the file copy and asks for the engine, host, database name and credentials. Skipped when [Database] Type is already set: an upgrade never re-asks. Start menu folder. Administrator password. Minimum five characters; the two boxes must match. Since 6.3.4 a space, a double quote or a backslash reaches the database step as typed: the installer has the server store the password as PBKDF2 and hands it to the database tools in the environment variable HM_ADMIN_PASSWORD, never on a command line. Set one. While the value is empty, COMAuthentication::AttempAnonymousAuthentication grants server-administrator rights to any COM caller and RestApiServer::Start refuses to start the REST API. Server profile (since 6.3.4), on a new installation only. Service account (since 6.3.4). Ready to install. Pressing Install stops an existing hMailServer service and waits ShutdownDrainSeconds + 30 seconds for it (since 6.3.7, ShutdownDrainSeconds plus 90). If it will not stop, setup refuses to go on: "The hMailServer service did not stop within 30 seconds." Stop it in services.msc and run setup again; do not work around this. Install. The setting profile page (since 6.3.4) A setting profile is the thirty or so settings that make a server a particular kind, named. The wizard offers four, with None (the shipped settings) chosen until you pick another: Profile For office One server that receives an office's mail, holds its mailboxes and sends what its people write: SPF, DKIM, DMARC and greylisting on, spam held in the quarantine, auto-ban and account lockout, a password policy and the breach check gateway A server behind a filtering gateway that has already judged the mail: greylisting off, and XCLIENT and an ARC seal trusted only from the addresses and the sealer you name; putting the gateway's addresses in Incoming relays is yours to do (Behind a gateway) relay An outbound relay that holds no mailbox anybody reads: IMAP and POP3 closed, hard bounces suppressed, deliveries throttled per destination, every message traced sender The relay's shape for a high-volume sender judged on its bounce and complaint rates After the database step the installer runs hMailServer.exe --apply-profile NAME --once --if-new --confirm; --if-new leaves alone a database that already holds ten accounts or more. Every failure is said, naming the profile as not applied, and the installation succeeds with the shipped settings. In the wizard no difference is shown: each profile's sentence names the listener, the filter or the trust it changes, and choosing it is the confirmation, so relay and sender close IMAP and POP3 with no further question. Chosen later, from the Control Panel's Setting profiles page or the Control Deck's checklist, a profile shows its difference from this server before it changes anything. Either way it saves what it replaces and can be put back. A profile never sets a port, a directory, a [Database] value, a password or an IP range's Require SSL/TLS when authenticating. One caution from Profiles.md: the installer page is among what it lists as "written and read, and not run", because "the installer was not built for this change". The service account page (since 6.3.4) Until 6.3.4 the Windows service ran as LocalSystem, so a flaw reachable through SMTP, IMAP or POP3 was a flaw with full control of the computer. A new installation now runs it as NT SERVICE\hMailServer, the service's own virtual account: no password, no account to create, and it reaches only the folders it is granted. The machine The page offers The default No hMailServer service yet NT SERVICE\hMailServer, or LocalSystem NT SERVICE\hMailServer A service running as LocalSystem keep LocalSystem, or move it keep LocalSystem A service running as any other account keep that account, or move it back to LocalSystem keep the account An upgrade never changes the account unless this page is answered to. What the account is granted, by hMailServer.exe /GrantServiceAccess: Modify on the program folder's own Data, Logs, Temp and Database; Read on its other folders; Modify on Bin\hMailServerApiKeys.ini; nothing on hMailServer.INI; and a folder the configuration names elsewhere only once an administrator approves it. An attended installation asks (--confirm). A silent one approves nothing: when the configuration names a folder or key file outside those folders, it leaves the service on LocalSystem, working, and says why. The folders and the certificate and key files the configuration names are checked against those grants and reported: NOT APPROVED, a folder nobody has approved; OUTSIDE, a certificate or key file, which is never given Read where it is (move it into Data\Certificates, or approve its folder for Read); REFUSED, a folder that may never be granted. A folder is approved with --approve-modify "<folder>" or --approve-read "<folder>", or by answering Yes to --confirm; approvals are kept in HKEY_LOCAL_MACHINE\SOFTWARE\hMailServer\ServiceAccessPaths, a key only Administrators and SYSTEM may change. Approve only a folder you recognise: the service may then write in it. Never granted, approved or not: anything not a full path on a fixed local drive; a drive's root; the program folder, a folder above it, or anything in it but its Data, Logs, Temp and Database; the Windows folder, a Program Files folder, the user profiles folder or ProgramData\Microsoft, or any folder in or above one of them; ProgramData or a folder above it (a folder of your own inside it may be approved); and any path through a junction, a symbolic link or a mount point. --report-only says what would be done and changes nothing. Exit codes: 0 every grant made and everything named reached, or confirmed, 1 a grant or an approval failed, 2 not in an installation's Bin, 3 not elevated, 4 something outside not confirmed, 5 a folder that is never granted is named, 6 answered No. What only LocalSystem could do is refused with a sentence: the live update's apply (the update is still checked; on 6.3.4 and 6.3.5 an administrator downloads the installer from the release page, checks its signature and runs it, and from 6.3.6 installs the verified update with Install update on the Control Panel's Server status page on the server, with one Windows prompt), the auto-ban's Windows Firewall rules (AutoBanFirewall, HM7460; banned addresses are still refused by the server) and Utilities.MakeDependent. SQL Server with integrated authentication on the same machine needs a login first: CREATE LOGIN [NT SERVICE\hMailServer] FROM WINDOWS, then a user with db_owner. MySQL, MariaDB and PostgreSQL use a user and password, and nothing changes. hMailServer.INI is read-only to the service. A change of the administrator password over COM or the Control Panel's Administrator password card is refused; make it from an elevated prompt in Bin with hMailServer.exe --set-admin-password, which takes the password from HM_ADMIN_PASSWORD or, failing that, from standard input, and restart the service (ServiceAccount.md writes it /SetAdministratorPassword). Enrolling the administrator's TOTP second factor needs an account that may write the file, so move the service to LocalSystem for the enrolment and back. To move a service that runs as LocalSystem, run the installer again and choose the move, use the Control Panel's Windows service account card under Server limits & expert settings, or, from an elevated prompt in Bin: hMailServer.exe --confirm /GrantServiceAccess hMailServer.exe --service-account virtual /Register net stop hMailServer && net start hMailServer running the second line only when the first ended in 0. To go back, run the installer again and choose Move it back to LocalSystem, use the same card, or run hMailServer.exe --service-account localsystem /Register and restart the service. ServiceAccount.md records that the live registration "is exercised by hand on a throwaway machine; nothing here registers a service on the bench". What runs after the files are copied # Step What runs If it fails 1 .NET 10 Desktop Runtime Only when missing; since 6.3.4 pinned to 10.0.12 by version and SHA-512; 6.3.7 carries 10.0.13 and installs it only where no .NET 10 Desktop Runtime is installed at all Error dialog; exit codes 0, 3010 and 1638 count as success 2 Database backend SSCERuntime_x64-ENU.msi, built-in engine only Step 4 is skipped 3 Create the service hMailServer.exe --service-account <choice> /Register; a service to be moved is registered as LocalSystem here Step 5 is skipped 3a Administrator password (since 6.3.4) hMailServer.exe --set-admin-password The install fails 4 Create the database DBSetupQuick.exe for the built-in engine, DBSetup.exe for an external one chosen for the first time The install fails, naming the exit code 4a Secure a new installation (since 6.3.4) hMailServer.exe --apply-new-install-defaults Said and logged; the installation succeeds 4b Apply the profile (since 6.3.4) --apply-profile, above Said; the shipped settings stay 4c Stored-secrets key (since 6.3.4) hMailServer.exe --create-stored-secrets-key Said, with the command to run by hand 4d Move the service (since 6.3.4) /GrantServiceAccess, and only when that ends in 0, --service-account virtual /Register The service stays on LocalSystem, working 5 Start the service net START hMailServer, the verdict taken from the SCM "The hMailServer service was installed but did not start." The database step runs while the service is still LocalSystem, because it writes [Database] into hMailServer.INI through the service, which the virtual account may not do. ServiceMain reports SERVICE_RUNNING before it connects to the database, so a running service proves the process started, not that the schema is usable; step 4's exit code covers the schema. What a new installation starts with (since 6.3.4) Step 4a runs hMailServer.exe --apply-new-install-defaults after the database step, before the server first listens, and only on a database this installation created: on one DBSetup.exe attached the verb exits 5, which the installer only logs, and the installation succeeds. On a created database, ports 25, 587, 110 and 143 offer STARTTLS with a self-signed certificate that mail clients warn about, and the Internet IP range requires TLS for authentication, so a client on another machine must start TLS before it signs in; an upgraded server is left as it was. What each default is, how to replace the certificate (Let's Encrypt certificates are automatic) and how to apply the defaults by hand are in Hardening a public mail server. The stored-secrets key (since 6.3.4) On a new installation step 4c makes the key that seals each account's TOTP second factor and the [Settings] secrets in the database. It is kept in this machine's hMailServer.INI alone, never in the database or a backup, and an upgrade makes none. Export it and keep the file with the database backups, stored apart from them: # elevated, in the Bin folder .\hMailServer.exe --export-stored-secrets-key D:\keys\hmailserver-stored-secrets.key A database restored without it opens none of those secrets. Hardening a public mail server covers the key in full: what it seals, other nodes, and a key that is lost. Confirm it is running, and open the firewall Get-Service hMailServer should say Running. On a new installation that kept the page's default, services.msc shows it logging on as NT SERVICE\hMailServer. sc.exe qfailure hMailServer shows the recovery the installer set: restarts after 60, 120 and 300 seconds, the counter reset after 86400. The installer does not open firewall ports. Until you do, nothing reaches the server. One rule per port, in an elevated PowerShell; for SMTP: New-NetFirewallRule -DisplayName "hMailServer SMTP" -Direction Inbound -Protocol TCP -LocalPort 25 -Action Allow Which ports to open, and which to leave closed, are in Every port hMailServer listens on. The first hour: the checklist and the sample domain Since 6.3.4 the server judges its own first hour. Twelve items, each done, action_needed, cannot_tell or not_needed: a profile, a domain, an account, TLS on the submission port, passwords only over TLS, an SPF record, DKIM signing, a DMARC record, a backup destination, a second factor for the administrator, the stored-secrets key and the account the server runs as. It is the Control Deck's Checklist view, the head of the Control Panel's External setup page, GET /api/v1/setup/checklist and COM's Utilities.GetSetupChecklist. A button on the Control Panel's Welcome page and on the Deck's checklist makes a throwaway sample domain, example.test, with three mailboxes, a list, a rule and eight delivered messages; a second removes it. The server mints one password for the three mailboxes and shows it once, in the answer that makes the sample; Your first domain and mailbox has the detail. Remove the sample before the server takes real mail. Silent installation A silent install answers the two 6.3.4 pages with /profile= and /serviceaccount=, and leaves the administrator password unset unless /adminpassword= or HM_ADMIN_PASSWORD gives it. Always check the exit code: a failed database create fails the install. The switches, the profiles and the password are in Unattended installs. What the installer wrote {app}\Bin\hMailServer.INI is the only configuration file. Since 6.3.4 the database is the settings store: the file keeps [Directories], [Database], [Security] and [GUILanguages], its [Settings] section is the server's copy, and a hand edit to a key the database holds is named in the error log (HM5804) and does not take effect. A service that may write the file puts the line back at the next start; under NT SERVICE\hMailServer the copy is not refreshed and the edited line stays as you left it, so a line that survives a restart is still not the value in use. [Security] AdministratorPassword is PBKDF2, $h1$<iterations>$<salt-hex>$<key-hex>. {app}\Data, {app}\Events, {app}\Addons and the ini are left behind by an uninstall, on purpose. What it does not do, and where to read more The installer does not open the firewall, does not create ports 465, 993 and 995, publishes no DNS record, and never applies the secure defaults, a profile or a stored-secrets key to an upgraded database. All of this is Windows only: the Linux packages have no wizard, no Control Panel and no COM (First install on Linux). Sources: the wiki's Installing hMailServer and Before You Install; SecureDefaults.md, ServiceAccount.md, Profiles.md, SetupChecklist.md, SampleDomain.md and Upgrading.md; and chapters 3 and 4 of the public documentation. The release announcement is hMailServer 6.3.4: a password could run code on Windows servers with JScript scripting.