NodeMailServer
KumoMTA

KumoMTA configuration

Listener, users, domains, DKIM key sources, sending IPs, queue rates, spool and webhooks.

Settings come from outbound/.env (see Environment variables) and from the files in outbound/policy/.

SMTP listener

init.lua starts one SMTP listener:

SettingValue
Address0.0.0.0:587
HostnameKUMOMTA_HOSTNAME (default mail.enjoys.in)
Relay hosts127.0.0.1, ::1, 10.0.0.0/8, 172.16.0.0/12 (Docker) and 192.168.0.0/16

An HTTP listener for metrics and the API runs on 127.0.0.1:8000.

AUTH only works after STARTTLS

KumoMTA accepts SMTP AUTH only on a TLS-protected connection. Clients must use STARTTLS on port 587. Until you set tls_certificate and tls_private_key on the listener, KumoMTA uses a self-signed certificate, which strict clients will reject.

Users

outbound/policy/users.lua maps a username to a password. It is read on every login, so you can edit it without restarting.

return {
  ["user1"] = "change-me",
}

Passwords are stored in plain text. For production, keep them in a secrets store or compare hashes.

Messages are only accepted from clients that logged in: smtp_server_rcpt_to rejects every recipient with 550 5.7.1 Authentication required for an unauthenticated session.

Sender and recipient domains

Two files list domains, and both currently contain the same two:

FileUsed for
domains.luaThe sender domains that may send when USE_RELAY=true.
listener_domains.tomlDomains that accept relayed mail (relay_to = true), and the default of logging bounce reports (log_oob) and feedback-loop reports (log_arf).

Replace the domains in both with your own.

DKIM keys

dkim.lua takes the private key from one of three places, chosen by DKIM_BACKEND:

BackendWhere the key comes from
file/opt/kumomta/etc/dkim/<domain>/<selector>.key. Mount your keys there.
httpGET $DKIM_HTTP_URL?domain=<d>&selector=<s> with the header X-API-Key: $DKIM_API_KEY.
redisThe key <domain>::pvt::key in the Redis server at REDIS_HOST.

The domain is read from the message's From header, and the selector is DKIM_SELECTOR. A key is looked up once and then reused for 5 minutes, so a new key takes up to 5 minutes to be used. If no key is found, the message is sent unsigned and a warning is logged.

DKIM only runs with USE_RELAY=true

With USE_RELAY=false, dkim.lua is not loaded and mail leaves unsigned. Set USE_RELAY=true to sign, and list your sender domains in domains.lua.

Sending IPs

egress.lua builds an egress pool called main-pool from KUMOMTA_SOURCE_IPS, a comma-separated list. Each IP becomes a source named source-1, source-2 and so on, and announces KUMOMTA_HOSTNAME in its EHLO. If the variable is unset, KumoMTA sends from the default route.

When you use several IPs, give every one a PTR record that matches KUMOMTA_HOSTNAME.

Queues and rate limits

queue.lua creates a queue for each recipient domain, all using main-pool.

Recipient domainMessage rate
gmail.com, googlemail.com200 per minute
yahoo.com, ymail.com100 per minute
outlook.com, hotmail.com, live.com, msn.com60 per minute
Everything else300 per minute
Retry settingValue
First retry1 minute
Longest wait between retries4 hours
Give up after24 hours

Spool and logs

WhatWhere
Message data/var/spool/kumomta/data
Message metadata/var/spool/kumomta/meta
Logs/var/log/kumomta, in 30 second segments

The compose file keeps /var/spool/kumomta and /var/log/kumomta in Docker volumes.

Webhooks

When WEBHOOK_URL is set, webhook.lua posts log events to it as JSON. Each event includes these headers from the message: Subject, From, To and Message-ID. Leave WEBHOOK_URL unset to turn webhooks off.

Record types include Reception, Delivery, Bounce, TransientFailure, Expiration, OOB and Feedback. See the KumoMTA log record reference for the full list.

If your endpoint is down, KumoMTA keeps the events in a queue and retries, starting after 1 minute and backing off to 20 minutes between attempts.

On this page