From 2b240501e0144bdea30dd3aaa11941e580346d7e Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Tue, 8 Jul 2025 02:44:23 +0200 Subject: [PATCH] Introduce system name and domain options Bring them up from the DMARC reporting section to the mailserver toplevel so they become reusable for the upcoming TLSRPT integration. We default to the first domain in the domains option, if not set explicitly, so that `systemDomain` doesn't become a blocker for existing setups. We still encourage picking out the intended one, which is likely the one used for the MX hostname. This also simplifies the DMARC reporting configuration, which doesn't need to be so fine-grained. Co-Authored-By: Emily --- default.nix | 88 +++++++++++++++++++++--------------------- docs/release-notes.rst | 9 +++++ flake.nix | 4 -- mail-server/rspamd.nix | 10 ++--- tests/external.nix | 6 +-- 5 files changed, 58 insertions(+), 59 deletions(-) diff --git a/default.nix b/default.nix index e10bd92..83f2a16 100644 --- a/default.nix +++ b/default.nix @@ -69,6 +69,35 @@ in description = "The fully qualified domain name of the mail server."; }; + systemName = mkOption { + type = types.str; + default = "${cfg.systemDomain} mail system"; + defaultText = literalExpression "\${config.mailserver.systemDomain} mail system"; + example = "ACME Corp."; + description = '' + The sender name given in automated reports. + ''; + }; + + systemDomain = mkOption { + type = types.str; + default = + if (config.networking.domain != null && lib.elem config.networking.domain cfg.domains) then + config.networking.domain + else + lib.head cfg.domains; + defaultText = literalExpression '' + if config.networking.domain != null && lib.elem config.networking.domain cfg.domains then + config.networking.domain + else + lib.head cfg.domains + ''; + example = literalExpression "config.networking.domain"; + description = '' + The primary domain used for sending automated reports. + ''; + }; + domains = mkOption { type = types.listOf types.str; example = [ "example.com" ]; @@ -972,51 +1001,6 @@ in ''; }; - localpart = mkOption { - type = types.str; - default = "dmarc-noreply"; - example = "dmarc-report"; - description = '' - The local part of the email address used for outgoing DMARC reports. - ''; - }; - - domain = mkOption { - type = types.enum cfg.domains; - example = "example.com"; - description = '' - The domain from which outgoing DMARC reports are served. - ''; - }; - - email = mkOption { - type = types.str; - default = with cfg.dmarcReporting; "${localpart}@${domain}"; - defaultText = literalExpression ''"''${localpart}@''${domain}"''; - readOnly = true; - description = '' - The email address used for outgoing DMARC reports. Read-only. - ''; - }; - - organizationName = mkOption { - type = types.str; - example = "ACME Corp."; - description = '' - The name of your organization used in the `org_name` attribute in - DMARC reports. - ''; - }; - - fromName = mkOption { - type = types.str; - default = cfg.dmarcReporting.organizationName; - defaultText = literalMD "{option}`mailserver.dmarcReporting.organizationName`"; - description = '' - The sender name for DMARC reports. Defaults to the organization name. - ''; - }; - excludeDomains = mkOption { type = types.listOf types.str; default = [ ]; @@ -1471,5 +1455,19 @@ in (mkRemovedOptionModule [ "mailserver" "smtpdForbidBareNewline" ] '' The workaround for the SMTP Smuggling attack is default enabled in Postfix >3.9. Use `services.postfix.config.smtpd_forbid_bare_newline` if you need to deviate from its default. '') + (mkRenamedOptionModule [ "mailserver" "dmarcReporting" "domain" ] [ "mailserver" "systemDomain" ]) + (mkRenamedOptionModule + [ "mailserver" "dmarcReporting" "organizationName" ] + [ "mailserver" "systemName" ] + ) + (mkRemovedOptionModule [ "mailserver" "dmarcReporting" "localpart" ] '' + The localpart is now fixed at `noreply-dmarc` to simplify the configuration. + '') + (mkRemovedOptionModule [ "mailserver" "dmarcReporting" "email" ] '' + The address is now fixed at `noreply-dmarc@''${config.mailserver.systemDomain}` to simplify the configuration. + '') + (mkRemovedOptionModule [ "mailserver" "dmarcReporting" "fromName" ] '' + The name in the `FROM` field for DMARC report now uses the `mailserver.systemName`. + '') ]; } diff --git a/docs/release-notes.rst b/docs/release-notes.rst index 7e1429f..d4877e4 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -1,6 +1,15 @@ Release Notes ============= +NixOS 25.11 +----------- + +- The ``systemName`` and ``systemDomain`` options have been introduced to have + reusable configurations for automated reports (DMARC, TLSRPT). They come with + reasonable defaults, but it is suggested to check and change them as needed. +- DMARC reports are now sent with the ``noreply-dmarc`` localpart from the + system domain. + NixOS 25.05 ----------- diff --git a/flake.nix b/flake.nix index 18757c5..da8ae84 100644 --- a/flake.nix +++ b/flake.nix @@ -94,10 +94,6 @@ domains = [ "example.com" ]; - dmarcReporting = { - organizationName = "Example Corp"; - domain = "example.com"; - }; }; } ]; diff --git a/mail-server/rspamd.nix b/mail-server/rspamd.nix index 257cac7..73e119a 100644 --- a/mail-server/rspamd.nix +++ b/mail-server/rspamd.nix @@ -121,11 +121,11 @@ in ${lib.optionalString cfg.dmarcReporting.enable '' reporting { enabled = true; - email = "${cfg.dmarcReporting.email}"; - domain = "${cfg.dmarcReporting.domain}"; - org_name = "${cfg.dmarcReporting.organizationName}"; - from_name = "${cfg.dmarcReporting.fromName}"; - msgid_from = "${cfg.dmarcReporting.domain}"; + email = "noreply-dmarc@${cfg.systemDomain}"; + domain = "${cfg.systemDomain}"; + org_name = "${cfg.systemName}"; + from_name = "${cfg.systemName}"; + msgid_from = "${cfg.systemDomain}"; ${lib.optionalString (cfg.dmarcReporting.excludeDomains != [ ]) '' exclude_domains = ${builtins.toJSON cfg.dmarcReporting.excludeDomains}; ''} diff --git a/tests/external.nix b/tests/external.nix index 842e62c..0f47acb 100644 --- a/tests/external.nix +++ b/tests/external.nix @@ -47,11 +47,7 @@ ]; rewriteMessageId = true; dkimKeyBits = 1535; - dmarcReporting = { - enable = true; - domain = "example.com"; - organizationName = "ACME Corp"; - }; + dmarcReporting.enable = true; loginAccounts = { "user1@example.com" = {