{ config, lib, ... }: let cfg = config.mailsystem; in { options.mailsystem = { enable = lib.mkEnableOption "nixos-mailsystem"; openFirewall = lib.mkOption { type = lib.types.bool; default = true; description = "Automatically open ports in the firewall."; }; fqdn = lib.mkOption { type = lib.types.str; example = "mail.example.com"; description = "Fully qualified domain name of the mail server."; }; reverseFqdn = lib.mkOption { type = lib.types.str; default = cfg.fqdn; defaultText = lib.literalMD "{option}`mailsystem.fqdn`"; example = "server.example.com"; description = '' Fully qualified domain name used by the server to identify with other servers. This needs to be set to the same value of the server's IP reverse DNS. ''; }; domains = lib.mkOption { type = lib.types.listOf lib.types.str; example = ["example.com"]; default = []; description = "List of domains to be served by the mail server"; }; messageSizeLimit = lib.mkOption { type = lib.types.int; default = 64 * 1024 * 1024; description = "Maximum accepted mail size"; }; vmailUID = lib.mkOption { type = lib.types.int; default = 5000; description = "The unix UID of the virtual mail user."; }; vmailUserName = lib.mkOption { type = lib.types.str; default = "vmail"; description = "The user name of the user that owns the directory all the mail is stored."; }; vmailGroupName = lib.mkOption { type = lib.types.str; default = "vmail"; description = "The group name of the user that owns the directory all the mail is stored."; }; mailDirectory = lib.mkOption { type = lib.types.str; default = "/var/vmail"; description = "Storage location for all mail."; }; accounts = lib.mkOption { type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { options = { name = lib.mkOption { type = lib.types.str; example = "user1@example.com"; description = "Username"; }; hashedPasswordFile = lib.mkOption { type = with lib.types; nullOr str; default = null; example = "/run/secrets/user1-passwordhash"; description = '' A file containing the user's hashed password. Use `mkpasswd` as follows ``` nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' ``` ''; }; isSystemUser = lib.mkOption { type = lib.types.bool; default = false; description = '' System users are not allowed to change their password and are cannot receive any mails (-> send-only). Mails sent to such an account will be rejected. ''; }; rejectMessage = lib.mkOption { type = lib.types.str; default = "This account cannot receive emails."; description = '' The message that will be returned to the sender when an email is sent to a system account. ''; }; }; config.name = lib.mkDefault name; })); example = { user1 = { hashedPassword = "$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/"; }; user2 = { hashedPassword = "$6$oE0ZNv2n7Vk9gOf$9xcZWCCLGdMflIfuA0vR1Q1Xblw6RZqPrP94mEit2/81/7AKj2bqUai5yPyWE.QYPyv6wLMHZvjw3Rlg7yTCD/"; }; }; description = "All available accounts for the mailsystem."; default = {}; }; virtualAliases = lib.mkOption { type = let isAccount = value: builtins.elem value (builtins.attrNames cfg.accounts); isDomain = value: !(lib.hasInfix "@" value) && (builtins.elem value cfg.domains); account = lib.mkOptionType { name = "Mail Account"; check = isAccount; }; accountOrDomain = lib.mkOptionType { name = "Mail Account or Domain"; check = value: (isAccount value) || (isDomain value); }; in with lib.types; attrsOf (either (nonEmptyListOf account) accountOrDomain); example = { "info@example.com" = "user1@example.com"; "postmaster@example.com" = "user1@example.com"; "abuse@example.com" = "user1@example.com"; "multi@example.com" = ["user1@example.com" "user2@example.com"]; "aliasdomain.com" = "domain.com"; }; description = '' Virtual account and domain aliases. A virtual alias means, that all mail directed at a given target are forwarded to the specified other destinations, too. For account aliases, this means that, e.g., `"user1@example.com"` receives all mail sent to `"info@example.com"`. In addition, `"user1@example.com"` is also able to impersonate `"info@example.com"` when sending mails. It is also possible to create an alias for multiple accounts. In this example, all mails for `"multi@example.com"` will be forwarded to both `"user1@example.com"` and `"user2@example.com"`. For domain aliases, this means that all mails directed at an aliased domain, e.g., `"aliasdomain.com"` are forwarded to `"domain.com"` This also entails, that any account or alias of `"domain.com"` receives mails directed at `"aliasdomain.com"`. However, if `"user@domain.com"` shall be able to send mails using `"user@aliasdomain.com"`, an explicit alias needs to be configured. ''; default = {}; }; dkimSettings = lib.mkOption { type = with lib.types; attrsOf (listOf (submodule { options = { selector = lib.mkOption { type = lib.types.str; example = "mail"; description = "DKIM Selector"; }; keyFile = lib.mkOption { type = lib.types.path; example = "/run/secrets/dkim/example.com.mail.key"; description = '' Path to DKIM private-key-file. A public-private-pair can be generated as follows: ``` nix-shell -p rspamd --run 'rspamadm dkim_keygen -s "selector" -t ed25519 -d example.com nix-shell -p rspamd --run 'rspamadm dkim_keygen -s "selector" -b 2048 -d example.com ``` ''; }; }; })); example = { "example.com" = [ { selector = "mail"; keyFile = "/run/secrets/dkim/example.com.mail.key"; } ]; }; description = '' Per-domain DKIM configuration. This option allows to optionally set one or more DKIM private keys and their respective selectors for each domain individually. ''; default = {}; }; extraSettingsFile = lib.mkOption { type = lib.types.nullOr lib.types.path; description = '' YAML file to merge into the mailsystem configuration at runtime. This can be used to store secrets, and, more importantly, keep your email addresses out of the hands of spammers. This `extraSettingsFile` currently supports `domains`, `accounts` and `virtualAliases` which can be defined in the same manner as they can be via nix. ''; default = null; }; certificateScheme = lib.mkOption { type = lib.types.enum ["acme" "selfsigned"]; default = "acme"; description = '' The scheme to use for managing TLS certificates: 1. `acme`: The server retrieves letsencrypt certificates via NixOS's acme module using nginx. 2. `selfsigned`: The server creates self-signed certificates on the fly (intended for testing). ''; internal = true; visible = false; }; }; imports = [ ./dovecot.nix ./kresd.nix ./nginx.nix ./postfix.nix ./redis.nix ./roundcube.nix ./rspamd.nix ./selfsigned.nix ./user.nix ]; }