aboutsummaryrefslogblamecommitdiff
path: root/systems/eldiron/mail/dovecot.nix
blob: 9c9cd7cc67f87ebb810177b5e1c61fdfdb6ef306 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
                           












                                                                            
                                                   





























                                                                                                
                                                                 












                                                                                                                                                                                                                     


























                                                                         





                                                   



                                                                            
                                                                                                        

        










                                                                                                  
                               



                             





                                                                
                                                                    
                                                   
                                                  
                                               
                                                    

                                                            
                                                        


                                                       











                                                          










                                                         




















                                                          
                


                                                             
                                                                                                
 










                                                                                                                      




                                                                                                                     


                                                                                
         







                               
         




                               
         
                      
         
                      
         





                                                                                        
         
                             
         


                              
         










                                      
         






                                                           



                                                          



                                                           

                                                           

          
 







                                         
 


















                                                                          
 



                                                              
                                                          














                                                                   

                                                                 
                                                                                                                                                                        

                                                                                                                                                                       




                                                                



                                          
                                                             
      
                                  


                                          
                                                             
      
























                                                                        


    
{ lib, pkgs, config, ... }:
let
  sieve_bin = pkgs.runCommand "sieve_bin" {
    buildInputs = [ pkgs.makeWrapper ];
  } ''
    cp -a ${./sieve_bin} $out
    chmod -R u+w $out
    patchShebangs $out
    for i in $out/*; do
      wrapProgram "$i" --prefix PATH : ${lib.makeBinPath [ pkgs.coreutils ]}
    done
    '';
in
{
  config = lib.mkIf config.myServices.mail.enable {
    myServices.dns.zones."immae.eu".subdomains =
      with config.myServices.dns.helpers;
      {
        imap = ips servers.eldiron.ips.main;
        pop3 = ips servers.eldiron.ips.main;
      };

    myServices.chatonsProperties.services.email = {
      file.datetime = "2022-08-22T01:00:00";
      service = {
        name = "E-mail account";
        description = "Compte e-mail avec configuration imap et smtp/pop3";
        logo = "https://www.dovecot.org/wp-content/uploads/2021/09/favicon.ico";
        website = "https://mail.immae.eu/";
        status.level = "OK";
        status.description = "OK";
        registration."" = ["MEMBER" "CLIENT"];
        registration.load = "OPEN";
        install.type = "PACKAGE";
      };
      software = {
        name = "Dovecot";
        website = "https://www.dovecot.org/";
        license.url = "https://github.com/dovecot/core/blob/main/COPYING";
        license.name = "MIT and LGPLv2.1 Licenses";
        version = pkgs.dovecot.version;
        source.url = "https://github.com/dovecot/core";
        modules = ["roundcube" "rainloop"] ++ map (a: a.pname) config.services.dovecot2.modules;
      };
    };
    systemd.services.dovecot2.serviceConfig.Slice = "mail.slice";
    secrets.keys."dovecot/sql" = {
      user = config.services.dovecot2.user;
      group = config.services.dovecot2.group;
      permissions = "0400";
      text = ''
        driver = mysql
        connect = host=${config.myEnv.mail.dovecot.mysql.socket} dbname=${config.myEnv.mail.dovecot.mysql.database} user=${config.myEnv.mail.dovecot.mysql.user} password=${config.myEnv.mail.dovecot.mysql.password}
        password_query = SELECT NULL AS password, 'Y' as noauthenticate, destination AS user \
          FROM forwardings WHERE \
            ((regex = 1 AND '%u' REGEXP CONCAT('^',source,'$')) OR (regex = 0 AND source = '%u')) \
            AND active = 1
      '';
    };
    secrets.keys."dovecot/ldap" = {
      user = config.services.dovecot2.user;
      group = config.services.dovecot2.group;
      permissions = "0400";
      text = ''
        hosts = ${config.myEnv.mail.dovecot.ldap.host}
        tls = yes

        dn = ${config.myEnv.mail.dovecot.ldap.dn}
        dnpass = ${config.myEnv.mail.dovecot.ldap.password}

        auth_bind = yes

        ldap_version = 3

        base = ${config.myEnv.mail.dovecot.ldap.base}
        scope = subtree

        pass_filter = ${config.myEnv.mail.dovecot.ldap.filter}
        pass_attrs = ${config.myEnv.mail.dovecot.ldap.pass_attrs}

        user_attrs = ${config.myEnv.mail.dovecot.ldap.user_attrs}
        user_filter = ${config.myEnv.mail.dovecot.ldap.filter}
        iterate_attrs = ${config.myEnv.mail.dovecot.ldap.iterate_attrs}
        iterate_filter = ${config.myEnv.mail.dovecot.ldap.iterate_filter}
        '';
    };

    users.users.vhost = {
      group = "vhost";
      uid = config.ids.uids.vhost;
    };
    users.groups.vhost.gid = config.ids.gids.vhost;
    users.users."${config.services.dovecot2.user}".extraGroups = [ "acme" ];

    nixpkgs.overlays = [
      (self: super: {
        dovecot = super.dovecot.override { withMySQL = true; openldap = self.openldap_libressl_cyrus; };
      })
    ];

    # https://blog.zeninc.net/index.php?post/2018/04/01/Un-annuaire-pour-les-gouverner-tous.......
    services.dovecot2 = {
      enable = true;
      enablePAM = false;
      enablePop3 = true;
      enableImap = true;
      enableLmtp = true;
      protocols = [ "sieve" ];
      modules = [
        pkgs.dovecot_pigeonhole
        pkgs.dovecot_fts_xapian
      ];
      mailUser = "vhost";
      mailGroup = "vhost";
      createMailUser = false;
      mailboxes = {
        Trash  = { auto = "subscribe"; specialUse = "Trash"; };
        Junk   = { auto = "subscribe"; specialUse = "Junk"; };
        Sent   = { auto = "subscribe"; specialUse = "Sent"; };
        Drafts = { auto = "subscribe"; specialUse = "Drafts"; };
      };
      mailLocation = "mbox:~/Mail:INBOX=~/Mail/Inbox:INDEX=~/.imap";
      sslServerCert = "/etc/dovecot/fullchain.pem";
      sslServerKey = "/var/lib/acme/mail/key.pem";
      sslCACert = "/etc/dovecot/fullchain.pem";
      extraConfig = builtins.concatStringsSep "\n" [
        # For printer which doesn’t support elliptic curve
        ''
          ssl_alt_cert = </etc/dovecot/fullchain-rsa.pem
          ssl_alt_key = </var/lib/acme/mail-rsa/key.pem
        ''

        ''
          postmaster_address = postmaster@immae.eu
          mail_attribute_dict = file:%h/dovecot-attributes
          imap_idle_notify_interval = 20 mins
          namespace inbox {
            type = private
            separator = /
            inbox = yes
            list = yes
          }
        ''

        # ACL
        ''
          mail_plugins = $mail_plugins acl
          plugin {
            acl = vfile:${pkgs.writeText "dovecot-acl" ''
              Backup/* owner lrp
              ''}
            acl_globals_only = yes
          }
        ''

        # Full text search
        ''
          # needs to be bigger than any mailbox size
          default_vsz_limit = 2GB
          mail_plugins = $mail_plugins fts fts_xapian
          plugin {
            plugin = fts fts_xapian
            fts = xapian
            fts_xapian = partial=2 full=20
            fts_autoindex = yes
            fts_autoindex_exclude = \Junk
            fts_autoindex_exclude2 = \Trash
            fts_autoindex_exclude3 = Virtual/*
          }
        ''

        # Antispam
        # https://docs.iredmail.org/dovecot.imapsieve.html
        ''
        # imap_sieve plugin added below

        plugin {
            sieve_plugins = sieve_imapsieve sieve_extprograms
            imapsieve_url = sieve://127.0.0.1:4190

            sieve_before = file:${./sieve_scripts}/backup.sieve;bindir=/var/lib/vhost/.sieve_bin

            # From elsewhere to Junk folder
            imapsieve_mailbox1_name = Junk
            imapsieve_mailbox1_causes = COPY APPEND
            imapsieve_mailbox1_before = file:${./sieve_scripts}/report_spam.sieve;bindir=/var/lib/vhost/.imapsieve_bin

            # From Junk folder to elsewhere
            imapsieve_mailbox2_name = *
            imapsieve_mailbox2_from = Junk
            imapsieve_mailbox2_causes = COPY
            imapsieve_mailbox2_before = file:${./sieve_scripts}/report_ham.sieve;bindir=/var/lib/vhost/.imapsieve_bin

            # From anywhere to NoJunk folder
            imapsieve_mailbox3_name = NoJunk
            imapsieve_mailbox3_causes = COPY APPEND
            imapsieve_mailbox3_before = file:${./sieve_scripts}/report_ham.sieve;bindir=/var/lib/vhost/.imapsieve_bin

            sieve_pipe_bin_dir = ${sieve_bin}

            sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
        }
        ''
        # Services to listen
        ''
        service imap-login {
          inet_listener imap {
          }
          inet_listener imaps {
          }
        }
        service pop3-login {
          inet_listener pop3 {
          }
          inet_listener pop3s {
          }
        }
        service imap {
        }
        service pop3 {
        }
        service auth {
          unix_listener auth-userdb {
          }
          unix_listener ${config.services.postfix.config.queue_directory}/private/auth {
            mode = 0666
          }
        }
        service auth-worker {
        }
        service dict {
          unix_listener dict {
          }
        }
        service stats {
          unix_listener stats-reader {
            user = vhost
            group = vhost
            mode = 0660
          }
          unix_listener stats-writer {
            user = vhost
            group = vhost
            mode = 0660
          }
        }
        ''

        # Authentification
        ''
        first_valid_uid = ${toString config.ids.uids.vhost}
        disable_plaintext_auth = yes
        passdb {
          driver = sql
          args = ${config.secrets.fullPaths."dovecot/sql"}
        }
        passdb {
          driver = ldap
          args = ${config.secrets.fullPaths."dovecot/ldap"}
        }
        userdb {
          driver = ldap
          args = ${config.secrets.fullPaths."dovecot/ldap"}
        }
        ''

        # Zlib
        ''
        mail_plugins = $mail_plugins zlib
        plugin {
          zlib_save_level = 6
          zlib_save = gz
        }
        ''

        # Sieve
        ''
        plugin {
          sieve = file:~/sieve;bindir=~/.sieve-bin;active=~/.dovecot.sieve
        }
        service managesieve-login {
        }
        service managesieve {
        }
        ''

        # Virtual mailboxes
        ''
        mail_plugins = $mail_plugins virtual
        namespace Virtual {
          prefix = Virtual/
          location = virtual:~/Virtual
        }
        ''

        # Protocol specific configuration
        # Needs to come last if there are mail_plugins entries
        ''
        protocol imap {
          mail_plugins = $mail_plugins imap_sieve imap_acl
        }
        protocol lda {
          mail_plugins = $mail_plugins sieve
        }
        ''
      ];
    };
    networking.firewall.allowedTCPPorts = [ 110 143 993 995 4190 ];
    system.activationScripts.dovecot = {
      deps = [ "users" ];
      text  =''
        install -m 0755 -o vhost -g vhost -d /var/lib/vhost
        '';
    };

    services.cron.systemCronJobs = let
      cron_script = pkgs.writeScriptBin "cleanup-imap-folders" ''
        ${pkgs.dovecot}/bin/doveadm expunge -A MAILBOX "Backup/*" NOT FLAGGED BEFORE 8w 2>&1 > /dev/null | grep -v "Mailbox doesn't exist:" | grep -v "Info: Opening DB"
        ${pkgs.dovecot}/bin/doveadm expunge -A MAILBOX Junk SEEN NOT FLAGGED BEFORE 4w 2>&1 > /dev/null | grep -v "Mailbox doesn't exist:" | grep -v "Info: Opening DB"
        ${pkgs.dovecot}/bin/doveadm expunge -A MAILBOX Trash NOT FLAGGED BEFORE 4w 2>&1 > /dev/null | grep -v "Mailbox doesn't exist:" | grep -v "Info: Opening DB"
        '';
      in
      [
        "0 2 * * * root ${cron_script}/bin/cleanup-imap-folders"
      ];
    security.acme.certs."mail-rsa" = {
      postRun = ''
        systemctl restart dovecot2.service
      '';
      extraDomainNames = [ "imap.immae.eu" "pop3.immae.eu" ];
    };
    security.acme.certs."mail" = {
      postRun = ''
        systemctl restart dovecot2.service
      '';
      extraDomainNames = [ "imap.immae.eu" "pop3.immae.eu" ];
    };
    myServices.monitoring.fromMasterActivatedPlugins = [ "imap" "tcp" ];
    myServices.monitoring.fromMasterObjects.service = [
      {
        service_description = "imap connection works";
        host_name = config.hostEnv.fqdn;
        use = "external-service";
        check_command = "check_imap_connection";

        servicegroups = "webstatus-remote-services,webstatus-email";
        _webstatus_name = "IMAP";
        _webstatus_url = "imap.immae.eu";
      }

      {
        service_description = "imap SSL is up to date";
        host_name = config.hostEnv.fqdn;
        use = "external-service";
        check_command = ["check_tcp_ssl" "993"];

        servicegroups = "webstatus-ssl";
        _webstatus_name = "IMAP";
        _webstatus_url = "imap.immae.eu";
      }

    ];
  };
}