# SPDX-FileCopyrightText: 2021-2024 Simon Bruder # # SPDX-License-Identifier: AGPL-3.0-or-later { 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; protocols = [ "sieve" ]; 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"; }; }; mailPlugins.perProtocol = { imap.enable = [ "imap_sieve" ]; lmtp.enable = [ "sieve" ]; }; sieve = { scripts = { before = pkgs.writeText "spam.sieve" '' require "fileinto"; if header :is "X-Spam" "Yes" { fileinto "Spam"; } ''; }; extensions = [ "fileinto" ]; pipeBins = lib.mkIf cfg.spam.enable [ "${pkgs.rspamd}/bin/rspamc" ]; }; imapsieve.mailbox = lib.mkIf cfg.spam.enable [ { name = "Spam"; causes = [ "COPY" ]; before = pkgs.writeText "learn-spam.sieve" '' require ["vnd.dovecot.pipe", "copy", "imapsieve"]; pipe :copy "rspamc" ["learn_spam"]; ''; } { name = "*"; from = "Spam"; causes = [ "COPY" ]; before = pkgs.writeText "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"]; ''; } ]; pluginSettings = { sieve = "file:/var/lib/sieve/%d/%n/scripts;active=/var/lib/sieve/%d/%n/active.sieve"; }; 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 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 service managesieve-login { inet_listener sieve { port = 4190 } } ''; }; systemd.services.dovecot2 = { wants = [ "acme-finished-${cfg.fqdn}.target" ]; after = [ "acme-finished-${cfg.fqdn}.target" ]; }; networking.firewall.allowedTCPPorts = [ 143 # IMAP 993 # IMAP (implicit TLS) 4190 # ManageSieve ]; security.acme.certs."${cfg.fqdn}".postRun = '' if systemctl is-active dovecot2; then systemctl --no-block reload dovecot2 fi ''; }