summaryrefslogtreecommitdiff
path: root/os/kay/modules/mail.nix
blob: 5c8cb962a7b53ef76614bcf7f9be895a68961d7d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
{ config, ... }: 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.stalwart-mail = {
    enable = false;
    openFirewall = true;

    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";
        };
        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 = "relaxed/relaxed"; # what

          expire = "10d";
          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 = "relaxed/relaxed"; # what

          expire = "10d";
          report = true;
        };
      };

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

      storage = {
        data = "rocksdb";
        fts = "rocksdb";
        blob = "rocksdb";
        lookup = "rocksdb";
        directory = "in-memory";
      };
      store.rocksdb = {
        type = "rocksdb";
        path = "rocksdb";
        compression = "lz4";
      };

      directory."in-memory" = {
        type = "memory";
        options.subaddressing = true;

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