Draft: Full mail server
This MR extends the existing mail-server
SR to a full mail server bundle, including:
- a user database (including aliases) backing both Postfix and Dovecot, that can be populated using shared instances (previously using Postgres, now using plain text per JP request)
- a preconfigured Snappymail webmail (using the
apache-php
component) - the configuration needed to interact with the outside world
The last point revolves around two facts:
- that we can't assume the machine hosting the instance to have a public IPv4 address, which is unfortunately still a requirement for receiving and sending mail since numerous providers can't handle IPv6 yet.
- even if the machine had an IPv4 address, we can't rely on it to send mail: most providers use proprietary IP range lists for spam management, so reliable mail posting must be done through some kind of trusted relay. This can be done using third-party services such as Scaleway, Sendinblue or Rapidmail. Currently, SMTP2GO free tier is used.
A second SR is also included: mail-server-relay
which only contains a Postfix server that acts as the middleman between the mail backends and a third-party mail delivery service. This allows using a single delivery service for multiple domains hosted on different servers, all handled in SlapOS.
State of things
Currently:
- relay and mail domains are configurable
- accounts are configured as shared instances (passwords are set through a link + token. this is unfinished and the way tokens are generated an updated will be redone)
- network components (Postfix, Dovecot, Apache) are monitored and configurable
- aliases are not implemented yet. They will be handled as shared instances too, but the exact details have not yet been decided
On the relay side, backends and domains are set in the instance configuration. Ultimately this will be done with shared instances too: the mail backends will request slaves from the relay. DNS configuration (MX records), however, will probably remain manual.
MR is WIP draft. Commits have been squashed multiple times, will squash and reorder ultimately.
Questions:
- is a domain-per-backend setup what we want? This would mean that when requesting an account (as a shared instance) we need to choose which node this instance will live in (the one hosting the mail server). Otherwise we'd get accounts in the wrong servers.
- receiving mails from the outside requires port 25 to be open on the
mail-server-relay
instance. This can be complicated if it's living on a Rapid.space instance. On the current testing setup this is on an OVH VPS
Example setup
- two domains:
mail1.example.com
andmail2.example.com
, each with a MX pointing to the IPv4 ofmailrelay.lan
- a third-party relay:
3rdpartyrelay.com
configured with the IP (4 or 6) ofmailrelay.lan
- two
mail-server
instances:maildemo1.lan
andmaildemo2.lan
(handling their respective domain) - one
mail-server-relay
instance:mailrelay.lan
configured with both domains and their server's domain name, and the relay's domain name
flowchart LR;
Dom1["mail1.example.com (MX)"]:::mxDomain;
Dom2["mail2.example.com (MX)"]:::mxDomain;
Relay["mailrelay.lan"]:::relay;
Gmail["gmail.com"]:::remoteAddr;
Hotmail["gmail.com"]:::remoteAddr;
Third["3rdpartyrelay.com"]:::extRelay;
Demo1["maildemo1.lan"]:::backendServer;
Demo2["maildemo2.lan"]:::backendServer;
Hotmail -->|sends mail to| Dom1;
Hotmail -->|sends mail to| Dom2;
Dom1 -->|MX points to| Relay;
Dom2 -->|MX points to| Relay;
Relay -->|forwards outbound to 3rd party| Third;
Third -->|delivers to external server| Gmail;
Relay <-->|handles mail1.example.com| Demo1;
Relay <-->|handles mail2.example.com| Demo2;
classDef localAddr fill:#e0f7fa,stroke:#006064;
classDef remoteAddr fill:#f1f8e9,stroke:#33691e;
classDef backendServer fill:#fff3e0,stroke:#e65100;
classDef relay fill:#fce4ec,stroke:#880e4f;
classDef extRelay fill:#ede7f6,stroke:#311b92;
classDef mxDomain fill:#e8eaf6,stroke:#3f51b5;
Example mail paths
From alice@mail1.example.com to bob@mail1.example.com:
flowchart LR;
A["alice@mail1.example.com"]:::localAddr;
B["maildemo1.lan"]:::backendServer;
C["bob@mail1.example.com"]:::localAddr;
A -->|SMTP submission| B;
B -->|Local delivery| C;
classDef localAddr fill:#e0f7fa,stroke:#006064;
classDef remoteAddr fill:#f1f8e9,stroke:#33691e;
classDef backendServer fill:#fff3e0,stroke:#e65100;
classDef relay fill:#fce4ec,stroke:#880e4f;
classDef extRelay fill:#ede7f6,stroke:#311b92;
From alice@mail1.example.com to charlie@mail2.example.com:
flowchart LR;
A["alice@mail1.example.com"]:::localAddr;
B["maildemo1.lan"]:::backendServer;
C["mailrelay.lan"]:::relay;
D["maildemo2.lan"]:::backendServer;
E["charlie@mail2.example.com"]:::localAddr;
A -->|SMTP submission| B;
B -->|Relay to mailrelay| C;
C -->|Delivery to backend| D;
D -->|Local delivery| E;
classDef localAddr fill:#e0f7fa,stroke:#006064;
classDef remoteAddr fill:#f1f8e9,stroke:#33691e;
classDef backendServer fill:#fff3e0,stroke:#e65100;
classDef relay fill:#fce4ec,stroke:#880e4f;
classDef extRelay fill:#ede7f6,stroke:#311b92;
From alice@mail1.example.com to david@gmail.com (outbound mail):
flowchart LR;
A["alice@mail1.example.com"]:::localAddr;
B["maildemo1.lan"]:::backendServer;
C["mailrelay.lan"]:::relay;
D["3rdpartyrelay.com"]:::extRelay;
E["david@gmail.com"]:::remoteAddr;
A -->|SMTP submission| B;
B -->|Relay to mailrelay| C;
C -->|Outbound relay| D;
D -->|Delivery to recipient SMTP| E;
classDef localAddr fill:#e0f7fa,stroke:#006064;
classDef remoteAddr fill:#f1f8e9,stroke:#33691e;
classDef backendServer fill:#fff3e0,stroke:#e65100;
classDef relay fill:#fce4ec,stroke:#880e4f;
classDef extRelay fill:#ede7f6,stroke:#311b92;
From etienne@hotmail.com to alice@mail1.example.com (inbound mail):
flowchart LR;
A["etienne@hotmail.com"]:::remoteAddr;
B["mailrelay.lan"]:::relay;
C["maildemo1.lan"]:::backendServer;
D["alice@mail1.example.com"]:::localAddr;
A -->|SMTP connect| B;
B -->|Routing by recipient domain| C;
C -->|Local delivery| D;
classDef localAddr fill:#e0f7fa,stroke:#006064;
classDef remoteAddr fill:#f1f8e9,stroke:#33691e;
classDef backendServer fill:#fff3e0,stroke:#e65100;
classDef relay fill:#fce4ec,stroke:#880e4f;
classDef extRelay fill:#ede7f6,stroke:#311b92;