Going to Production: Hardware Sizing and Domain DNS
Quick Start gets the system running; this guide covers two things you must do before production: choosing the right server, and setting up the DNS records for your mail domain.
Hardware and System Requirements
OS and Software
- Production deployment: a Linux server (x86_64 / aarch64 both fine) with
Docker (Compose v2). All four production stacks (ce / ee / multi / ha) are
fully containerized and managed by
mailezctl; the distribution'sinstall.shalso offers an interactive installer (pre-checking Docker, Compose v2, openssl, curl). - Development experience: the engine and control plane run natively on Linux / macOS / Windows with no restrictions on the dev machine; the Go toolchain (1.26+) is only needed when building images from source.
- Time sync: enable NTP. The lease mechanism of multi-instance HA / multi-active clusters is sensitive to clock skew; keep single-node deployments time-synced too (scheduled sending and log troubleshooting rely on accurate clocks).
Sizing
The mail stack itself is light: a single Mailezine engine instance idles at about 24 MiB of memory and peaks around 34 MiB under a 10k-user load model (internal benchmark). The bulk of system resources goes to the control plane and infrastructure components (MySQL, TiDB, Rspamd, MinIO). The table below lists recommended starting points — pick a stack by mailbox count:
| Scenario | Stack | vCPU | Memory | Disk (SSD) |
|---|---|---|---|---|
| Personal / trial / demo | dev or ce | 1–2 | 2 GiB | 20 GB |
| Small team (≤ 50 mailboxes) | ce | 2 | 4 GiB | 100 GB |
| Mid-size org (≤ 500 mailboxes) | ce or ee, single node | 4 | 8–16 GiB | sized by quota |
| Scale-out (ee + multi/ha) | components on separate nodes | 4+ per node | 8 GiB+ per node | sized by quota |
Disk estimation: each mailbox defaults to a 1 GiB quota (adjustable per user or per domain in the admin console), plus headroom for full-text search indexes, logs, and attachment staging. Large message blobs and cloud-drive files should land in MinIO/S3 object storage (Enterprise), keeping only hot data on local disk.
Network and Ports
The server needs a public IP with the following ports open:
| Port | Purpose | Exposure |
|---|---|---|
| 25 | SMTP (server-to-server inbound) | inbound public; outbound see below |
| 465 / 587 | Client sending (SMTPS / Submission) | public (for mail clients) |
| 110 / 995 | POP3 / POP3S | public (if using POP3) |
| 143 / 993 | IMAP / IMAPS | public (for mail clients) |
| 4190 | ManageSieve (filter sync) | public (if clients manage Sieve) |
| 80 / 443 | Gateway: web entry + ACME auto certificates | public |
| 8081 / 8082 / 8083 | Backend API / admin console / webmail | internal only or behind the gateway reverse proxy; do not expose directly |
Cloud providers usually block outbound port 25 by default (anti-spam): either request an unblock from your provider, or configure an external SMTP relay (smarthost, SASL auth supported) in the admin console so outbound mail is delivered through the relay; for forwarding scenarios the engine rewrites envelopes with SRS automatically, so bounces never return to your domain.
Domain DNS Setup
Using mail domain example.com and mail host mail.example.com (i.e.
MAILEZ_HOSTNAMES) as an example. All records are added at your DNS
provider:
| Type | Host | Value | Purpose | Required? |
|---|---|---|---|---|
| A / AAAA | mail | server public IP | host name clients connect to and MX points to; also required for ACME issuance | ✅ required |
| MX | @ | mail.example.com (priority 10) | routing rule for other servers delivering *@example.com | ✅ required |
| TXT (SPF) | @ | v=spf1 a mx -all | declares "only this host may send for me"; receivers use it to prevent spoofing | ✅ strongly recommended |
| TXT (DKIM) | <selector>._domainkey | v=DKIM1; k=rsa; p=<public key> | outbound signing public key; generate in the admin console and copy the full record | ✅ strongly recommended |
| TXT (DMARC) | _dmarc | v=DMARC1; p=quarantine; rua=mailto:postmaster@example.com | tells receivers what to do when SPF/DKIM fails and where to send reports | ✅ strongly recommended |
| PTR (rDNS) | server IP | mail.example.com | reverse DNS; set at your cloud/ISP provider, not the DNS provider | ⭐ strongly affects deliverability |
| CNAME (optional) | autodiscover | mail.example.com | Enterprise Outlook / Exchange ActiveSync autodiscovery | optional |
Notes:
- DKIM: generate the key in the admin console under "Domains → DKIM";
the page shows the exact record name and value, ready to copy into DNS.
The selector defaults to
dkim(changeable viaMAILEZ_DKIM_SELECTOR), so the record looks likedkim._domainkey.example.com. Regenerating rotates the key (in-flight mail during the switch window may fail DKIM — expected). - SPF:
a mxcovers both sending paths (mail host A record + MX target); if you also send through a relay provider, appendinclude:per their docs. On the inbound side, the engine runs full SPF / DKIM / DMARC verification on every incoming message and emits Authentication-Results, regardless of whether you publish these records — publishing them protects the mail you send out. - PTR reverse DNS: most receivers' anti-spam systems (including mailezine's built-in reputation scoring) check that the sending IP's PTR matches the EHLO host name. Mail from a public IP without a PTR easily lands in spam; configure it in your cloud console before going live.
- TLS certificates: with
MAILEZ_TLS=letsencryptthe gateway obtains and renews certificates automatically (requires 80/443 reachable and themail.example.comA record in effect); you can also place your owncert.pem/key.pem(see the repo'sdeploy/certs/README.md). Implicit TLS on 465/993/995 reuses the same certificates. - Verification: after saving records, confirm they have propagated
globally with
dig/nslookup(dig MX example.com,dig TXT dkim._domainkey.example.com); the admin console's DKIM status turns verified once DNS propagates. Then exchange a test message with an external mailbox (Gmail, QQ Mail, etc.) and check the Authentication-Results the recipient shows:spf=pass dkim=pass dmarc=pass. An online mail health-check service works well for a comprehensive audit too.
Production Checklist
- Server meets the sizing guidance, NTP enabled, Docker + Compose v2 ready
- Public IP ready, outbound 25 unblocked or relay configured
-
mailez.envsetsMAILEZ_SECRET_KEY/MAILEZ_STACK_SECRET/MAILEZ_DOMAIN/MAILEZ_HOSTNAMES(production refuses placeholder secrets) - DNS: A / MX / SPF / DKIM / DMARC in effect, PTR configured at the cloud provider
- Ports: mail ports open to the public, admin ports not exposed
- TLS:
MAILEZ_TLS=letsencrypt(or your own certs), implicit TLS handshakes on 465/993/995 - Admin account created (
mailez-seed), default password changed - Backups: config export + engine
backup(full KV+blob export) in routine ops - Enterprise:
MAILEZ_LICENSE_FILEmounted, license shown as valid on the overview page
For scale-out operations details see the repo's docs/scaling.md; upgrade
procedures are in docs/upgrades.md and docs/rollout-runbook.md.