{ config, lib, pkgs, ... }: let inherit (lib.modules) mkIf; inherit (lib.options) mkEnableOption; domain = "charlieroot.dev"; acmeRoot = "/var/lib/acme/challenges-stalwart"; cfg = config.modules.system.services.stalwart; in { options.modules.system.services.stalwart.enable = mkEnableOption "stalwart"; config = mkIf cfg.enable { services.stalwart-mail = { enable = true; package = pkgs.stalwart-mail; openFirewall = true; settings = { email = { # All incoming messages via SMTP or LMTP are automatically encrypted before they are written to disk, # provided the user has uploaded their S/MIME certificate or OpenPGP public key. encryption.enable = true; }; server = { # The default server hostname is utilized in SMTP EHLO commands, # as well as included in message headers and reports. hostname = "mail.${domain}"; tls = { # Specifies whether the TLS encryption is available for the listener. enable = true; # Specifies whether the listener should use implicit or explicit TLS encryption. # If set to false (the default), the listener will use explicit TLS encryption, # which requires clients to initiate a STARTTLS command before upgrading the connection # to an encrypted one. If set to true, the listener will use implicit TLS encryption, # which requires the connection to be encrypted from the start. implicit = true; }; # Listeners are responsible for receiving incoming TCP connections. listener = { # Unencrypted SMTP connections are received on port 25 by default. # This is the standard port for SMTP, and is used by mail servers to send email to each other. smtp = { protocol = "smtp"; bind = ["localhost::25" "[::]:25"]; tls.implicit = true; }; # SMTP submissions with implicit TLS are received on port 465 by default. # This is the standard port for SMTP submissions with native implicit TLS, # and is used by mail clients to send email to mail servers. submissions = { bind = ["localhost::465" "[::]:465"]; protocol = "smtp"; tls.implicit = true; }; imaps = { bind = ["localhost::993" "[::]:993"]; protocol = "imap"; tls.implicit = true; }; jmap = { bind = ["localhost::8080" "[::]:8080"]; url = "https://mail.${domain}"; protocol = "jmap"; tls.implicit = true; }; management = { bind = ["localhost:8080"]; protocol = "http"; tls.implicit = true; }; }; lookup.default = { hostname = "mail.${domain}"; inherit domain; }; }; storage = { data = "postgresql"; blob = "postgresql"; fts = "postgresql"; lookup = "postgresql"; full-text = { default-language = "en"; }; }; store = { postgresql = { # Specifies the database type, set to "postgresql" for PostgreSQL. type = "postgresql"; # The hostname or IP address of the PostgreSQL server. host = "localhost"; # Port PostgreSQL runs on. Defaults to 5432. port = "5432"; # Name of the database to connect to. # TODO: add this to PostgreSQL. name = "stalwart"; # The username used for authentication with the PostgreSQL server. # TODO: add this to PostgreSQL. username = "stalwart"; # Compression algorithm to use. compression = "lz4"; # Clean up every day at 5:30am local time. purge.frequency = "30 5 *"; # Enable TLS tls.enable = true; }; }; }; }; services.nginx = { enable = true; virtualHosts.${domain} = { addSSL = true; enableACME = true; locations."/" = { proxyPass = "http://localhost:${toString 8080}"; }; }; }; security.acme = let email = "charlie@charlieroot.dev"; in { # testing server, do not use in production, but DO use it for setting things up. # it has much higher rate limits. # defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory"; certs = { ${domain} = { webroot = acmeRoot; inherit email; group = "nginx"; }; "mail.${domain}" = { webroot = acmeRoot; inherit email; group = "nginx"; }; }; }; }; }