Skip to main content

The Mailezine Engine

Mailezine is Mailez's first-party mail engine: a single binary with pluggable storage. It is the only engine across every tier (dev / community / enterprise) — protocol capabilities and mail features are identical between editions; the editions differ only in storage scale and licensed features.

Relationship Between Editions

CommunityEnterprise
EngineMailezine (the same binary)Mailezine (the same binary)
StoragePebble KV + local-FS blob (single node)TiDB KV + MinIO/S3 blob (distributed)
Gatewaynginx for HTTP/ACME onlysame
Mail portsPublished by the engine, built-in implicit TLS (465/993/995)same
PlatformsNative Linux / macOS / Windowssame
ScalingObject-storage elasticity, multi-instance HA, TiDB horizontal scaling

Both editions share the same backend control plane (directory / auth / admin console / Webmail). Traditional Postfix + Dovecot deployments migrate in place with mailezine migrate.

Design Principles

  • Single binary — one executable contains everything
  • Pluggable storage — pebble (local / single node) / tidb (distributed) + S3/MinIO blob
  • All protocols in-house — SMTP / IMAP / POP3 / ManageSieve, with MIT libraries such as go-msgauth
  • One engine — community and enterprise run the same code; upgrades only touch storage and licensing

Current Status

Completed:

  • ✅ SMTP send/receive / validation / spam filtering / local delivery / outbound queue (incl. SRS, rate limiting)
  • ✅ IMAP read path (CONDSTORE / SORT / ACL / ID / QUOTA)
  • ✅ POP3 / ManageSieve / Sieve executor
  • ✅ Pebble / TiDB KV + MinIO/S3 blob storage loop
  • ✅ Full-text search (bleve) + Tika attachment text extraction (PDF / Office / ODF)
  • ✅ Two clustering shapes (enterprise): active-passive lease failover, or the multi tier's fully multi-active engine — every replica serves every account; per-message transactional delivery claims with crash-takeover, cross-node singleton leases, per-node FTS convergence and per-account write pinning, verified by a real two-process kill -9 failover drill; implicit TLS
  • ✅ Archive capture and outbound DLP approval (wired to the control plane)
  • ✅ One-way traditional-architecture (Postfix+Dovecot / Maildir) → Pebble/TiDB migration tool
  • ✅ Full test suite green on all three platforms (Linux/macOS/Windows)

Benchmarks (10,000-user enterprise load)

Measured on the same machine in the same session (September 2026 re-run); the "traditional stack" column is the Postfix + Dovecot architecture running side by side, each stack paired with its control plane:

MetricTraditional stack (postdove)MailezineGainWhat it means
Inbound throughput3.1 msg/s13.6 msg/s4.4×3.4× more mail per second on the same hardware
Inbound p506.19 s1.35 s4.6×New mail arrives near-instantly
Submission throughput2.2 msg/s6.8 msg/s3.1×Bulk outbound queues drain comfortably
IMAP FETCH p5035.97 ms20.96 ms1.7×Snappier reads; long lists scroll smoothly
Queue delivery2.1 msg/s7.2 msg/s3.4×Fewer bounces and delayed deliveries
Enqueue→delivery p5035.6 s5.30 s6.7×Nearly seven times faster end-to-end delivery
Queue backlog122 msgs0 msgszeroZero backlog under load
Idle memory (full stack)~162 MiB~6.4 MiB1/25Runs comfortably on small hosts
Peak load memory~270 MiB~73 MiB1/3.7Memory stays flat through mail floods

Standalone Development

# 1. Prepare the dev directory and password stubs
$env:MAILEZINE_DIRECTORY_FILE = "internal/directory/testdata/dev-directory.json"
$env:MAILEZINE_AUTH_DEV_FILE = "internal/auth/testdata/dev-passwords.json"

# 2. Start (listens on :11480 health endpoint by default)
go run ./cmd/mailezine
# Also listens on :1025 (SMTP inbound), :1587 (Submission), :1143 (IMAP),
# :10110 (POP3), :11490 (ManageSieve)

# 3. Verify
curl http://127.0.0.1:11480/health

# 4. End-to-end smoke test (local delivery + relay enqueue)
go test ./cmd/mailezine -run TestEndToEnd -v

Configuration

Everything can be overridden via environment variables (or a TOML overlay file via MAILEZINE_CONFIG):

