Skip to main content

Mail

Applies to: SimpleTwo 0.9.x, mail 0.43 · Checked: 27.09.2026

SimpleTwo mail is two roles. mail holds the mailboxes, the queue and the database; clients connect to it. mx is the edge: it takes mail from the internet, sends mail out, signs it with DKIM and checks what arrives. The mx nodes keep no database and no mailboxes, only a queue on their own disk. Between the two are LMTP (on mail) and port 2525 (on mx), closed to anyone but each other.

Before the MX record

Until DNS has an MX record pointing at an mx node, no mail reaches you from the internet — and that is right until somebody is named to answer abuse reports (the abuse@ and postmaster@ addresses). Make them aliases in identity for real people before you publish the MX record.

1. DNS records and DKIM keys​

Console → Mail → Mail DNS shows each mail domain's records — MX, SPF, DMARC, DKIM, SRV, MTA-STS and TLS-RPT — and checks each one in DNS.

The coordinator makes the DKIM keys: an ed25519 and an RSA 2048 pair per domain. Changing a key takes three steps:

  1. New DKIM key makes a new pair; publish its two records.
  2. Activate the new key is available only once the new records answer in DNS.
  3. The old pair is retired; its records may go seven days later, on the date the card shows.

2. Devices without a password​

Printers, an ERP or a monitoring system that cannot sign in are set up in Console → Mail → Mail devices: a name, the networks they connect to mx port 25 from, the addresses they may write as, and where to (inside the organisation only, or anywhere). Everything else signs in with an app password on ports 587/465.

3. Content filters​

The filters are the MX_FILTERS variable on the mx node, a JSON list in the order they check:

[
{"name": "rspamd", "transport": "milter", "address": "inet:127.0.0.1:11332", "on_error": "open"},
{"name": "av", "transport": "icap", "address": "icap://av.corp.example:1344/respmod", "on_error": "closed"}
]
  • milter — rspamd, clamav-milter, spamass-milter. A message the filter marks as spam (X-Spam: Yes and the like, the spam_signal field) goes to Junk; the filter's fields are in the message's delivery headers, and the message's bytes are never changed.
  • icap — an anti-virus over RFC 3507. How the product says it found something is the verdict field (headers, header_patterns, on_modified_body, status_codes).
  • on_error — what a filter that does not answer means: open lets the message through without it (the anti-spam default), closed tells the sender 451 to try again later (for an anti-virus).
  • on_virus — an anti-virus's find: quarantine (ICAP's default) or reject.

A list that does not parse stops the service: a filter configured and quietly not run is mail nobody checked. Greylisting is rspamd's greylist module with a Redis shared by every mx node; mx keeps no greylist of its own.

4. DNS block lists​

Every client of port 25 is checked against MX_DNSBL_ZONES (default zen.spamhaus.org). A listed client is told 554 5.7.1 … blocked using <zone> at every MAIL. Addresses in MX_DNSWL_ZONES are not checked.

Each zone tests itself at start and hourly. A zone that stops answering as it should is disabled, and the mx node's /healthz says why. The usual cause is a query through a public resolver, which Spamhaus refuses: the node's resolver must be its own. Commercial use of Spamhaus needs a DQS key.

5. The quarantine​

A message in which the anti-virus found a virus, and one a filter quarantined, is held on the server. The sender is told it was accepted. Each recipient gets a notice from the postmaster: who sent it, the subject, the date, the reason, and the number to give the administrator.

Console → Mail → Quarantine lists the held messages. Only an administrator releases one to its recipients or deletes it, and each action goes into the audit log with the administrator's name. What nobody decides on is deleted after 30 days (MAIL_QUARANTINE_DAYS).

6. Groups with members outside​

When a group has outside addresses (partners), each gets a copy of its own. The copy's reverse-path is the group's service address, sales+bounce.<token>@corp.example, so an outside recipient's refusal comes back to the group, not to whoever wrote to it.

  • A bounce is logged on the copy's path in the delivery log, and kept in the domain's postmaster@ mailbox when there is one.
  • Never passed outside: delivery notices, messages judged spam, held messages, and all of a group's mail when the installation has no mx node.
  • After five bounces in a row (each within a week of the last) a member outside is disabled: its copies stop and the log says why. An administrator can enable it again.
  • When a sender signs with SPF alone and its domain has p=reject, a recipient outside may refuse the copy. That is a known limit of mailing lists.

7. MTA-STS​

When a recipient's domain publishes an MTA-STS policy in enforce mode, mx sends it mail only to the servers the policy lists, only over TLS, and only to a certificate valid for the server's name. When that cannot be done, the message is not sent in the clear: it waits and is tried again. The policies are kept on the mx node's disk; /healthz counts them.

Your own domain's policy is published by the coordinator. Mail DNS has three records for it:

  • _mta-sts.<domain>: a TXT record with the current policy's id. The id changes with the policy, and the record must then be updated.
  • mta-sts.<domain>: a CNAME to the coordinator. The coordinator obtains the certificate for this name itself and serves the policy at https://mta-sts.<domain>/.well-known/mta-sts.txt. The policy lists every mx node.
  • _smtp._tls.<domain>: a TXT record for TLS-RPT reports, sent to tls-reports@<domain>. Make that address an alias for whoever reads the reports.

The policy's mode is chosen on the same card. Start with testing: senders report failures but still deliver. Turn on enforce once a week of reports shows none. Under enforce a sender keeps the policy for a week and sends only to the nodes it lists. It takes a new mx node once it sees a new id in _mta-sts, so update that record as soon as you add a node.

8. The delivery log​

Any message's path — from mx to a mailbox or to a remote server — is found by either side's queue number or by address. The mx events wait on the node's disk and reach the log even if the mail cluster was away.