{ lib, config, pkgs, ... }: let hostname = "mail.${config.networking.domain}"; dovecot-ldap-args = pkgs.writeText "ldap-args" '' uris = ldap://localhost dn = uid=search, ou=users, dc=ifsr, dc=de auth_bind = yes !include ${config.sops.secrets."dovecot_ldap_search".path} ldap_version = 3 scope = subtree base = dc=ifsr, dc=de user_filter = (&(objectClass=posixAccount)(uid=%n)) pass_filter = (&(objectClass=posixAccount)(uid=%n)) ''; in { networking.firewall.allowedTCPPorts = [ 993 # IMAPS 4190 # Managesieve ]; sops.secrets."dovecot_ldap_search".owner = config.services.dovecot2.user; services.dovecot2 = { enable = true; enableImap = true; enableQuota = true; quotaGlobalPerUser = "10G"; enableLmtp = true; enablePAM = false; mailLocation = "maildir:~/Maildir"; sslServerCert = "/var/lib/acme/${hostname}/fullchain.pem"; sslServerKey = "/var/lib/acme/${hostname}/key.pem"; protocols = [ "imap" "sieve" ]; mailPlugins = { globally.enable = [ "listescape" ]; perProtocol = { imap = { enable = [ "imap_sieve" "imap_filter_sieve" ]; }; lmtp = { enable = [ "sieve" ]; }; }; }; mailboxes = { Spam = { auto = "subscribe"; specialUse = "Junk"; autoexpunge = "60d"; }; Sent = { auto = "subscribe"; specialUse = "Sent"; }; Drafts = { auto = "subscribe"; specialUse = "Drafts"; }; Trash = { auto = "subscribe"; specialUse = "Trash"; }; Archive = { auto = "no"; specialUse = "Archive"; }; }; modules = [ pkgs.dovecot_pigeonhole ]; # set to satisfy the sieveScripts check, will be overridden by userdb lookups anyways mailUser = "vmail"; mailGroup = "vmail"; sieve = { # just pot something in here to prevent empty strings extensions = [ "notify" ]; pipeBins = map lib.getExe [ (pkgs.writeShellScriptBin "learn-ham.sh" "exec ${pkgs.rspamd}/bin/rspamc learn_ham") (pkgs.writeShellScriptBin "learn-spam.sh" "exec ${pkgs.rspamd}/bin/rspamc learn_spam") ]; plugins = [ "sieve_imapsieve" "sieve_extprograms" ]; scripts = { before = pkgs.writeText "spam.sieve" '' require "fileinto"; if anyof( header :contains "x-spam-flag" "yes", header :contains "X-Spam-Status" "Yes"){ fileinto "Spam"; } ''; }; }; imapsieve.mailbox = [ { # Spam: From elsewhere to Spam folder or flag changed in Spam folder name = "Spam"; causes = [ "COPY" "APPEND" "FLAG" ]; before = ./report-spam.sieve; } { # From Junk folder to elsewhere name = "*"; from = "Spam"; causes = [ "COPY" ]; before = ./report-ham.sieve; } ]; extraConfig = '' auth_username_format = %Ln passdb { driver = ldap args = ${dovecot-ldap-args} } userdb { driver = ldap args = ${dovecot-ldap-args} } service auth { unix_listener /var/lib/postfix/auth { group = postfix mode = 0660 user = postfix } } service managesieve-login { inet_listener sieve { port = 4190 } service_count = 1 } namespace inbox { separator = / inbox = yes } service lmtp { unix_listener dovecot-lmtp { group = postfix mode = 0600 user = postfix } client_limit = 1 } plugin { # https://doc.dovecot.org/configuration_manual/plugins/listescape_plugin/ listescape_char = "\\" } ''; }; }