VariableDefaultDescription
MAILEZINE_STORAGE_BACKENDpebblepebble | tidb
MAILEZINE_ROCKS_PATHPebble KV path (required)
MAILEZINE_STORAGE_DSNTiDB DSN (required for tidb)
MAILEZINE_S3_ENDPOINTemptyS3/MinIO blob; empty = local FS
MAILEZINE_S3_ACCESS_KEY / MAILEZINE_S3_SECRET_KEY / MAILEZINE_S3_BUCKETS3 credentials and bucket
MAILEZINE_BLOB_COMPRESSIONfalseCompress blobs at rest (text compresses 60–80%)
MAILEZINE_FTS_ENABLEDfalseEnable bleve full-text search
MAILEZINE_FTS_TIKA_URLemptye.g. http://tika:9998; enables attachment text extraction
MAILEZINE_HA_ENABLEDfalseMulti-instance active-passive HA
MAILEZINE_HA_LEASE_PATHemptyShared lease file; empty = S3 bucket lease
MAILEZINE_CLUSTER_MODEsinglemulti = fully multi-active engine (requires TiDB; mutually exclusive with HA)
MAILEZINE_CLUSTER_NODE_IDautoMulti-active node identity (leave empty under compose replicas)
MAILEZINE_QUEUE_CLAIM_LEASE_SECONDS600Multi-active delivery-claim lease (must exceed the slowest single delivery)
MAILEZINE_ACCOUNT_GATE_ENABLEDtrueMulti-active per-account write pinning (advisory; proceeds after the bounded wait)
MAILEZINE_ARCHIVE_ENABLED / MAILEZINE_ARCHIVE_URLfalse / emptyArchive capture, forwarded to the control-plane archive store
MAILEZINE_DLP_ENABLED / MAILEZINE_DLP_URLfalse / emptyOutbound DLP scan + approval; fails open
MAILEZ_LICENSE_FILEemptyEnterprise license file (platform-level; unset = development edition, unlimited mailboxes)
MAILEZ_LICENSE_REQUIREDfalseWhen true, a missing or invalid license refuses startup
MAILEZINE_DIRECTORY_FILE / MAILEZINE_AUTH_DEV_FILEDev-mode directory / password stubs
MAILEZINE_BACKEND_ADDRESS127.0.0.1:8080Backend control-plane address
MAILEZINE_STACK_SECRETemptyShared secret for the control-plane /stack API
MAILEZINE_HOSTNAMEhostnameEHLO / Authentication-Results hostname
MAILEZINE_RSPAMD_URLemptyEnterprise high-tier anti-spam: e.g. http://mail-filter:11333/checkv2; takes precedence over the built-in baseline when set
MAILEZINE_JUNK_ENABLEDtrueBuilt-in baseline anti-spam (community default tier): auth-results scoring + DNSBL + sender lists; yields automatically when Rspamd is configured
MAILEZINE_JUNK_HEADER_SCORE / MAILEZINE_JUNK_REJECT_SCORE4.5 / 12Score thresholds for X-Spam headers / MTA rejection (deliberately lenient)
MAILEZINE_JUNK_RBLSbl.spamcop.netComma-separated DNSBL zones; empty disables DNSBL queries
MAILEZINE_JUNK_WHITELIST / MAILEZINE_JUNK_BLACKLISTemptyFull addresses, bare domains or @domain, comma-separated
MAILEZINE_JUNK_GREYLISTfalseGreylist first-seen senders scoring in the ambiguous band (retries within an hour pass)
MAILEZINE_SMTPS_ADDR / MAILEZINE_IMAPS_ADDR / MAILEZINE_POP3S_ADDRemptyImplicit-TLS ports (requires certificates)

Migration Tool

To migrate a traditional architecture (Dovecot Maildir storage) into KV storage, use mailezine migrate:

# maildir → pebble (local KV)
go run ./cmd/mailezine migrate --src /var/vmail --dst /var/lib/mailezine

# maildir → tidb (distributed KV, optional S3 blob)
go run ./cmd/mailezine migrate --src /var/vmail --to tidb --dsn "root:@tcp(127.0.0.1:4000)/mailezine"

Migration preserves per-mailbox order, flags, keywords and internal dates; UIDs/UIDVALIDITY are re-allocated per store invariants and clients resync per RFC 3501. --dry-run scans and counts without writing. The maildir reader is POSIX-only; other platforms get a stub that explains the constraint.

Licensing (Enterprise)

The enterprise edition is controlled by an offline signed license file (Ed25519). The license is a perpetual software right: it carries edition (enterprise) and max_mailboxes (the mailbox/user cap, enforced forever) with no expiry. Without a license it runs as the development edition (unlimited). Production deployments mount the license file and set MAILEZINE_LICENSE_REQUIRED=true; a missing or invalid license refuses startup. Licenses are issued by Mailez HQ (cmd/license), and the admin console enforces the same mailbox cap when creating mailboxes.

Annual technical service (support, SLA, launch assistance) is a separate subscription decoupled from the license, loaded via MAILEZ_SERVICE_FILE (issued with cmd/license service issue). Service certificates can be mounted by both the community and enterprise editions — they represent support entitlement, never software gating.