{ inputs, povSelf, hostConfig, config, lib, dnsNix, ... }: let inherit (lib) types; cfg = lib.getAttrFromPath povSelf config; in { options = { enable = { type = types.bool; default = false; }; hostName = { type = types.str; default = config.networking.fqdn; }; primaryDomain = { type = types.str; default = "zaphyra.eu"; }; primaryDomainDkimKey = { type = types.str; default = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMuEtG24S6ksVx04avtjwIrfijZvQMxe44HrAXjW+Qe7ZbBHtS+q8alvL21zHbe4VgAOTNZ+fCnqSif4TFaOQnwuGwWke5SRBHV6RmWLaJUnN7krjFj+oNmKnl5M3GPI62shhk4OlMgAdDrH/JApd4XTqR3m0U/8rXqPumfbHhzwIDAQAB"; }; extraDomains = { type = with types; attrsOf str; default = { "katja.wtf" = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC56L/GDEY0hTvcZjjCpk3/3c4qAmGAQR06tVpgz7gHs0kMPiGhpg3gDv8kCOu4l3C96oT6eaQoyLcC+ZhJT4ribZaNSD+7lkXk23s4LecklBQxLAjvLrc0GQ9zYp8/Qg4g+Wo9fHR3Lum4tqyyFuT/P21knw+nDWxvz3d0Y4XNVwIDAQAB"; "ctu.cx" = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOuE5vBNP0L4i3OxcFdFbTJ/c8o58CL+cMHBh8lAZej1nSYOPBdpfJRpWiHduWu8cLWNu62nDeY9IGGnE6g9o6+6sMT51NdoY7FFcNNjhm0EoZVDaB1Ffy74ycIDAwuNfp8kpKFsxWMSs1CFy6IRDIIzaQc9JAIoBUBbN5rP2DcwIDAQAB"; "ctucx.de" = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCg3pBG8oH8h0w5YrZ7Dpmtk+/XqE9HElWeF1SWMo86aVLkbsMKjY0WbfAq5YfEdSr/pQrILC+oAt/q6TuLzABYd7cLzK7KgdIX2SuYvujmHqzOOn1huAkzQU0wJMnMYx/0wCFMnVHXsWY9UF2zHDhYu8Jo9vuwMPwGG9u1qnfdCQIDAQAB"; "thein.ovh" = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYogCqmPNomxG4KyZGsfpefFNPS5lY9aRm7TjiONKKPKQFb4oFfUBacurfL+cdGhX6CBnRr6IUXZ37e+ptOyWNFfG1e5R7dJeRdmCZvsn2DRbxCEeGA6gjl3hmRIjg3HUCWjWlzjRXV4Qke/7Q1y1lfivOrgU72bLw/V7BEi1OZQIDAQAB"; "zuggeschmack.de" = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnAw4RQAJ2yFYmqIRzSfyEhFmC7ICywBMx65u3U3blge+HOa/kO1jc8tA2CCVQpgJur0fBB8NFFWpTMEfL0zETxWK07FQE9HfN52P+i4B4wo4P9N/ig5ZYcyXfrgUZtQaUzGRpHZ6gAe6YS1SREsjfOC8eTMF6HELdSR4W4fFbiwIDAQAB"; }; }; ip6Address = { type = types.str; default = hostConfig.networking.ip6Address; }; ip4Address = { type = types.str; default = hostConfig.networking.ip4Address; }; }; config = lib.mkIf cfg.enable ( let mailAutoConfig = '' ${cfg.primaryDomain} ${cfg.hostName} ${cfg.hostName} ${cfg.hostName} 993 SSL password-cleartext %EMAILADDRESS% ${cfg.hostName} 465 SSL password-cleartext %EMAILADDRESS% ''; in { dns.zones = with dnsNix.combinators; let TXT = [ "v=spf1 a mx ip4:${cfg.ip4Address} +ip6:${cfg.ip6Address} ~all" ]; DMARC = "v=DMARC1; p=none"; MX = with mx; [ (mx 10 "${cfg.hostName}.") ]; in { "${cfg.primaryDomain}" = { inherit MX TXT; SRV = [ { proto = "tcp"; service = "imaps"; priority = 0; weight = 1; port = 993; target = "${cfg.hostName}."; } { proto = "tcp"; service = "imap"; priority = 0; weight = 1; port = 143; target = "${cfg.hostName}."; } { proto = "tcp"; service = "submission"; priority = 0; weight = 1; port = 587; target = "${cfg.hostName}."; } ]; subdomains = { autoconfig.CNAME = [ "${cfg.hostName}." ]; _dmarc.TXT = [ DMARC ]; "${config.mailserver.dkimSelector}._domainkey".TXT = [ cfg.primaryDomainDkimKey ]; }; }; } // (lib.mapAttrs (domain: dkimKey: { inherit MX TXT; subdomains = { _dmarc.TXT = [ DMARC ]; "${config.mailserver.dkimSelector}._domainkey".TXT = [ dkimKey ]; }; }) cfg.extraDomains); systemd.services.dovecot.after = [ "sops-install-secrets.service" ]; sops.secrets = { "mailPasswords/katja@zaphyra.eu" = { }; "mailPasswords/gts@zaphyra.eu" = { }; "mailPasswords/vaultwarden@zaphyra.eu" = { }; "mailPasswords/info@zuggeschmack.de" = { }; "mailPasswords/gts@zuggeschmack.de" = { }; "resticPasswords/mail" = { }; "sieveScripts/katja@zaphyra.eu.sieve" = { sopsFile = inputs.self.sopsSecrets.zaphyra.sieve; key = "katja@zaphyra.eu"; restartUnits = [ "dovecot2.service" ]; owner = "dovecot2"; path = "/etc/dovecot/sieve/katja@zaphyra.eu.sieve"; }; }; modules.filesystem.impermanence.system.dirs = [ "/var/lib/dhparams" "/var/lib/dovecot" "/var/lib/postfix" { directory = "/var/lib/dkimKeys"; mode = "0700"; user = "rspamd"; group = "rspamd"; } { directory = "/var/lib/mailboxes"; mode = "0700"; user = "virtualMail"; group = "virtualMail"; } { directory = "/var/lib/redis-rspamd"; mode = "0700"; user = "redis-rspamd"; group = "redis-rspamd"; } { directory = "/var/lib/rspamd"; mode = "0700"; user = "rspamd"; group = "rspamd"; } { directory = "/var/lib/sieve"; mode = "0770"; user = "virtualMail"; group = "virtualMail"; } ]; security.acme.certs."${cfg.hostName}".reloadServices = [ "postfix.service" "dovecot2.service" ]; services = { dovecot2.sieve.extensions = [ "editheader" ]; nginx = { enable = true; virtualHosts = { "autoconfig.${cfg.primaryDomain}" = { useACMEHost = "${config.networking.fqdn}"; forceSSL = true; locations."= /mail/config-v1.1.xml".return = "200 '${mailAutoConfig}'"; }; }; }; }; mailserver = { enable = true; fqdn = cfg.hostName; openFirewall = true; localDnsResolver = false; virusScanning = false; certificateScheme = "acme"; enableManageSieve = true; enableSubmission = true; enableSubmissionSsl = true; enableImap = true; enableImapSsl = true; enablePop3 = false; enablePop3Ssl = false; fullTextSearch.enable = true; dmarcReporting = { enable = true; domain = "zaphyra.eu"; organizationName = "zaphyra-mail"; }; indexDir = "/var/lib/dovecot/indices"; mailDirectory = "/var/lib/mailboxes"; sieveDirectory = "/var/lib/sieve"; dkimKeyDirectory = "/var/lib/dkimKeys"; domains = [ cfg.primaryDomain ] ++ (lib.attrNames cfg.extraDomains); loginAccounts = { "katja@zaphyra.eu" = { hashedPasswordFile = config.sops.secrets."mailPasswords/katja@zaphyra.eu".path; sieveScript = '' require ["include"]; include :global "katja@zaphyra.eu"; ''; aliases = [ "@zaphyra.eu" "@ctu.cx" "@ctucx.de" "@thein.ovh" "@katja.wtf" ]; }; "gts@zaphyra.eu" = { hashedPasswordFile = config.sops.secrets."mailPasswords/gts@zaphyra.eu".path; sendOnly = true; }; "vaultwarden@zaphyra.eu" = { hashedPasswordFile = config.sops.secrets."mailPasswords/vaultwarden@zaphyra.eu".path; sendOnly = true; }; "info@zuggeschmack.de" = { hashedPasswordFile = config.sops.secrets."mailPasswords/info@zuggeschmack.de".path; aliases = [ "@zuggeschmack.de" ]; }; "gts@zuggeschmack.de" = { hashedPasswordFile = config.sops.secrets."mailPasswords/gts@zuggeschmack.de".path; sendOnly = true; }; }; }; modules.services.resticBackup.paths.mail = { passwordFile = config.sops.secrets."resticPasswords/mail".path; paths = [ "/var/lib/mailboxes" "/var/lib/dkimKeys" "/var/lib/sieve" ]; }; } ); }