summaryrefslogblamecommitdiff
path: root/os/kay/modules/mail.nix
blob: 22f9c2d11ea4ec11ab68f4274def23c8c1adbe4f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                          
                               
                                         
                                         

                           
                        


                          



                                                                   
                                                                                    


                                       
                                   

    
                                                                 
                                                                    
 

                                                                            
 


                                                                          
 







                                     
                            
                  

                        















                                                                              
                




                                       
 
                         















                                                 
                              




                             



                   
                                                                     
                         
                           

                                                                
                                             
 

                                 
                        

                   
                                                                         
                         
                               
                                                                
                                       
                                             
 

                                 




                               

                                                              

        
                 



                              
                             
        




                              


                                  

        
                            
                        
 

                      
                            
                            
                                                                  
                          

                                         
                                 
                             

                                                                  

           



        
{ config, pkgs, ... }: let
  ipv6 = "2001:470:ee65::1337";
  domain = config.global.userdata.domain;
  username = config.global.userdata.name;
  email = [
    "${username}@${domain}"
    "official@${domain}"

    "postmaster@${domain}"
    "hostmaster@${domain}"
  ];

  credentials_directory = "/run/credentials/stalwart-mail.service";
in {
  security.acme.certs.${domain}.postRun = "systemctl restart stalwart-mail.service";
  sops.secrets = {
    "mail.${domain}/dkim_rsa" = {};
    "mail.${domain}/dkim_ed25519" = {};
    "mail.${domain}/password" = {};
  };

  systemd.services.stalwart-mail.serviceConfig.LoadCredential = [
    "password:${config.sops.secrets."mail.${domain}/password".path}"

    "dkim_rsa:${config.sops.secrets."mail.${domain}/dkim_rsa".path}"
    "dkim_ed25519:${config.sops.secrets."mail.${domain}/dkim_ed25519".path}"

    "cert:${config.security.acme.certs.${domain}.directory}/fullchain.pem"
    "key:${config.security.acme.certs.${domain}.directory}/key.pem"
  ];

  services.postgresql = {
    ensureDatabases = [ "stalwart" ];
    ensureUsers = [{
      name = "stalwart";
      ensureDBOwnership = true;
    }];
  };

  services.stalwart-mail = {
    enable = true;
    openFirewall = true;

    # foundation db is too big to build on a 32GB ram machine, good job
    # trillion dollar company, proud of you
    package = pkgs.stalwart-mail.overrideAttrs {
      buildNoDefaultFeatures = true;
      buildFeatures = [ "postgres" ];
      buildInputs = with pkgs; [
        bzip2
        openssl
        zstd
      ];
      # some tests fails with -lfdb_c: No such file, just disable this for row
      # probably because of not including foundationdb, upstream has this
      # enabled so it's not the end of the world
      doCheck = false;
    };

    settings = {
      queue.outbound = {
        ip-strategy = "ipv6_then_ipv4";
        source-ip.v6 = "['${ipv6}']";
        tls.starttls = "optional";
      };

      server.listener = {
        smtp = {
          bind = [ "[${ipv6}]:25" "0.0.0.0:25" ];
          protocol = "smtp";
        };
        submission = {
          bind = "[::]:587";
          protocol = "smtp";
        };
        submissions = {
          bind = "[::]:465";
          protocol = "smtp";
          tls.implicit = true;
        };
        imaptls = {
          bind = "[::]:993";
          protocol = "imap";
          tls.implicit = true;
        };
        http = {
          bind = "[::]:8085";
          protocol = "http";
        };
      };

      signature = {
        rsa = {
          private-key = "%{file:${credentials_directory}/dkim_rsa}%";
          inherit domain;
          selector = "rsa";
          headers = ["From" "To" "Date" "Subject" "Message-ID"];
          algorithm = "rsa-sha-256";
          canonicalization = "simple/simple";

          set-body-length = true;
          expire = "2d";
          report = true;
        };
        ed25519 = {
          private-key = "%{file:${credentials_directory}/dkim_ed25519}%";
          inherit domain;
          selector = "ed25519";
          headers = ["From" "To" "Date" "Subject" "Message-ID"];
          algorithm = "ed25519-sha256";
          canonicalization = "simple/simple";

          set-body-length = true;
          expire = "2d";
          report = true;
        };
      };

      certificate."default" = {
        cert = "%{file:${credentials_directory}/cert}%";
        private-key = "%{file:${credentials_directory}/key}%";
      };

      storage = {
        data = "postgresql";
        fts = "postgresql";
        blob = "postgresql";
        lookup = "postgresql";
        directory = "memory";
      };
      store.postgresql = {
        type = "postgresql";
        host = "localhost";
        database = "stalwart";
        user = "stalwart";
        timeout = "15s";
        tls.enable = false;
        pool.max-connections = 10;
      };

      directory."memory" = {
        type = "memory";

        principals = [
          {
            class = "admin";
            name = username;
            secret = "%{file:${credentials_directory}/password}%";
            inherit email;
          }
          { # for mta-sts & dmarc reports
            class = "individual";
            name = "reports";
            secret = "%{file:${credentials_directory}/password}%";
            email = [ "reports@${domain}" ];
          }
        ];
      };
    };
  };
}