Repository navigation
Installing on Linux
Released in 6.3.0, on 10 September 2026 - the first release in this server's history to carry Linux packages, and the reason that number is 6.3 and not 6.2.29. From 6.3.0 to 6.3.3 every release carried a
.deb, an.rpmand an AppImage for x86-64 and AArch64, built by the tag's own GitHub workflow. 6.3.7, the latest release (17 October 2026, schema 6108), carries, as 6.3.6 did, the generic.deband.rpmfor x86-64 and AArch64, a.debfor Debian 12 and 13 and Ubuntu 24.04 and an.rpmfor Fedora 44 and 43, EL 10 and 9, openSUSE Leap 16.0 and Tumbleweed, each for both architectures, and both AppImages, built by the tag's GitLab pipeline; the AArch64 files are cross-compiled and tested under emulation. 6.3.4 and 6.3.5 carried the x86-64.deband.rpmonly - 6.3.4 built by hand after GitHub's suspension, with no ARM machine to build on, and 6.3.5 by its tag's pipeline, which kept its AArch64 packages and AppImages as CI artifacts, out of the release - so an AArch64 or AppImage installation's last release before 6.3.6 is 6.3.3, and it upgrades to the newest release by hand, once. Brought up on 5 October 2026 to 6.3.6 (6 October 2026, schema 6108), for what 6.3.6 changes on this page, and on 18 October 2026 to 6.3.7, the latest release (17 October 2026, schema 6108), for the files it carries, its schema and how a server reaches it.hMailServer runs on Linux, on x86-64 and AArch64, since the work of 8 September 2026. This page says exactly how far that goes: what is packaged, what is proven, what is not there yet, and how a Linux installation is administered without a Control Panel. Every claim on it was checked against the tree that day, and brought up to 6.3.4 (master 92b8f9f63, and 8adce850a, the commit the tag v6.3.4 was first made on, for the schema and the checks of a download, which are the same at the tag, 51e2dbda0) on 26 September 2026; section 5 of Roadmap2, The Linux port beyond compiling, is the running record of the rows still open, and the packaging README is the file this page is drawn from.
Read this first. The Linux build is the server: the same SMTP, POP3, IMAP,
delivery, anti-spam and REST code as the Windows service, compiled with clang or
GCC from one CMakeLists.txt. It is not the Control Panel, which is a Windows
application, and it has no COM, which is the surface every Windows setup tool
uses. Administration on Linux is the configuration file, the server's own
command-line options, and the REST API - with the Control Deck, the browser
administration page the same listener serves - which creates and changes domains,
accounts, rules, routes, certificates, listeners and settings. Since 6.3.4 there is also
hmctl, a command-line client over that API
(Command Line), and the database, not the file, holds the [Settings] keys
(Administering it). If you need the Control Panel, you need
Windows, or a Windows machine that reaches the Linux server's REST listener.
flowchart LR
subgraph win["Windows"]
CP["Control Panel"] -- COM --> WS["hMailServer.exe<br/>(service)"]
end
subgraph lin["Linux"]
INI["/etc/hmailserver/hMailServer.ini"] --> LS["/usr/bin/hmailserver<br/>(systemd unit)"]
CLI["hmailserver --set-admin-password<br/>--create-database / --upgrade-database"] --> LS
REST["REST API :8045<br/>(and the Control Deck)"] --> LS
LS --> DB[("PostgreSQL or MySQL/MariaDB")]
LS --> STORE["/var/lib/hmailserver"]
end
- What is proven
- What you get
- Installing the package
- First start, step by step
- The server's command line
- Where things are
- Administering it
- Logs and the journal
- Upgrading
- What is not there yet
- Building it yourself
On 8 September 2026, against a live PostgreSQL 18:
| Step | Result |
|---|---|
hmailserver --create-database |
Created the database and built the schema (version 6031) from the create script |
hmailserver --upgrade-database |
Reported nothing to do |
systemctl start (the unit runs --foreground) |
The server started and opened its SMTP, POP3, IMAP and REST listeners |
POST /api/v1/domains/{domain}/accounts |
Created an account |
SMTP submission with AUTH
|
Accepted, delivered to the mailbox on disk |
IMAP SELECT INBOX / FETCH
|
The same message, subject intact |
The schema version in the first row is the one the binary of 8 September carried: 6.3.0 and 6.3.1 shipped 6031, 6.3.2 6038, 6.3.3 6040, 6.3.4 6104, 6.3.5 6105, and 6.3.6 and 6.3.7 - the latest release, which adds no step - 6108 (Changes Since 6.2.10 section 2), so a database created by 6.3.6 or 6.3.7 is stamped 6108.
Both architectures compile every one of the 496 core translation units (x86-64
natively, AArch64 cross-compiled); the .deb was installed on a machine, created
the service user and directories with the stated modes, and its binary read the
packaged configuration. The AArch64 packages, up to 6.3.3's, were built by CI on an ARM
runner until GitHub became unavailable on 18 September 2026, and have not yet been installed
on ARM hardware by hand; the roadmap says so. 6.3.4 has none. Since 25 September 2026 GitLab
CI has a linux-cross job, written to compile every core translation unit for AArch64 on
the project's own runner and to build no package. It passed in master's first full pipeline,
2886389460 on 27 September 2026, in 9 min 19 s (ContinuousIntegration.md). The
generic AArch64 .deb and .rpm are built and installed under emulation by the package jobs of
.gitlab/ci/, and a release carries them again from 6.3.6.
For a tag vX.Y.Z the release page holds, beside the Windows installer, the artefacts
below - every one of them for 6.3.0 to 6.3.3 and from 6.3.6, and only the two
x86-64 packages for 6.3.4 and 6.3.5:
| Artefact | For | Name | In 6.3.7 (as in 6.3.6) |
|---|---|---|---|
| Debian package | Debian, Ubuntu and derivatives, x86-64 | hmailserver_X.Y.Z_amd64.deb |
Yes: hmailserver_6.3.7_amd64.deb (and in 6.3.4 and 6.3.5) |
| Debian package | the same, AArch64 | hmailserver_X.Y.Z_arm64.deb |
Yes: hmailserver_6.3.7_arm64.deb (6.3.4 and 6.3.5 had none; 6.3.3's was the last before 6.3.6) |
| RPM | Fedora, RHEL, openSUSE and derivatives, x86-64 | hmailserver-X.Y.Z-1.x86_64.rpm |
Yes: hmailserver-6.3.7-1.x86_64.rpm (and in 6.3.4 and 6.3.5) |
| RPM | the same, AArch64 | hmailserver-X.Y.Z-1.aarch64.rpm |
Yes: hmailserver-6.3.7-1.aarch64.rpm (6.3.4 and 6.3.5 had none) |
| Distribution packages (6.3.6) | a .deb for Debian 12 and 13 and Ubuntu 24.04, an .rpm for Fedora 44 and 43, EL 10 and 9, openSUSE Leap 16.0 and Tumbleweed, each for x86-64 and AArch64 |
the release page names each | Yes: eighteen, new in 6.3.6 |
| AppImage | any x86-64 or AArch64 distribution |
hMailServer-X.Y.Z-x86_64.AppImage, hMailServer-X.Y.Z-aarch64.AppImage
|
Yes: hMailServer-6.3.7-x86_64.AppImage and hMailServer-6.3.7-aarch64.AppImage (6.3.4 and 6.3.5 had none; 6.3.3's were the last before 6.3.6) |
On GitLab the two x86-64 packages also have a version-less address that always fetches the
latest release's file, https://gitlab.com/hmailserver/hmailserver/-/releases/permalink/latest/downloads/
followed by hmailserver_amd64.deb or hmailserver.x86_64.rpm. GitLab picks that release by
date and has no pre-release flag, so the project's own download links,
https://updates.progressiverobot.com/download/hmailserver_amd64.deb and
/download/hmailserver.x86_64.rpm, always lead to the newest stable release's file instead,
never a pre-release's. The site has served HTTPS since 26 September 2026
(issue #30), and on 27 September 2026
both addresses led to 6.3.4's packages. Since 6.3.6 the AArch64 packages and
the AppImages have the same: https://gitlab.com/hmailserver/hmailserver/-/releases/permalink/latest/downloads/
followed by hmailserver_arm64.deb, hmailserver.aarch64.rpm,
hMailServer-x86_64.AppImage or hMailServer-aarch64.AppImage (the link paths carry no
version), or the update site's /download/ names; while 6.3.4 and 6.3.5 were the latest
release, which lacked them, the links in the table were 6.3.3's own. The server's own update
checker still looks for the versioned names above.
Up to 6.3.3 each has a Sigstore .cosign.bundle beside it, signed by the same workflow that
signs the installer; verify one the same way (Installing hMailServer has the
cosign verify-blob line). 6.3.4's packages carry no bundle, so no server's live update
installs them: install the package by hand, as below. Their SHA-256 are in the release's
hmailserver-6.3.4-SHA256SUMS.txt, whose signature, hmailserver-6.3.4-SHA256SUMS.txt.sig, is
made with the key that signs the release tags; with OpenSSH 8.1 or later, in a clone of the
repository and with the downloads beside you:
ssh-keygen -Y verify -f .gitlab/allowed_signers -I christopher.j.holloway@outlook.com -n file -s hmailserver-6.3.4-SHA256SUMS.txt.sig < hmailserver-6.3.4-SHA256SUMS.txt
sha256sum -c --ignore-missing hmailserver-6.3.4-SHA256SUMS.txtThe first must say Good "file" signature for christopher.j.holloway@outlook.com, the second
OK for each file you downloaded. Each package also has an SBOM of its own beside it,
<package>.cdx.json (Security Policy, Software bills of materials). The names are
not cosmetic: a Linux server's update checker builds the name its own package manager and
architecture would install and looks for exactly that on the release page.
From a build service. Three carry 6.3.7, each built from the release's source tarball
and the Debian and RPM packaging inside it, as
Channels.md gives them, read on
21 October 2026: OBS's home project home:progressiverobot publishes it for openSUSE Leap
16.0 (x86_64 and aarch64) and Tumbleweed (x86_64), in repositories OBS signs (sudo zypper addrepo https://download.opensuse.org/repositories/home:/progressiverobot/16.0/home:progressiverobot.repo,
openSUSE_Tumbleweed in place of 16.0 for Tumbleweed; then fetch the repository's key,
repodata/repomd.xml.key under the same address, and import it with sudo rpm --import only
if gpg --show-keys shows the fingerprint BA0868309CFBD36498CE41D22F0B9419E67EE770, OBS's
key for the project, so that zypper trusts the repository without asking; then sudo zypper install hmailserver); Copr's progressiverobot/hmailserver built it for Fedora 44 and 43 and EPEL
10, each on x86_64 and aarch64 (sudo dnf copr enable progressiverobot/hmailserver && sudo dnf install hmailserver); and the PPA ppa:hmailserver/hmailserver publishes it for Ubuntu
24.04 and 26.04, amd64 and arm64 (sudo add-apt-repository ppa:hmailserver/hmailserver && sudo apt install hmailserver). On 23 October 2026 6.3.7 was installed from each of the three
as a user installs it - on Ubuntu 24.04 and 26.04, Fedora 44 and AlmaLinux 10, amd64 and arm64
each, and on Leap 16.0, both, and Tumbleweed, x86_64 - and the server it installed started and
answered SMTP and the REST API over TLS
(Channels.md, What was tried;
PackageManagers.md). The AUR and the Snap Store have
nothing yet.
One more thing exists and is not a release asset: a PKGBUILD for Arch in the
tree (hmailserver/source/Server/platform/packaging/PKGBUILD), which builds from the
tag on your own machine, which is what Arch asks for. Its source line clones the tag
from the project's repository on GitLab (its url, https://gitlab.com/hmailserver/hmailserver).
The AppImage (build-appimage.sh makes one from a built tree, with linuxdeploy and its
AppImage plugin put in build/.appimage-tools by hand, since the script no longer downloads
them from GitHub) is a try-it-out artefact for a daemon
that is not meant to run out of a home directory, and is labelled as such on its way out.
Since 6.3.6 the AppImage makes its data, logs, temp, events and database folders
under $HMAILSERVER_HOME (by default $XDG_DATA_HOME/hmailserver, or
~/.local/share/hmailserver) under umask 077 and sets them 0700 on every run, so that a tree
an earlier AppImage made under the user's umask - 0755 under the usual 022, in a home other
users may enter on many distributions - is closed too; its configuration is 0600 (the
packages' folders were 0750 and their configuration 0640 already, below).
sudo apt install ./hmailserver_6.3.4_amd64.deb # Debian, Ubuntu
sudo dnf install ./hmailserver-6.3.4-1.x86_64.rpm # Fedora, RHELThe packages declare their library dependencies automatically (dpkg-shlibdeps for the .deb, rpm's own auto-requires), so libpq is pulled in with them. If you are
going to use MySQL or MariaDB, install its client library yourself: the
server opens libmariadb.so.3 at run time rather than linking it, so no
package manager will do it for you - libmariadb3 on Debian and Ubuntu,
mariadb-connector-c on Fedora and RHEL, mariadb-libs on Arch. The container
image installs libmariadb3 itself from the release after 6.3.7
(Running in a Container).
The package installs the server enabled and stopped, on purpose. It has no database yet, and a mail server that cannot reach one writes an error to the log every second until somebody notices. The post-install message says what to do next; the next section is the long form of it.
What the maintainer scripts do, so you know what to undo:
| Create | the hmailserver system user and group |
| Create |
/var/lib/hmailserver and its temp, events and database subdirectories, and /var/log/hmailserver, all 0750 hmailserver:hmailserver
|
| Install |
/etc/hmailserver/hMailServer.ini at 0640 root:hmailserver - readable by the service, writable only by root |
| Enable |
hmailserver.service, without starting it |
| On upgrade | run hmailserver --upgrade-database as the service user (only if a database is configured), then try-restart the service if it was running |
| On remove | stop and disable; leave the mail store and the logs alone, and say so |
On purge (.deb) |
remove /etc/hmailserver as well; still leave the store |
| Require (6.3.6) |
ca-certificates, which apt and dnf install with the package. Every .rpm the project makes also requires ((glibc-gconv-extra(<arch>) or glibc-gconv-modules-extra(<arch>)) if (dnf and system-release)) and recommends the same pair: required where dnf is installed on Fedora or EL, whose release package provides system-release - there dnf installs them with the package, the live update's dnf install included - and only recommended elsewhere, because on openSUSE the live update installs with rpm -Uvh; zypper installs the recommendation unless solver.onlyRequires is on. On Fedora and EL a server without them whose dnf has no repository enabled (an unregistered RHEL, say) has the update refused, and stays on the earlier version, until glibc-gconv-extra is installed. The RPM spec, whose packages have no live update, requires its distribution's one by name; an AppImage runs on its host's glibc and cannot require a package - on Fedora, EL or openSUSE install it by hand. Without the converters the server reads and writes no text in a character set but Unicode's, US-ASCII, UTF-7, ISO-8859-1, ISO-8859-15 and Windows-1252 (BIG5, ISO-2022-JP, Windows-1251 and ISO-8859-2 came out empty), and from 6.3.6 it says so at its start and in --check-config (PackagesRpm.md, The character sets) |
| Install (6.3.6) |
/usr/share/hmailserver/licenses/AGPL-3.0.txt and a copyright file - /usr/share/doc/hmailserver/copyright from the .deb, /usr/share/licenses/hmailserver/copyright from the .rpm. Alpine Linux (musl; an APKBUILD and an OpenRC service) and Nix (a flake with a NixOS module) are supported from the tree (Alpine.md, Nix.md); the Debian source package and the RPM spec a distribution's maintainer starts from are SourcePackages.md |
1. Create the database and its user. PostgreSQL:
sudo -u postgres createuser --pwprompt --createdb hmailserverWith --createdb the server creates the database itself in step 4. If you
would rather the service role could not create databases - which is the
tidier policy - leave the flag off and create it yourself:
sudo -u postgres createuser --pwprompt hmailserver
sudo -u postgres createdb --owner hmailserver hmailserverStep 4 notices an existing, empty database and builds the schema inside it.
Since 6.3.4 it leaves a database that already holds this build's schema, or an
older one, as it is with exit status 0, and exits 1 for a newer one; on 6.3.3 it
refused any database that already held a schema and named --upgrade-database.
2. Tell the server where it is.
sudoedit /etc/hmailserver/hMailServer.iniTwo things to change, and the file has a paragraph on each:
-
[Database] Type-PostgreSQLorMySQL. -
[Database] Server,Database,Username,PasswordandPort. Write the port out (5432,3306); it goes into the connection string as it stands and there is no useful default. -
Since 6.3.4, optionally
[Database] TlsMode(prefer, the default,require,verify-fullordisable) andTlsCaFile. With nothing set, MySQL and MariaDB are reached over TLS whenever the database server offers it, the certificate unchecked; before 6.3.4 the connection through MariaDB Connector/C was never encrypted.sudo -u hmailserver hmailserver --check-databasemakes one connection and says what it got (DatabaseTls.md). A MySQL or MariaDB server must be MySQL 5.7.9 or MariaDB 10.2.2 or later, since every table isutf8mb4from schema 6102.
Leave AdministratorPassword alone; the next step writes it.
Since 6.3.4, this is also the moment to set the REST
listener of step 7 - [Settings] RestApiPort and RestApiBindAddress, and the
certificate and key if you bind anything but loopback - because every [Settings] key
the file holds at the server's first start is taken into the database then, the packaged
RestApiPort=0 among them, and a later edit to a key the database holds is not applied
(step 7 has the command for that case).
3. Set the administrator password. It is read from standard input with echo off, hashed with PBKDF2 exactly as the Control Panel hashes it on Windows, and written into the file. The file is root-owned, so this runs as root:
sudo hmailserver --set-admin-password4. Create the schema.
sudo -u hmailserver hmailserver --create-databaseIf the database is not there, this connects to the server the [Database]
section names with no database selected, creates it in the backend's own
dialect and reconnects; if it is there and empty, it uses it. Either way it
then runs the create script for the backend's type - what DBSetup does
over COM on Windows (CreateExternalDatabase; DBSetupQuick creates only the built-in database). It refuses the two Windows-only backends (SQL Server and SQL
Server Compact) by name.
A new installation is secured at its first start (since 6.3.4). A database
--create-database makes is marked as a new installation's, and it leaves a file,
.new-installation, in the configured DataFolder. Before every start the unit runs
hmailserver --apply-new-install-defaults --if-marked, which does nothing unless that
file is there; at the first start after step 4 it gives the server a self-signed
certificate (RSA 2048, 825 days, under /var/lib/hmailserver/Certificates), STARTTLS on
25, 587, 110 and 143, and TLS required for authentication on the Internet IP range,
so that a password from another machine never crosses the network in the clear; this
machine's own range is left as it was. It acts only on a database marked within a day of
its clock and still as the create script left it, and never on an upgraded or attached
one. A DataFolder outside the unit's ReadWritePaths needs a drop-in adding it before
that first start. Mail clients warn about the self-signed certificate: replace it with
ACME or your own (Encryption and Certificates,
SecureDefaults.md).
The stored-secrets key (since 6.3.4). Each account's TOTP second factor and the
[Settings] secrets are sealed in the database under a key that lives in
hMailServer.ini, never in the database or a backup. Run as the service user, step 4
cannot write the root-owned file and makes none; make it, and export it at once to keep
with the database backups, apart from them:
sudo hmailserver --create-stored-secrets-key
sudo hmailserver --export-stored-secrets-key /root/hmailserver-stored-secrets.keyUntil a key is made those secrets are kept as written, and the setup checklist says so (SecretsAtRest.md).
5. Check what it read, before opening anything.
sudo -u hmailserver hmailserver --check-configIt prints the configuration path, the directories and the database type it
made of what you wrote, and exits without opening a listener or the database.
Database type: 0 means the Type key did not take.
6. Start it.
sudo systemctl start hmailserver
sudo systemctl status hmailserver
journalctl -u hmailserver -f7. Turn on the REST API, which is how you will administer it. In the
configuration, [Settings] RestApiPort=8045 and RestApiBindAddress=127.0.0.1
(loopback, unless you also set RestApiCertificateFile and
RestApiPrivateKeyFile), then:
sudo systemctl reload hmailserver # SIGHUP: re-reads the configuration
curl -u Administrator http://127.0.0.1:8045/api/v1/statusA reload stops and restarts the listeners inside the running process, so do it
when nothing is mid-delivery. The user name is Administrator, as on Windows.
That is 6.3.3, where the file is what the server reads. Since 6.3.4 it works only if
those lines were in the file before step 6. From schema
6042 the database is the settings store: the first start took the packaged
RestApiPort=0 into it, and a value edited into the file afterwards is reported in the
error log as HM5804 and the stored value is used, so the reload brings up no listener.
With the listener off, nothing that speaks the API can change it either. The server's own
command is the door:
sudo hmailserver --set-setting RestApiPort=8045
sudo hmailserver --set-setting RestApiBindAddress=127.0.0.1
sudo systemctl restart hmailserver--set-setting stores the value the way the REST API stores one, writes the server's copy
into the file (it runs as root because the file is root's, and keeps its owner and mode),
and prints what it stored. It refuses a name the server does not read, a port that is not
0 to 65535 and a bind address that is not an IP address or localhost; a secret's value -
SRSSecret, PasswordPepper and the like - is refused on the command line, and is typed
at a prompt instead with the name alone (sudo hmailserver --set-setting SRSSecret).
The file's [SettingsOverride] section, applied over the store, is the other way through:
[SettingsOverride]
RestApiPort=8045
RestApiBindAddress=127.0.0.1sudo systemctl reload hmailserver # the listener starts; HM5807 names the override
export HMAIL_URL=http://127.0.0.1:8045
hmctl ini set RestApiPort 8045 # stored, reported as HM5808 while the override stands
hmctl ini set RestApiBindAddress 127.0.0.1
sudoedit /etc/hmailserver/hMailServer.ini # remove the [SettingsOverride] section
sudo systemctl reload hmailserverhmctl asks for the administrator password (or reads HMAIL_PASSWORD); curl -X PUT
with {"value":"8045"} on /api/v1/settings/ini/RestApiPort does the same. One more
thing differs on a package installation: the packaged file is
0640 root:hmailserver and the unit's ProtectSystem=strict leaves /etc read-only to
the service, so the server does not write its copy of a stored value back into the file.
A value stored over the API, such as these two, is in effect, and the line left as it was
is not an error: the application log says, where application logging is on, that the file
is read-only to the account the server runs as and that its [Settings] copy is not
refreshed, and the key's line keeps its old value until it is changed by hand to the same
value (The Service Account).
8. Your first domain. Open the Control Deck - http://<host>:8045/ in a
browser, in any of its twenty languages - sign in as Administrator with the
password from step 3, and add the domain on its Domains view: the name, the
postmaster, and everything else as the Control Panel would set it. The same over
the API, for a script or a session with no browser:
curl -u Administrator -H "Content-Type: application/json" \
-d '{"name":"example.com","active":true,"postmaster":"postmaster@example.com"}' \
http://127.0.0.1:8045/api/v1/domainsThe name is checked exactly as the Control Panel checks it (400 with its
sentence if it is not a valid domain name, 409 if it already exists), and
every other setting takes the default a new domain gets there. PUT /api/v1/domains/example.com with {"active":false} switches it off;
DELETE removes it with its accounts, aliases, lists and directories.
Creating and deleting a domain are server-wide: an API key restricted to
named domains gets 403.
Then create the account over REST and send yourself a message - the table at the top of this page is the sequence that was run.
hmailserver --help, verbatim in substance:
| Option | What it does |
|---|---|
--config <file> |
The configuration file to read. Default: hMailServer.ini beside the executable, then /etc/hmailserver/hMailServer.ini
|
--foreground |
Run in the foreground and log to standard error as well as to the log directory. This is the default; the option exists so the unit file can say so |
--check-config |
Read the configuration, report what it says, exit without opening a listener or the database. Since 6.3.6 it ends with a line Character sets: that says every character set the server converts text in - the code page table's 24 and the PST import's - converts here, or names those that do not, with the package that has them on Fedora, EL and openSUSE; a start with any missing writes the same to standard error and to the application log. A warning, not a refusal: it still exits 0 |
--set-admin-password |
Read a new administrator password from standard input (echo off), hash it with PBKDF2, write it to the configuration, exit |
--create-database |
Create the database [Database] names on the server it names, and run the create script for its type |
--upgrade-database |
Run every upgrade script from the database's version to this build's, in order. Refuses a database from a newer build; stops rather than loops if a script runs and the version does not move |
--check-database |
Since 6.3.4. Connect once to the database, with its TlsMode and TlsCaFile, say whether the connection is encrypted and whether the certificate was checked, and exit: 0 connected, 1 not, 2 not configured |
--set-setting NAME=VALUE, --set-setting NAME
|
Since 6.3.4. Store one [Settings] value in the database and write the server's copy into the file - for the settings the server needs before its REST API can be reached, RestApiPort above all (step 7). With the name alone the value is read from standard input, and a secret's value is refused on the command line. Run as root |
--apply-environment |
Since 6.3.4. Store every setting the environment names - HM_SETTING_<key>, HM_PROPERTY_<name>, their _FILE forms and the container's HM_REST_* - each checked first, nothing stored if one is refused; an administrator's change to a setting it names is then refused until a run without it (Running in a Container, Profiles and Environment). Run as the service user |
--apply-profile NAME [--confirm] [--once] [--if-new], --revert-profile
|
Since 6.3.4. Apply one of the four setting profiles, or put back what the last one changed (Profiles and Environment). --confirm is needed where an entry closes a listener, trusts an address range, weakens a check or shortens a window; --if-new does nothing on a server with ten accounts or more. Run with the server stopped, as the service user |
--apply-new-install-defaults [--if-marked [<file>]] |
Since 6.3.4. The secure defaults of a new installation, above. Only to a database --create-database marked, still as the create script left it; exit 5 and nothing changed otherwise. Run as the service user, with the server stopped |
--sample-domain create, --sample-domain remove
|
Since 6.3.4. Make, or take away again, the throwaway example.test with three mailboxes, a list, a rule and eight delivered messages (Your First Domain and Mailbox). Remove it before the server takes real mail: its password is in the documentation |
--measure-store, --compress-store [--decompress], --recount-store
|
Since 6.3.4. What compressing the message store and holding its large parts once would save, and the rewrite either way, with the server stopped (MessageStore.md). Since 6.3.6, run as root, a store command, an object-store copy, --sample-domain, a profile or --apply-environment becomes the service's account - the data directory's owner, with its groups - before it opens anything, and refuses (exit 2) a data directory that cannot be examined, or whose way is not root's and its owner's alone. Over a data directory that belongs to root - a service run as root, as a source build or a container without User= has it - it runs on as root, and says so on standard error, where the data directory and every folder under it, the log, temporary, event and database folders and every folder under them, every folder a link in them leads to, the configuration that names them, and the ways to all of them are root's alone (each folder root's and written by no other account, no default access control list giving another account a write, each link root's); it then makes what it makes with every other account's write taken away, whatever the umask. Otherwise it refuses (exit 2), naming the first folder, file or link another account owns or may write - a log directory below Ubuntu's /var/log, which the syslog group may write, among them - and what to do: give it to root and take the other accounts' write from it (chown root:root, chmod go-w, setfacl -bk), name folders that are root's alone in the configuration, or give the data directory to the service's account, as the package does. Every other command line run as root (--set-setting, the stored-secrets verbs, --create-database, --upgrade-database and the rest) writes nothing to the log directory; what it did, and why it failed, is on its own output, and a report that would have gone to the error log is not written, but for the stored-secrets code's HM7496 and HM7497, which go to standard error (The Service Account, On Linux, a command run as root). The package's layout - data and logs the hmailserver account's, below folders only root writes - is the first case and is unchanged |
--encrypt-store, --decrypt-store
|
Since 6.3.4. Encrypt, or decrypt with the domain's recovery passphrase, what a mailbox encrypted at rest stored before it was switched on (Encryption and Certificates) |
--copy-store-to-object-storage, --copy-store-from-object-storage
|
Since 6.3.4. Copy the message store into the object store the settings name, or back, each file verified and a stopped run resumed (ObjectStorage.md) |
--verify-update <file> |
Since 6.3.4. Check a downloaded package or AppImage against the Sigstore bundle beside it, the way the server does before applying one; exit 0 when a signer the server trusts made it |
--create-stored-secrets-key, --export-stored-secrets-key <file>, --import-stored-secrets-key <file>, --forget-sealed-secrets <key id>
|
Since 6.3.4. Make, export, import on another node, or - lost for good - clear what was sealed under the stored-secrets key. Run as root |
--version, --help
|
Signals: SIGTERM and SIGINT stop the server; SIGHUP re-reads the
configuration (what the Control Panel's Reinitialize does); SIGPIPE is
ignored, so a peer that hangs up cannot kill the process.
From the package's install rules:
/usr/bin/hmailserver the server; one file
/usr/bin/dh2048.pem read from beside the binary; required by
every TLS context (tlds.txt is gone since
6.3.6: the Public Suffix List is compiled
in, and apt and dnf remove the old file)
/usr/share/hmailserver/DBScripts/*.sql schema creation and upgrade scripts
/usr/lib/systemd/system/hmailserver.service the unit
/etc/hmailserver/hMailServer.ini the configuration (a conffile: an upgrade
never overwrites it). Since 6.3.4 its
[Settings] section is a copy of the
database, which holds those keys
/usr/bin/hmctl since 6.3.4: the command-line client over
the REST API
/etc/logrotate.d/hmailserver the log rotation rule
Created by the maintainer scripts, and therefore not removed with the package:
/var/lib/hmailserver the mail store: one directory per domain, one per mailbox
/var/lib/hmailserver/temp scratch space for message assembly and backups
/var/lib/hmailserver/events event scripts
/var/log/hmailserver the logs
The six [Directories] keys in the packaged configuration point at exactly this
layout, and since 6.3.0 a relative value in any of the five non-program
directories is resolved against ProgramFolder, so a moved installation can be
written as one absolute path rather than six (Relocating an Installation).
There is no Control Panel and no COM here. These surfaces:
-
The configuration file. On 6.3.3, everything in the Settings Reference
that is an
hMailServer.inikey applies unchanged; the packaged file has a paragraph on every key it sets. Since 6.3.4, the file keeps[Directories],[Database],[Security],[GUILanguages],[LDAP],[SendingLimits],[SendingLimitsOverrides]andPasswordPepper, and every other[Settings]key is stored in the database from schema 6042: set before the first start, a value is taken in from the file; after it, a value is changed over the REST API (PUT /api/v1/settings/ini/{name}) or withhmctl ini set, and an edit to the file for a key the database holds is reported as HM5804 and not applied (Settings Overview). On 6.3.3 a change applies at the next start orsystemctl reload; since 6.3.4 a value stored over the API applies when it is saved for 211 of the 241 keys, and the rest wait for a reinitialise (28, a listener's port or TLS among them) or a restart (2). Every setting can also come from the environment (hmailserver --apply-environment), and a setting profile sets the thirty or so that make a server the kind it is (Profiles and Environment).WindowsEventLogEnabled=1is a Windows inheritance in name only - on Linux it means syslog, and the operational events (database down, a listener that could not bind, a failed backup, the disk floor) reach the journal through it. -
Directory authentication is LDAP, and only LDAP:
[LDAP] Enabled=1withServer,Security(2 = LDAPS, 1 = StartTLS) and a simple bind, proven against OpenLDAP. There is noLogonUserhere, so a directory-linked account with LDAP switched off is refused with HM6421 naming the settings to set. -
Stored secrets - the database password in the configuration, route and
fetch-account passwords, the TOTP secret - are protected under a key the
server makes on first use,
<DataFolder>/.hmailserver-secret-key(32 bytes, mode 0600), with AES-256-GCM; the stored form startsLINUX1:. The key file travels with the data directory: back it up with the database, and a secret moved to a machine without it cannot be opened (HM6414). A WindowsDPAPI:secret is likewise unreadable on Linux and is reported once. Since 6.3.4, what the database holds and every node must open - each account's TOTP second factor and the[Settings]secrets - is sealed under the installation's stored-secrets key instead (HMK1:), once there is one (step 4 above). -
Event scripts (since 6.3.4): JavaScript, in the QuickJS engine the Linux
build embeds, for the same events and function names as on Windows, with
ScriptLanguage=JavaScript; a script has no file, process or network access, andScriptTimeoutand a 64 MB ceiling bound it. Before 6.3.4 a Linux server refused any script (EventScripts.md). -
SNMP (since 6.3.4): a read-only SNMPv3 agent, off, and answering nobody until
a manager's address is in
SnmpAllowedAddresses; binding UDP 161 needs the unit'sCAP_NET_BIND_SERVICE, which the packaged unit has (Monitoring and Health). -
The REST API (The REST API). Accounts, aliases, settings, the queue,
the message store, the self-service portal. Authenticate as
Administratorwith the password from step 3./api/v1/settings/ini- every[Settings]key - takes the administrator password only; an API key of any scope is refused. -
The Control Deck, served by the same listener at
/(Control Panel Pages), reads and writes.hmailserver/docs/DeckParity.mdcounts it from the sources: in 6.3.3, 15 views reach 322 of the 330 COM properties the desktop Control Panel writes - domains and accounts, lists, IP ranges, external accounts, rules, routes, certificates, listeners, server messages, the settings groups, the backup, the queue, the logs and DANE records; the gaps are account groups, folder permissions and application passwords. In 6.3.4 it has 40 views (DeckParity.md's count) - adding, among others, the audit trail, groups, roles, remote-domain policies, reports, devices, webhooks, spam traps, the reputation watch, what changed from stock, the first-hour checklist with the setting profiles, the API keys, the quarantine, the archive and its holds, the update, the DNS records to publish, folder permissions, migrations and the DMARC reports received - and the census counts 466 properties the desktop program writes, 458 of them writable over REST and all 458 reached from a view. The eight left are an account's directory fields (title, department, phones, photo), whichPUT /api/v1/accounts/{address}/directorycarries under names the census does not match, so read DeckParity's What the heuristic gets wrong before calling them a gap. On 6.3.3 its Settings view carries only four[Settings]keys (SmtpTarpitCount,SmtpTarpitDelaySeconds,UseLanguage,RewriteEnvelopeFromWhenForwarding), so a listener, TLS, OAuth 2.0 or logging key is the file there. Since 6.3.4 the settings groups the view draws carry more rows kept as[Settings]keys, each with a badge saying when a save applies; a key no group carries is the API orhmctl. The Control Deck is the walk through it. -
hmctl(since 6.3.4), installed by the packages as/usr/bin/hmctl: the same API from a shell, withhmctl ini set,get,listanddeletefor the[Settings]keys,hmctl config export,diffandapplyfor the configuration as one document,hmctl config changedfor what differs from stock,hmctl settings profilesandapply-profilefor the setting profiles andhmctl sample-domainfor the throwaway domain (Command Line).
The server's own logs are in /var/log/hmailserver, in the same format as on
Windows (Troubleshooting reads them). Sieve scripts and the backup index, which the
server marks with a byte-order mark, are UTF-16LE on both platforms, so a file written on
one reads on the other. The backup and event logs are UTF-8 on Linux since 6.3.6, as the
application and error logs are - the server converts hmailserver_backup.log and
hmailserver_events.log in place the first time it opens each, and logrotate's earlier
copies stay UTF-16LE - and UTF-16LE on Windows.
A memory-safety fault is recorded in /var/log/hmailserver/crash-oracle.log
(one line: signal, address, thread, event number), after which the process dies
by the signal it caught and the kernel's core-dump policy applies; the unit
file says how to allow a core, and why it is off by default. The journal carries the startup line,
anything written to standard error, and the operational events. The logrotate
rule uses copytruncate because the server does not reopen its log on a
signal; the rule says so at length.
journalctl -u hmailserver -f
tail -f /var/log/hmailserver/hmailserver_$(date +%F).logInstall the new package. On an upgrade the maintainer scripts run
hmailserver --upgrade-database as the service user (only when a database is
configured) and then try-restart the service if it was running. A failure of
the schema upgrade is reported and does not fail the package - the binary is
already in place, and the server's own log is the better place to read why - so
read what the upgrade printed:
sudo -u hmailserver hmailserver --upgrade-database # safe to run by hand; "nothing to do" when done6.3.4 is installed by hand: its packages carry no Sigstore bundle, so no server's
live update installs them. The configuration is a conffile and is never overwritten.
Upgrading to 6.3.4: --upgrade-database moves the schema to 6104 - on MySQL and
MariaDB the 6102 step rebuilds every table as utf8mb4, which takes time on a large
database and needs the ALTER privilege, and a MySQL older than 5.7.9 or a MariaDB older
than 10.2.2 stops the upgrade at 6041 with error 1071, having changed nothing (Upgrading hMailServer) - and the server's next start - the maintainer script's try-restart, if it was running -
makes the database the settings store: keys the 6.3.3 mirror already held keep their
stored values, and any [Settings] key of /etc/hmailserver/hMailServer.ini it never
held is taken in from the file. A [Settings] line edited after the old
server last started is treated as an edit at that first start (HM5804) and not applied;
restart the old server once after the last change before upgrading. An upgrade makes
no stored-secrets key and never applies the secure defaults of a new installation; the
setup checklist says what is left. Before it stops, a 6.3.4 server drains - the SMTP, IMAP, POP3 and ManageSieve listeners close at
the socket, so senders retry, and the queue pauses - and ShutdownDrainSeconds (30 is a
reasonable figure) lets what is in flight finish; POST /api/v1/server/drain does the same
on its own for maintenance. The package's post-install step still runs the schema upgrade,
so the new bootstrap key [Database] UpgradeOnStart is not needed here
(Upgrading hMailServer). The server's update
checker, when enabled, looks for the package name its own platform would install
and tells you. A 6.3.4 server reads https://updates.progressiverobot.com, which GitLab
Pages serves from the project's releases; a server from 6.3.0 to 6.3.3 reads the suspended
account's Releases API on GitHub, which has answered 404 since 18 September 2026 and still
does, until
UpdateFeedUrl=https://updates.progressiverobot.com/releases.json points it there
(UpdateFeed.md).
Since 6.3.4, it can also apply it - a release signed by a signer it trusts, which 6.3.4's own packages are not. The server
runs unprivileged and cannot install a package, so it writes a one-file request
into /run/hmailserver and a root path unit the package enables,
hmailserver-update.path, takes it and runs
/usr/lib/hmailserver/hmailserver-update. That program checks every line of the
request against root's own configuration rather than the request's word for it,
stops the unit, verifies the package again as root against its Sigstore
bundle - the same check the server made, made by a process the server could not
have influenced - and refuses anything that is not a genuine upgrade: the
version is read from the package itself and compared with what dpkg or rpm
says is installed, so a signed but superseded release cannot be put back. Then
it installs with apt-get/dpkg or dnf/rpm (an AppImage is swapped in
place, the old one kept as .previous), starts the unit, waits for the server
to stay up - and for /readyz when the metrics listener is on - reinstalls the
previous version if it does not, and writes one line to
<DataFolder>/Updates/last-apply.txt that the server reports at its next check
and the Control Deck shows. A refused request is explained in
journalctl -u hmailserver-update and nowhere else, on purpose: root writes
nothing into the service user's directory while a process of theirs may still be
running.
Since 6.3.6 the unit the helper stops and, for an AppImage, the image that verifies
the new one come from its own command line (--unit, --image), never from the
request; after the stop it checks that the unit is down and that nothing of the
service account still runs, and it verifies, reads and installs only copies of the
package and the rollback image that it made after the stop under /var/tmp. Before
installing it reads the database's schema with hmailserver --schema-version - where
systemd runs the machine, in the unit's own sandbox, as the unit's User=; where
systemd will not, the version is not read, never outside the sandbox - and puts the
earlier version back only onto the database it left (Upgrading Guide, On Linux
the live update holds to the same rule). A server under a unit of another name
needs --unit in a drop-in for hmailserver-update.service; an AppImage under the
path unit needs --image there and 6.3.6's script copied to /usr/lib/hmailserver/.
apt-get runs quietly. The helper opens the Updates directory, and makes and opens
its log and its outcome, while the server is confirmed stopped, gives them to the
service account through the open files before it starts the server, writes them
through those files alone, and renames each into place through the open directory,
which replaces a symbolic link and never follows it; 6.3.4 and 6.3.5 wrote, chowned
and renamed them by name after the restart. An update is applied by the helper of the
version it replaces, so 6.3.6's own helper applies 6.3.7, for the generic .deb and
.rpm of either architecture and both AppImages, each finding its own file in the feed by
name. On 6.3.4 or 6.3.5 install 6.3.7 with the package manager rather than by the live
update, whose apply step there is the one 6.3.6 fixed, or systemctl disable --now hmailserver-update.path until then (item 24 of 6.3.6's "What changes on upgrade"). A
server installed from one of 6.3.6's per-distribution packages is offered the generic
package, which apt refuses on Debian 12 and dnf on Enterprise Linux 9: upgrade it with its
package manager and its own release's package of 6.3.7 (Upgrading hMailServer 18.4f).
A request the helper refuses before it stops anything - an AppImage under the path
unit with no --image, a line that fails a check - no longer leaves the server
refusing connections for ten minutes: since 6.3.6 the server asks systemd about the
helper's unit every five seconds and leaves the drain once it has ended with no
outcome written (HM7151, naming the unit and its exit status).
Check that the machine can do it at all with
sudo /usr/lib/hmailserver/hmailserver-update checkwhich names the installer it would use, whether the path unit is active and
whether the running unit has the runtime directory the request needs. The Debian
and RPM packages enable and start the path unit for you; Arch does not enable
units from a package, so there sudo systemctl enable --now hmailserver-update.path
is yours to run. Nothing happens unless you turn the update check on and ask for
the install, from the Control Deck or over the API.
In the tree since 11 September 2026; the release workflow on GitHub pushed the image to
ghcr.io/progressiverobot/hmailserverfrom 6.3.2, which has answered 404 since GitHub suspended the project's account on 18 September 2026. The Compose file and the chart now nameregistry.gitlab.com/hmailserver/hmailserver, the project's GitLab container registry, where each release's pipeline pushes and signs its image since 6.3.6 - 6.3.7's isregistry.gitlab.com/hmailserver/hmailserver:6.3.7, also tagged6.3andlatest(Running in a Container). On 18 October 2026 the image was copied toghcr.io/rainbowwizard-coder/hmailserver, for the project's repository on GitHub, GitLab's mirror, which the owner made public on 20 October 2026, and on 21 October 2026 to Docker Hub, asdocker.io/progressiverobot/hmailserver, by its digest; each pulls without signing in, andcosign verifyof it passes with the identity and issuer ContainerImage.md gives. Nothing here pulls from either copy.
The same package as a container image, with the database, the REST listener and the administrator password written from the environment on start - and, since 6.3.4, every other setting too: Running in a Container. Everything on this page about what the server is, how it is administered and where things are applies to the container too; that page says what differs, which is mostly how the API is reached.
Shipped in 6.3.2. Since 6.3.4,
AutoBanFirewall,AutoBanCommandandAutoBanNeverBanare stored settings like the other[Settings]keys: set them over the API or withhmctl ini setrather than in the file.
An auto-ban (repeated failed logons from one address) is enforced by the server's own listeners: the kernel accepts the connection, the server refuses it. Two ways to push the ban below the server, and one is enough:
fail2ban, which needs no capability at all because it runs as root and reads
the application log. The package installs /etc/fail2ban/filter.d/hmailserver.conf
and a jail at /etc/fail2ban/jail.d/hmailserver.conf, disabled as Debian asks of
a shipped jail. The filter matches the two fixed-shape lines the server writes for
every counted failure and every ban, whether or not protocol logging is on
(AutoBanLogonEnabled, on as shipped, is what writes them). Turn it on:
printf '[hmailserver]\nenabled = true\n' > /etc/fail2ban/jail.d/hmailserver.local
systemctl reload fail2ban
fail2ban-client status hmailserver
The server itself, with AutoBanFirewall=1 under [Settings] (on 6.3.3): on every ban
and every expiry it runs /usr/lib/hmailserver/autoban-hook, which keeps an
nftables set with a timeout (iptables where there is no nft) and drops TCP from
the banned address to the ports the server listens on. Changing the firewall
needs CAP_NET_ADMIN, which the unit deliberately does not grant a mail server
by default. Grant it once, with a drop-in, and the hook's check verb says
whether it can act:
systemctl edit hmailserver
[Service]
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
systemctl restart hmailserver
sudo -u hmailserver /usr/lib/hmailserver/autoban-hook check
AutoBanCommand runs any program of yours instead of, or as well as, the hook -
<command> ban <address> <minutes> <ports> and <command> unban <address> - for a
cloud firewall or a router. And before turning either on, list the addresses you
administer from in AutoBanNeverBan: a ban that reaches the firewall locks that
address out of every mail port on the machine, not just out of one connection.
Since 6.3.6 what the auto-ban put below the server is lifted after a stop too. At every
start and reinitialise, before the first listener opens, the packaged hook is told reset
and then every ban in force - wherever it is installed, whether AutoBanFirewall is on or
off - and again when AutoBanFirewall is switched off; its iptables calls wait for the
xtables lock. AutoBanCommand's account is kept in autoban-command.ledger in the temp
folder, under the SHA-256 of the command line and never its text, and at a start the command
is told unban for each address it was left holding that is not banned now; a command
replaced or cleared is never run again, and the addresses it was told to ban and not to
un-ban are named in the error log (HM6523). A command that starts the server short of its
listeners (--sample-domain, --apply-environment, --apply-profile) does none of this.
Stated here rather than discovered later. Each is a row in the roadmap's Linux section, which is where the current state lives.
| Gap | What it means for you |
|---|---|
| The regression suite, in part |
hmailserver/test/LinuxRegressionTests compiles the suite's files in place - not copies of them, the same text the Windows gate runs - and puts a subset of its tests against a Linux server. Last measured on the tree of 17 September 2026 (7ef5fba2e): 1,725 results, 1,439 passed, 286 skipped, 0 failed. From 17 September it ran in CI as two halves on every push, with no continue-on-error, on GitHub Actions until GitHub became unavailable to the project on 18 September 2026; since 25 September 2026 .gitlab-ci.yml gives it a job, linux-suite, written to run it whole on the project's own runner for master, batch* branches and release tags, which had not yet run when ContinuousIntegration.md was written. What skips is what cannot be asked over HTTP or has no route yet - the public folders, a stored message's MIME as a COM object, the COM logon - and every skip names its reason. The Windows suite, which gates every change, has 3,811 tests in 6.3.4 (2,302 in 6.3.3) |
| AArch64 on hardware | CI built and installed the packages on an ARM runner until GitHub became unavailable on 18 September 2026; 6.3.4 and 6.3.5 had no AArch64 package or AppImage at all; 6.3.6 and 6.3.7 carry them again, cross-compiled and tested under emulation on the project's own runners, and nobody has installed one on ARM hardware by hand yet |
| Directory authentication is a simple bind over LDAPS or StartTLS, and only that |
[LDAP] BindMethod=1 (Negotiate) is Windows SSPI; on Linux it is refused (HM6420) as a directory failure, not a wrong password. The directory's certificate must chain to the system trust store, and Server must match the name in that certificate |
| No re-keying command | The stored-secret key file is made once and never rotated; replacing it means re-entering every stored password |
The packaging README has the full text; the short form:
sudo apt install cmake ninja-build clang libssl-dev zlib1g-dev libpq-dev \
libboost-thread-dev libboost-chrono-dev libboost-filesystem-dev libboost-regex-dev rpm file
export CC=clang CXX=clang++
cmake -S hmailserver/source/Server -B build/linux -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
cmake --build build/linux
cmake --build build/linux --target package # the .deb and the .rpmclang is a preference, not a requirement: GCC 13 and later builds the same
tree (export CC=gcc CXX=g++), and CI built with both until 18 September 2026;
GitLab CI's linux-build job is written to build with clang.
build/linux-tu-census.sh compiles every core source on its own and prints how
many a POSIX compiler accepts; --target aarch64-linux-gnu is the cross
measurement. Until GitHub became unavailable on 18 September 2026, CI ran both on every push
and failed when a single translation unit stopped compiling; since 25 September 2026 GitLab
CI has a linux-cross job that does the AArch64 half on the project's own runner; it passed in
master's first full pipeline, 2886389460, on 27 September 2026.
hMailServer 6.3.7, the latest release (17 October 2026, schema 6108) · AGPL-3.0-or-later · Repository · Mirror on GitHub · Report a documentation error (a GitLab issue naming the page)
Home — full index
Start here
1. Install and run
- Before You Install
- Installing hMailServer
- Installing on Linux
- Running in a Container
- Profiles and Environment
- The Control Panel
- The Control Deck
- Your First Domain and Mailbox
- Connecting a Mail Client
- The Webmail
- DNS for Your Domain
- Migration
2. Secure it
- Encryption and Certificates
- Database TLS
- Encryption for People
- Stopping Spam
- Stopping Viruses
- Security Hardening
- Secure Defaults
- The Service Account
- Secrets at Rest
- Sign-in and Identity
- Security Policy
3. Operate it
- Monitoring and Health
- The SNMP Agent
- Backup and Restore
- Message Storage
- Compliance and eDiscovery
- Troubleshooting
- Diagnosing Stalled Mail
- Relocating an Installation
- Upgrading hMailServer
- Upgrading Guide
- The Update Feed
- Migrating the Database Backend
- High Availability Runbook
- Warm Standby
- Runbooks Digest
4. Extend it
- Rules and Sieve
- Aliases Lists and Public Folders
- Rooms and Equipment
- Mailing Lists
- Routes and Relays
- Mail In to a Webhook
- Outbound Shaping
- The COM API and Scripting
- Event Scripts
- The REST API
- Command Line
- APIs Reference
5. Contribute to it
- Project Handbook
- Architecture
- Contributing
- Release Process
- Governance
- Assurance Case
- Regression Test Environment
- Fuzzing
- Regulatory Scope
- Third-Party Binaries
Look it up — from any journey
- Settings Reference
- Settings Overview
- Capabilities and Configuration
- Control Panel Reference
- Control Panel Pages
- Ports Reference
- Changes-Since-6210
- Version-History-to-6210
- Glossary
About this wiki
- hMailServer 6.3.7 is the latest release (17 October 2026, schema 6108)
- Pages say since 6.3.4 where a feature is new in it
- AGPL-3.0-or-later
- Repository, the one place the project is worked on
- Its mirror on GitHub, since 18 October 2026, with no Issues
- Questions: a GitLab issue with the Question template, GitHub Discussions Q&A, or the forum
- Report a documentation error: a GitLab issue naming the page