Feature Specification: Component smtp
Created: 2026-10-07
Status: Implemented
Input: Reconstructed from the code at 093e68b6f (core/components/shared/smtp/default.nix, core/setups/hosts-common.nix, core/setups/wiring/smtp-routing.nix, core/setups/groups/hosting-provider.nix, core/setups/groups/operator.nix, core/resources/smtp/), pull requests #1383, #1822, #1835 and #1852.
User Scenarios & Testing (mandatory)
User Story 1 - Relay the mail of a group (Priority: P1)
The applications of a group send mail, for example sign-up and reset mail.
The smtp component runs maddy as the mail relay of the group. It declares
provides = [ "smtp" ], so the node answers the mail.smtp requests of the
group (see smtp). The setup sets the daemon,
one submission account for each application and the generation of the
passwords on this node.
Why this priority: without a relay, no application of the group can send mail.
Independent Test: contracts-smtp-maddy, integrations-smtp-dkim,
integrations-smtp-reports and nix-unit-setups-smtp-routing.
Acceptance Scenarios:
- Given a group with an
smtpmachine, When the setups evaluate, Then the"mail".smtprequest hasenable = true,domain = "smtp.<domain>"and the instance name of the group. - Given a group with
autheliaorlldapmachines, When the setups evaluate, Then the relay gets a want for each of them, with senders frommailDomains.senders.
User Story 2 - Serve submission over TLS (Priority: P2)
A client submits mail over TLS. With the internal PKI, the certificate key
has owner and group maddy, and a renewal restarts maddy.service. With
ACME, a renewal reloads maddy.service (see ssl).
Why this priority: TLS protects the submission passwords.
Independent Test: contracts-smtp-maddy.
Acceptance Scenarios:
- Given a name
smtpthat ACME can challenge, When the setups evaluate, Then the ACME request reloadsmaddy.service.
User Story 3 - Alert on bounced mail (Priority: P3)
maddy reports a bounce only as a generated failed DSN line in its journal.
The component ships no journal of its own. node-logs.nix sends the journal
of maddy.service to Loki, and the maddy-failed-dsn rule in
telemetry.nix alerts on it.
Why this priority: the alert helps an admin, but mail flows without it.
Independent Test: no check covers the maddy-failed-dsn rule.
Acceptance Scenarios:
- Given a bounced message, When maddy logs
generated failed DSN, Then themaddy-failed-dsnrule fires.
Edge Cases
- The relay has no web UI, so the component requests no admin-UI
oidcforward-auth. - A group without an
smtpmachine gives no notifier to Authelia and no reset mail to lldap.
Requirements (mandatory)
Functional Requirements
- FR-001: The component MUST declare
provides = [ "smtp" ]and usepkgs.maddy. - FR-002: The implementation MUST request
"spiffe".spiffe.enable = true, so maddy reads its rotated submission passwords through the OpenBao agent. - FR-003: The component MUST NOT request an
oidcforward-auth, because the relay has no web UI. - FR-004: The setup MUST set the maddy configuration, the accounts and the password generation from the
mail.smtpresource.
Key Entities
"mail".smtp: the request of the setup. It carriesenable,domainandinstanceName.- Submission account: one account for each application that wants mail, with a password in OpenBao.
maddy-failed-dsn: the alert rule on bounced mail.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001:
contracts-smtp-maddy,integrations-smtp-dkimandintegrations-smtp-reportspass. - SC-002:
nix-unit-setups-smtp-routingandnix-unit-setups-lldap-mailpass.
Assumptions
- The
hosting-providerandoperatorgroups both declare ansmtpmachine. Each group runs its own relay. - The component has no icon.
- The provider implementation (
maddy-provider.nix,external-relay.nix) is incore/resources/smtp/, not in this component.
Known Deviations
None.