{ config, lib, pkgs, ... }: let cfg = config.mailserver; hasMailDiscoveryConfig = cfg.enable && cfg.fqdn != null && cfg.domains != [ ]; in lib.mkIf hasMailDiscoveryConfig ( let domain = builtins.head cfg.domains; mobileconfigHost = "autoconfig.${domain}"; radicaleHost = "cal.${domain}"; safeAccountName = email: builtins.replaceStrings [ "@" "+" ] [ "_" "-" ] email; mkUuid = seed: let hash = builtins.hashString "sha256" seed; in "${lib.substring 0 8 hash}-${lib.substring 8 4 hash}-${lib.substring 12 4 hash}-${lib.substring 16 4 hash}-${lib.substring 20 12 hash}"; mkMobileconfig = email: let safeName = safeAccountName email; profileUuid = mkUuid "${email}-apple-profile"; mailUuid = mkUuid "${email}-apple-mail"; caldavUuid = mkUuid "${email}-apple-caldav"; carddavUuid = mkUuid "${email}-apple-carddav"; in pkgs.writeText "${safeName}.mobileconfig" '' PayloadContent EmailAccountDescription ${domain} Mail EmailAccountName ${email} EmailAccountType EmailTypeIMAP EmailAddress ${email} IncomingMailServerAuthentication EmailAuthPassword IncomingMailServerHostName ${cfg.fqdn} IncomingMailServerPortNumber 993 IncomingMailServerUseSSL IncomingMailServerUsername ${email} OutgoingMailServerAuthentication EmailAuthPassword OutgoingMailServerHostName ${cfg.fqdn} OutgoingMailServerPortNumber 587 OutgoingMailServerUseSSL OutgoingMailServerUsername ${email} OutgoingPasswordSameAsIncomingPassword PayloadDescription Configures IMAP and SMTP for ${email}. PayloadDisplayName Mail PayloadIdentifier com.billenius.mobileconfig.${safeName}.mail PayloadType com.apple.mail.managed PayloadUUID ${mailUuid} PayloadVersion 1 CalDAVAccountDescription ${domain} Calendar CalDAVHostName ${radicaleHost} CalDAVPort 443 CalDAVUseSSL CalDAVUsername ${email} PayloadDescription Configures CalDAV for ${email}. PayloadDisplayName Calendar PayloadIdentifier com.billenius.mobileconfig.${safeName}.caldav PayloadType com.apple.caldav.account PayloadUUID ${caldavUuid} PayloadVersion 1 CardDAVAccountDescription ${domain} Contacts CardDAVHostName ${radicaleHost} CardDAVPort 443 CardDAVUseSSL CardDAVUsername ${email} PayloadDescription Configures CardDAV for ${email}. PayloadDisplayName Contacts PayloadIdentifier com.billenius.mobileconfig.${safeName}.carddav PayloadType com.apple.carddav.account PayloadUUID ${carddavUuid} PayloadVersion 1 PayloadDescription Configures mail, calendar, and contacts for ${email}. PayloadDisplayName ${domain} Mail PayloadIdentifier com.billenius.mobileconfig.${safeName} PayloadOrganization ${domain} PayloadRemovalDisallowed PayloadType Configuration PayloadUUID ${profileUuid} PayloadVersion 1 ''; mobileconfigProfiles = lib.mapAttrs ( email: _: { inherit email; safeName = safeAccountName email; profile = mkMobileconfig email; } ) cfg.loginAccounts; mobileconfigLandingPage = pkgs.writeText "mobileconfig-index.html" '' ${domain} Apple Profile

${domain} Apple Profile

Open this page in Safari on iPhone, iPad, or macOS and enter your email address to download the configuration profile.

The profile configures IMAP, SMTP, CalDAV, and CardDAV. You will still be asked for your password during installation.

''; mobileconfigRedirectConfig = lib.concatStrings ( lib.mapAttrsToList ( email: profile: '' if ($arg_emailaddress = "${email}") { return 302 /mobileconfig/${profile.safeName}.mobileconfig; } '' ) mobileconfigProfiles ); mobileconfigLocations = lib.listToAttrs ( [ { name = "= /mobileconfig"; value.return = "308 /mobileconfig/"; } { name = "= /mobileconfig/"; value.extraConfig = '' ${mobileconfigRedirectConfig} return 302 /mobileconfig/index.html; ''; } { name = "= /mobileconfig/index.html"; value.extraConfig = '' default_type text/html; alias ${mobileconfigLandingPage}; ''; } ] ++ lib.mapAttrsToList ( _: profile: { name = "= /mobileconfig/${profile.safeName}.mobileconfig"; value.extraConfig = '' default_type application/x-apple-aspen-config; add_header Content-Disposition 'attachment; filename="${profile.safeName}.mobileconfig"' always; alias ${profile.profile}; ''; } ) mobileconfigProfiles ); defaultMobileconfigLocation = let accounts = lib.attrNames mobileconfigProfiles; in if lib.length accounts == 1 then let profile = mobileconfigProfiles.${builtins.head accounts}; in { "= /mobileconfig/billenius.mobileconfig".extraConfig = '' default_type application/x-apple-aspen-config; add_header Content-Disposition 'attachment; filename="billenius.mobileconfig"' always; alias ${profile.profile}; ''; } else { }; in { services.nginx.virtualHosts.${mobileconfigHost}.locations = mobileconfigLocations // defaultMobileconfigLocation; } )