char/topaz-flake

git clone https://git.t4t.associates/char/topaz-flake

Charlotte Somsync mail faster405f936

main
4.9 KiB179 linesraw
1{
2  config,
3  lib,
4  pkgs,
5  ...
6}:
7let
8  domain = "mail.char.lt";
9  cert = config.security.acme.certs.${domain};
10  accounts = {
11    som-codes = "charlotte@som.codes";
12    char-lt = "c@char.lt";
13  };
14  passwordFile = name: "/var/secrets/mail/${name}.password";
15  mbsyncConfig =
16    name: username:
17    pkgs.writeText "mbsync-${name}.conf" ''
18      IMAPAccount migadu
19      Host imap.migadu.com
20      Port 993
21      User ${username}
22      PassCmd "${pkgs.coreutils}/bin/cat $CREDENTIALS_DIRECTORY/password"
23      TLSType IMAPS
24      CertificateFile /etc/ssl/certs/ca-certificates.crt
25
26      IMAPStore remote
27      Account migadu
28
29      IMAPAccount dovecot
30      Host 127.0.0.1
31      Port 143
32      User ${username}
33      PassCmd "${pkgs.coreutils}/bin/cat $CREDENTIALS_DIRECTORY/password"
34      TLSType None
35      AuthMechs PLAIN
36
37      IMAPStore local
38      Account dovecot
39
40      Channel mail
41      Far :remote:
42      Near :local:
43      Patterns *
44      Sync All
45      Create Both
46      Remove Both
47      Expunge Both
48      CopyArrivalDate yes
49      SyncState /var/lib/mail-sync/${name}/
50    '';
51in
52{
53  services.nginx.virtualHosts.${domain} = {
54    enableACME = true;
55    locations."/".return = "404";
56  };
57  security.acme.certs.${domain}.reloadServices = [ "dovecot.service" ];
58  networking.firewall.allowedTCPPorts = [ 993 ];
59
60  services.dovecot2 = {
61    enable = true;
62    package = pkgs.dovecot;
63    settings = {
64      dovecot_config_version = "2.4.4";
65      dovecot_storage_version = "2.4.4";
66      protocols.imap = true;
67      hostname = domain;
68      ssl = "required";
69      ssl_server_cert_file = "${cert.directory}/fullchain.pem";
70      ssl_server_key_file = "${cert.directory}/key.pem";
71
72      mail_uid = "dovemail";
73      mail_gid = "dovemail";
74      first_valid_uid = 1;
75      mail_driver = "maildir";
76      mail_path = "~/Maildir";
77      "namespace inbox" = {
78        inbox = true;
79        separator = "/";
80      };
81      "passdb passwd-file".passwd_file_path = "/run/dovecot2/passwd";
82      "userdb passwd-file".passwd_file_path = "/run/dovecot2/passwd";
83
84      mail_plugins = {
85        fts = true;
86        fts_flatcurve = true;
87      };
88      "fts flatcurve" = { };
89      fts_autoindex = true;
90      fts_flatcurve_substring_search = true;
91      "language en".default = true;
92      language_tokenizers = "generic email-address";
93      language_filters = "normalizer-icu";
94
95      # Sync over IMAP so Dovecot alone manages Maildir UIDs and indexes.
96      "service imap-login" = {
97        "inet_listener imap" = {
98          listen = "127.0.0.1";
99          port = 143;
100        };
101        "inet_listener imaps" = {
102          port = 993;
103          ssl = true;
104        };
105      };
106    };
107  };
108
109  systemd.tmpfiles.rules = [ "d /var/lib/mail 0700 dovemail dovemail -" ];
110
111  users.users.mail-sync = {
112    isSystemUser = true;
113    group = "mail-sync";
114  };
115  users.groups.mail-sync = { };
116
117  systemd.services = {
118    dovecot = {
119      wants = [ "acme-finished-${domain}.target" ];
120      after = [ "acme-finished-${domain}.target" ];
121      serviceConfig.LoadCredential = lib.mapAttrsToList (
122        name: _: "${name}:${passwordFile name}"
123      ) accounts;
124      preStart = lib.mkAfter ''
125        umask 077
126        : > /run/dovecot2/passwd.new
127        ${lib.concatStringsSep "\n" (
128          lib.mapAttrsToList (name: username: ''
129            test -n "$(cat "$CREDENTIALS_DIRECTORY/${name}")"
130            hash=$(${pkgs.openssl}/bin/openssl passwd -6 -stdin < "$CREDENTIALS_DIRECTORY/${name}")
131            [[ "$hash" != *$'\n'* ]]
132            printf '${username}:{CRYPT}%s:%s:%s::/var/lib/mail/${username}\n' \
133              "$hash" "$(id -u dovemail)" "$(id -g dovemail)" >> /run/dovecot2/passwd.new
134          '') accounts
135        )}
136        chown root:dovecot2 /run/dovecot2/passwd.new
137        chmod 640 /run/dovecot2/passwd.new
138        mv /run/dovecot2/passwd.new /run/dovecot2/passwd
139      '';
140    };
141  }
142  // lib.mapAttrs' (
143    name: username:
144    lib.nameValuePair "mail-sync-${name}" {
145      description = "Synchronise ${username} with Migadu";
146      wants = [ "network-online.target" ];
147      requires = [ "dovecot.service" ];
148      after = [
149        "network-online.target"
150        "dovecot.service"
151      ];
152      serviceConfig = {
153        Type = "oneshot";
154        User = "mail-sync";
155        Group = "mail-sync";
156        StateDirectory = "mail-sync/${name}";
157        StateDirectoryMode = "0700";
158        UMask = "0077";
159        LoadCredential = [ "password:${passwordFile name}" ];
160        ExecStart = "${pkgs.isync}/bin/mbsync --config ${mbsyncConfig name username} --all";
161        NoNewPrivileges = true;
162        PrivateTmp = true;
163        ProtectHome = true;
164        ProtectSystem = "strict";
165      };
166    }
167  ) accounts;
168
169  systemd.timers = lib.mapAttrs' (
170    name: _:
171    lib.nameValuePair "mail-sync-${name}" {
172      wantedBy = [ "timers.target" ];
173      timerConfig = {
174        OnBootSec = "1min";
175        OnUnitInactiveSec = "1min";
176      };
177    }
178  ) accounts;
179}