{ config, lib, pkgs, ... }: let cfg = config.sbruder.mailserver; postfixCfg = config.services.postfix; passdb = pkgs.writeText "dovecot-users" (lib.concatMapStringsSep "\n" ({ address, passwordHash, ... }: "${address}:{BLF-CRYPT}${passwordHash}") cfg.users); in lib.mkIf cfg.enable { services.dovecot2 = { enable = true; modules = with pkgs; [ dovecot_pigeonhole ]; enableLmtp = true; enablePAM = false; mailUser = "vmail"; mailGroup = "vmail"; mailLocation = "maildir:${cfg.storage}/%d/%n"; sslServerCert = "${cfg.certDir}/fullchain.pem"; sslServerKey = "${cfg.certDir}/key.pem"; mailboxes = { Archive = { specialUse = "Archive"; auto = "subscribe"; }; Sent = { specialUse = "Sent"; auto = "subscribe"; }; Drafts = { specialUse = "Drafts"; auto = "subscribe"; }; Trash = { specialUse = "Trash"; auto = "subscribe"; }; Spam = { specialUse = "Junk"; auto = "subscribe"; }; }; sieveScripts = { before = pkgs.writeText "spam.sieve" '' require "fileinto"; if header :is "X-Spam" "Yes" { fileinto "Spam"; } ''; }; extraConfig = '' # generated 2021-02-04, Mozilla Guideline v5.6, Dovecot 2.3.13, OpenSSL 1.1.1i, intermediate configuration # https://ssl-config.mozilla.org/#server=dovecot&version=2.3.13&config=intermediate&openssl=1.1.1i&guideline=5.6 ssl = required ssl_min_protocol = TLSv1.2 ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 ssl_prefer_server_ciphers = no protocol imap { mail_plugins = $mail_plugins imap_sieve } protocol lmtp { mail_plugins = $mail_plugins sieve } service imap-login { inet_listener imap { } } service lmtp { unix_listener dovecot-lmtp { mode = 0600 user = ${postfixCfg.user} group = ${postfixCfg.group} } } passdb { driver = passwd-file args = username_format=%u ${passdb} } userdb { driver = static args = uid=vmail gid=vmail home=${cfg.storage}/%d/%n } service auth { unix_listener auth { mode = 0660 user = ${postfixCfg.user} group = ${postfixCfg.group} } } lda_mailbox_autosubscribe = yes lda_mailbox_autocreate = yes plugin { sieve_plugins = sieve_imapsieve sieve_extprograms ${lib.optionalString cfg.spam.enable '' imapsieve_mailbox1_name = Spam imapsieve_mailbox1_causes = COPY imapsieve_mailbox1_before = file:/var/lib/dovecot/sieve/learn-spam.sieve imapsieve_mailbox2_name = * imapsieve_mailbox2_from = Spam imapsieve_mailbox2_causes = COPY imapsieve_mailbox2_before = file:/var/lib/dovecot/sieve/learn-ham.sieve sieve_pipe_bin_dir = ${pkgs.symlinkJoin { name = "sieve-pipe-bin-dir"; paths = with pkgs; [ rspamd ]; } }/bin ''} sieve_global_extensions = +vnd.dovecot.pipe } ''; }; systemd.services.dovecot2 = { wants = [ "acme-finished-${cfg.fqdn}.target" ]; after = [ "acme-finished-${cfg.fqdn}.target" ]; preStart = lib.mkIf cfg.spam.enable (lib.mkAfter (lib.concatStrings (lib.mapAttrsToList (name: content: '' cp ${pkgs.writeText name content} /var/lib/dovecot/sieve/${name} '') { "learn-spam.sieve" = '' require ["vnd.dovecot.pipe", "copy", "imapsieve"]; pipe :copy "rspamc" ["learn_spam"]; ''; "learn-ham.sieve" = '' require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; if environment :matches "imap.mailbox" "*" { set "mailbox" "''${1}"; } if string "''${mailbox}" "Trash" { stop; } pipe :copy "rspamc" ["learn_ham"]; ''; }))); }; networking.firewall.allowedTCPPorts = [ 143 # IMAP 993 # IMAP (implicit TLS) ]; security.acme.certs."${cfg.fqdn}".postRun = '' if systemctl is-active dovecot2; then systemctl --no-block reload dovecot2 fi ''; }