Repository navigation
Before You Install
This page began as a chapter of the 6.2.10 manual and has been corrected against the 6.2.28 source tree. The Control Panel's pages are grouped differently now, so the paths below use today's groups; the TLS ports 465, 993 and 995 exist only after you create them on the TCP/IP ports page (a fresh install seeds 25, 587, 110 and 143); and everything added since 6.2.10 is in Changes Since 6.2.10. Where a value here disagrees with the Settings Reference, which is generated from the code, the reference is right. The Linux, container, service-account, secure-defaults and first-hour notes describe 6.3.4 (27 September 2026, schema 6104), checked against master 92b8f9f63 (the release is the tag v6.3.4,
51e2dbda0, which adds a last batch to that tree; Changes-Since-6210 section 4e). 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), which carries the same files; what else 6.3.7 changes is not yet reflected here (Upgrading hMailServer 18.4f).
Not Windows? Since 6.3.0 the server itself also runs on Linux, on x86-64 and AArch64, and as a container built from the
.deb. 6.3.7, as 6.3.6 did, carries the x64 and ARM64 (preview) Windows installers, the.deband.rpmfor x86-64 and AArch64, each supported distribution release's own package, both AppImages, the source tarball and the Helm chart; 6.3.4 and 6.3.5 carried the x86-64.deband.rpmonly (Installing on Linux has the links). Everything on this page about DNS, the IP address, port 25, the PTR record and the host name applies unchanged; section 3.1 and the built-in database do not. A Linux server keeps its data in PostgreSQL or MariaDB (there is no built-in database there; a container image reaches MariaDB from the release after 6.3.7, 6.3.7's and earlier carrying PostgreSQL's client alone), has no Control Panel and no COM, and is administered through the REST API, the browser Control Deck andhmctl. Read Installing on Linux or Running in a Container after this page instead of Installing hMailServer.
Work through this before you download anything. Skipping it is the usual cause of a painful first day.
Five minutes with this flowchart will tell you whether the machine in front of you can be a mail server at all, or whether you are heading for the smart-host arrangement in Routes and Relays instead.
flowchart TD
A["64-bit Windows 10 1607 / Server 2016 or newer?"] -->|No| STOP1["Setup refuses to run. MinVersion=10.0.14393"]
A -->|Yes| B["Do you control the domain's DNS?"]
B -->|No| STOP2["Get DNS access first. MX, SPF, DKIM and DMARC all live there"]
B -->|Yes| C["Static public IP?"]
C -->|No| WARN1["Workable but fragile. Dynamic IPs are widely blacklisted"]
C -->|Yes| D["Inbound TCP 25 reaches this machine?"]
WARN1 --> D
D -->|No| E["Relay-only installation: you can send through a smart host but cannot receive directly"]
D -->|Yes| F["Outbound TCP 25 permitted?"]
F -->|No| E
F -->|Yes| G["PTR record requested from your provider?"]
G -->|No| WARN2["Install anyway, but chase it. Google and Microsoft refuse mail from IPs with no matching PTR"]
G -->|Yes| H["Choose a database"]
WARN2 --> H
E --> H
H --> I["Ready to install"]
The hard floor is enforced by the installer, not by advice. section_setup.iss sets
MinVersion=10.0.14393 and section_setup_64.iss sets ArchitecturesAllowed=x64, so on
anything older, or on 32-bit Windows, setup stops with the message from
section_messages.iss:
hMailServer requires Windows 10 version 1607 (build 14393) / Windows Server 2016
or later, 64-bit.
| Requirement | Value | Where it comes from | What happens when it is wrong |
|---|---|---|---|
| Windows version | 10.0.14393 or newer |
installation/section_setup.iss, MinVersion
|
Setup refuses to start. The floor is the .NET 10 Desktop Runtime's own floor, and that runtime is what the database tools need |
| Architecture | x64 only |
installation/section_setup_64.iss, ArchitecturesAllowed=x64
|
Setup refuses to start |
| Elevation | Administrator |
section_setup.iss, PrivilegesRequired=admin
|
Setup will not proceed: it creates a Windows service and writes to HKLM
|
| .NET 10 Desktop Runtime | Installed automatically when missing | bundled windowsdesktop-runtime-10.0-win-x64.exe, section_files_64.iss
|
Without it DBSetup, DBSetupQuick and DBUpdater cannot run, so the database is never created and the service starts against nothing |
| Visual C++ runtime | Shipped app-local (v145) |
Microsoft.VC145.CRT\* copied into {app}\Bin
|
Nothing to install — but never replace those DLLs with older ones; the service crashes on startup |
| The service's account |
NT SERVICE\hMailServer for a new installation since 6.3.4, or LocalSystem if the installer's page is answered so; an upgrade keeps what it had |
the installer's Service account page, /serviceaccount=
|
The virtual account reaches only the folders it is granted. Plan the data, log and backup folders inside the program folder, or approve them for the service when the installer asks; SQL Server with Windows authentication on the same machine needs a login for NT SERVICE\hMailServer first (ServiceAccount.md) |
| RAM | 2 GB minimum, more for a busy server | operational guidance | Thrashing under load. Nothing enforces it |
| Uptime | Always on | operational reality | A mail server that is asleep is a mail server that is losing mail |
Disk. Size for how much mail you will keep, not how much you have today. Two settings decide what the server does when the disk fills, and both are enforced during the SMTP conversation rather than at delivery time:
| Setting | Default | Effect |
|---|---|---|
MinimumFreeDiskSpaceMB |
100 |
Below this, MAIL FROM is answered 452 4.3.1 — a temporary refusal, so the sending server holds the message and retries. No spool file is opened and no recipient is validated |
DiskSpaceWarningThresholdMB |
1024 |
Above the floor but below this, the server logs a warning and keeps accepting mail |
(IniFileSettings.cpp:522-525; both are also in the Settings Reference.)
The mail itself lands under the data directory, one file per message:
C:\Program Files\hMailServer\
├── Bin\ hMailServer.exe, the .NET tools, OpenSSL, libpq, libmysql, hMailServer.INI
├── Data\ ← MESSAGES LIVE HERE. Size the disk for this folder
│ ├── example.com\
│ │ └── alice\
│ │ └── 3f\{3f7c....eml} two-character fan-out folder, then a GUID-named .eml
│ ├── #Public\ public folders, same two-character fan-out
│ └── {guid}.eml messages still in the delivery queue
├── Database\ the built-in database file, hMailServer.sdf
├── DBScripts\ the .sql create and upgrade scripts
├── Events\ EventHandlers.vbs — preserved across upgrades
├── Languages\ Control Panel translations
├── Logs\ hmailserver_*.log
├── Temp\
├── Addons\ DataDirectorySynchronizer, ImportTool
├── ControlPanel\ hMailCP.exe and its .NET dependencies
└── WebAdmin\ the single-page admin app served by the REST listener
(Folder set from installation/section_dirs.iss; message path shape from
PersistentMessage::GetFileName, Common/Persistence/PersistentMessage.cpp:1510-1545.)
Antivirus. Exclude
Data\,Database\andTemp\from real-time scanning. A scanner holding a message file open is a documented cause of delivery that silently does nothing — the server detects one shape of it explicitly and logs error 5760 rather than writing a message with no body (DistributionListSender::LoadedMessageIsGenuine_).
You need a domain you control — yourcompany.com — and the ability to edit its DNS
records. If your domain is with a registrar like Namecheap, Cloudflare, GoDaddy or
123-Reg, you have this.
You will need to publish, at minimum, an MX record and an SPF TXT record, and you
should publish DKIM and DMARC too. The Control Panel generates the exact record text
for each of them and then checks whether it is live: Monitoring & troubleshooting → DNS records.
You cannot do that until the server is installed, but it is worth knowing now that you will
not have to compose those records by hand. See DNS for Your Domain.
This is the step that stops most home installations.
- Your server needs a static public IP. A dynamic home IP will work badly and be widely blacklisted.
- Port 25 inbound must reach your server. Most consumer ISPs block it. Business connections and cloud/VPS providers usually allow it, sometimes on request.
- Port 25 outbound must work too. Many cloud providers (notably Azure and AWS) block outbound 25 by default and require you to ask.
Test both directions before you install — the second one from the server itself, the first from anywhere else:
# Inbound: can the outside world reach port 25 on your IP?
Test-NetConnection -ComputerName 203.0.113.10 -Port 25
# Outbound: can this machine reach someone else's port 25?
Test-NetConnection -ComputerName gmail-smtp-in.l.google.com -Port 25ComputerName : gmail-smtp-in.l.google.com
RemoteAddress : 142.250.153.26
RemotePort : 25
TcpTestSucceeded : True
TcpTestSucceeded : False on the outbound test means port 25 is blocked and you need a
smart host.
The ports you will eventually need open:
| Port | Protocol | Seeded by a fresh install? | Needed for |
|---|---|---|---|
| 25 | SMTP | Yes | Receiving mail from other servers. Without it you receive nothing |
| 587 | SMTP submission | Yes | Your own users sending mail |
| 110 | POP3 | Yes | Legacy clients |
| 143 | IMAP | Yes | Mail clients reading mail |
| 465 | SMTPS, implicit TLS | No — create it yourself | Clients that will not use STARTTLS |
| 993 | IMAPS, implicit TLS | No — create it yourself | The port most mail clients try first |
| 995 | POP3S, implicit TLS | No — create it yourself | Legacy clients over TLS |
The four seeded rows come from CreateTablesMSSQL.sql:1054-1060; the TLS ports are added
on Connections & protocols → TCP/IP ports. Full detail in Ports Reference.
Check before you commit. If your ISP blocks port 25, you cannot receive mail directly. You can still run hMailServer and relay outbound mail through a smart host (Routes and Relays), but inbound mail will not reach you.
Setup itself checks three of these ports. InitializeSetup calls CheckPorts(), a
WinSock bind test in the installer's own code (the unsigned ISC.DLL it used to call was
removed on 11 September 2026), and, when 25, 110 or 143 are already in use while the
hMailServer service is not running, tells you another mail server is on the machine. It is
a warning, not a refusal — but ignore it and two servers will fight over port 25.
What a new installation starts with on these ports (since 6.3.4). The installer gives a database it created a self-signed certificate, offers STARTTLS on 25, 587, 110 and 143, and requires TLS for authentication on the Internet IP range, so a mail client on another machine must start TLS before it sends a password; the webmail or a script on the server itself is unaffected, and mail from other servers is taken with or without TLS as before. Mail clients warn about the self-signed certificate until you replace it with one from ACME or your own (Encryption and Certificates). An upgraded server keeps its listeners and ranges as they were (SecureDefaults.md).
Your IP address must resolve backwards to your mail server's name. If mail.example.com
is 203.0.113.10, then 203.0.113.10 must resolve back to mail.example.com.
Only your ISP or hosting provider can set this — it is not in your domain's DNS. Ask them. Many large providers (Google, Microsoft) reject mail from IPs with no matching PTR record, so this is not optional.
Check what is there today:
Resolve-DnsName -Type PTR 10.113.0.203.in-addr.arpaName Type TTL Section NameHost
---- ---- --- ------- --------
10.113.0.203.in-addr.arpa PTR 3600 Answer mail.example.com
DNS name does not exist means there is no PTR record, and you should open a ticket with
whoever owns the IP address before you go live. Note the reversed octets: 203.0.113.10
becomes 10.113.0.203.in-addr.arpa.
hMailServer stores accounts, domains, message metadata and settings in a database. The
message bodies are files on disk (§3.1), not rows — so the database stays small relative
to Data\.
You have four choices. The installer's database page asks only "built-in or external"; if
you pick external, DBSetup.exe runs after the file copy and asks which external engine,
for the host, database name and credentials.
| Database |
[Database] Type in the INI |
Good for | What is bundled | What you must have first |
|---|---|---|---|---|
| Built-in (SQL Server Compact 4.0 SP1) | MSSQLCE |
Getting started; small installations |
SSCERuntime_x64-ENU.msi, installed by setup |
Nothing. This is the default |
| MySQL / MariaDB | MYSQL |
Most production use | MariaDB Connector/C 3.4.9 as Bin\libmysql.dll, plus its authentication plugins under Bin\plugin\
|
A reachable server - MySQL 5.7.9 or MariaDB 10.2.2 or later, since every table is utf8mb4 from 6.3.4 - and a login with every privilege on the database's name; DBSetup creates the database itself and refuses a name that exists |
| Microsoft SQL Server | MSSQL |
Windows shops that already run it | Nothing — uses the OS's own data stack | A reachable server, Express edition included, and a login allowed to create a database (dbcreator); DBSetup creates the database itself and refuses a name that exists |
| PostgreSQL | PostgreSQL |
Larger installations |
libpq from PostgreSQL 18.6 since 6.3.6 (18.3 up to 6.3.5) |
A reachable server and a login allowed to create a database (CREATEDB); DBSetup creates the database itself and refuses a name that exists |
(Type strings from IniFileSettings.cpp:129-136; bundled clients from
installation/section_files_common.iss and section_files_64.iss. Versions cross-checked
in Third-Party Binaries.)
Encryption to the database (since 6.3.4): MySQL and MariaDB are reached over TLS
whenever the database server offers it, the certificate unchecked; SQL Server through the
Microsoft OLE DB Driver (MSOLEDBSQL) encrypts the whole session; PostgreSQL is as it was.
[Database] TlsMode=verify-full with TlsCaFile requires TLS and checks the certificate
(DatabaseTls.md). Before 6.3.4 a MySQL or
MariaDB connection through the bundled client was never encrypted.
If in doubt, take the built-in database. You can migrate later — see Migrating the Database Backend — and for anything up to a few dozen mailboxes it is entirely adequate.
Two things about the built-in engine are worth knowing before you choose it:
-
It runs on a single database connection.
IniFileSettings::LoadSettingsforcesNumberOfConnectionsto 1 forMSSQLCE, with the comment "SQL CE is supposed to be ACID, robust and so on but isn't really". That is fine for small installations, and it is the first thing to change if the server feels slow under concurrency. -
Microsoft has withdrawn the SQL Server Compact download. The copy in
installation/SQLCE/is the archive of record (see Third-Party Binaries). It still installs; there is simply nowhere upstream left to fetch it from.
What the installer leaves in Bin\hMailServer.INI for the built-in engine:
[Database]
Type=MSSQLCE
Database=hMailServer
Server=
Username=
Password=<encrypted>
PasswordEncryption=6
Port=0
Internal=1The password for the built-in database is generated randomly by the server
(InterfaceDatabase::CreateInternalDatabase) — you never see it and never need it.
PasswordEncryption=6 is DPAPI, machine-scoped, so the value cannot be decrypted on
another machine; it falls back to the legacy Blowfish scheme (1) only when
ProtectStoredSecretsWithDPAPI is turned off. That machine scope matters for
Backup and Restore: a restored INI on a different machine cannot decrypt it.
Plan where the stored-secrets key will be kept (since 6.3.4). A new installation
makes a key that seals each account's second factor and the secret settings in the
database, and keeps it in hMailServer.INI alone - never in the database or a backup. The
installer asks you to export it; keep that file with the database backups, stored apart from
them, or a database restored on another machine opens none of those secrets
(SecretsAtRest.md).
Pick the name your mail server will be known by — conventionally mail.yourcompany.com.
Write it down. It is used in five places that must all agree:
| Where | What it is | What happens when they disagree |
|---|---|---|
Your domain's MX record |
Where other servers send your mail | Mail does not arrive |
The PTR record on your IP |
The reverse lookup | Google and Microsoft refuse or spam-file your mail |
| Your TLS certificate's subject | The name clients verify | Clients warn, or refuse to connect |
| Connections & protocols → Protocols → SMTP → Host name (HELO/EHLO greeting) | What you announce in the 220 banner and in HELO/EHLO
|
Receiving servers score you up as spam; some refuse outright |
| Your mail clients' server setting | What users type | A certificate warning for every user, every time |
Since 6.3.4. The shipped defaults suit one kind of deployment, and the thirty or so settings that make a server a different kind used to be found one page at a time. A setting profile is those settings, named, and the installer offers four on its last page, for a new installation only:
| Profile | For |
|---|---|
office |
One server that receives an office's mail from the Internet, 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: the gateway's addresses trusted, greylisting off |
relay |
An outbound relay for applications and other servers 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 |
None - the shipped settings - is chosen until you pick another, and a silent install
takes /profile=NAME. A profile shows the difference from this server before it changes
anything, saves what it replaces and can be put back, so it can equally be chosen later
from the Control Panel's Setting profiles page or the Control Deck's checklist.
Profiles and Environment has what each profile sets.
After the installation, a first-hour checklist the server judges for itself - a
profile, a domain, an account, TLS on the submission port, passwords only over TLS, SPF,
DKIM, DMARC, a backup destination, a second factor for the administrator, the stored-secrets
key and the account the service runs as - is the Control Deck's Checklist
view and heads the Control Panel's External setup page and its dashboard's "needs
attention" card. The Deck's checklist and the Control Panel's Welcome page also carry a
button that makes a throwaway example.test domain to learn on
(Your First Domain and Mailbox).
- Windows machine, 64-bit, build 14393 or newer, always on - or a Linux machine on x86-64 or AArch64 (6.3.6 and 6.3.7 carry both; 6.3.4 and 6.3.5 had x86-64 only) with PostgreSQL or MariaDB to hand (Installing on Linux)
- Administrator access to the machine
- Domain name with DNS access
- Static public IP
- Port 25 open inbound and outbound, both tested (§3.3)
- Ports 587, 143 and 993 planned for your users
- PTR record requested from your provider
- Host name chosen (
mail.yourcompany.com), and the same name planned for the MX record, the PTR record and the TLS certificate - Database chosen; if external, the server is reachable and the login may create the database, which DBSetup makes - an empty database made beforehand is refused (Migrating the Database Backend, step 3)
- Antivirus exclusions planned for
Data\,Database\andTemp\ - An administrator password chosen and in your password manager — setup asks for it, it must be at least five characters, and it is the master password for the whole server
- The kind of server it is (§3.7), if not the shipped defaults
- The service's account:
NT SERVICE\hMailServerfor a new installation, unless something it would need - a folder outside the program folder, SQL Server with Windows authentication - is planned for first (§3.1) - Somewhere to keep the exported stored-secrets key, apart from the database backups (§3.5)
Next: Installing hMailServer.
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