diff options
Diffstat (limited to 'modules/private/mail/postfix.nix')
-rw-r--r-- | modules/private/mail/postfix.nix | 488 |
1 files changed, 245 insertions, 243 deletions
diff --git a/modules/private/mail/postfix.nix b/modules/private/mail/postfix.nix index edfd196..9fdc7bd 100644 --- a/modules/private/mail/postfix.nix +++ b/modules/private/mail/postfix.nix | |||
@@ -1,267 +1,269 @@ | |||
1 | { lib, pkgs, config, myconfig, ... }: | 1 | { lib, pkgs, config, myconfig, ... }: |
2 | { | 2 | { |
3 | config.services.backup.profiles.mail.excludeFile = '' | 3 | config = lib.mkIf config.myServices.mail.enable { |
4 | + /var/lib/postfix | 4 | services.backup.profiles.mail.excludeFile = '' |
5 | ''; | 5 | + /var/lib/postfix |
6 | config.secrets.keys = [ | 6 | ''; |
7 | { | 7 | secrets.keys = [ |
8 | dest = "postfix/mysql_alias_maps"; | 8 | { |
9 | user = config.services.postfix.user; | 9 | dest = "postfix/mysql_alias_maps"; |
10 | group = config.services.postfix.group; | 10 | user = config.services.postfix.user; |
11 | permissions = "0440"; | 11 | group = config.services.postfix.group; |
12 | text = '' | 12 | permissions = "0440"; |
13 | # We need to specify that option to trigger ssl connection | 13 | text = '' |
14 | tls_ciphers = TLSv1.2 | 14 | # We need to specify that option to trigger ssl connection |
15 | user = ${myconfig.env.mail.postfix.mysql.user} | 15 | tls_ciphers = TLSv1.2 |
16 | password = ${myconfig.env.mail.postfix.mysql.password} | 16 | user = ${myconfig.env.mail.postfix.mysql.user} |
17 | hosts = unix:${myconfig.env.mail.postfix.mysql.socket} | 17 | password = ${myconfig.env.mail.postfix.mysql.password} |
18 | dbname = ${myconfig.env.mail.postfix.mysql.database} | 18 | hosts = unix:${myconfig.env.mail.postfix.mysql.socket} |
19 | query = SELECT DISTINCT destination | 19 | dbname = ${myconfig.env.mail.postfix.mysql.database} |
20 | FROM forwardings_merge | 20 | query = SELECT DISTINCT destination |
21 | WHERE | 21 | FROM forwardings_merge |
22 | ((regex = 1 AND '%s' REGEXP CONCAT('^',source,'$') ) OR (regex = 0 AND source = '%s')) | 22 | WHERE |
23 | AND active = 1 | 23 | ((regex = 1 AND '%s' REGEXP CONCAT('^',source,'$') ) OR (regex = 0 AND source = '%s')) |
24 | AND '%s' NOT IN | 24 | AND active = 1 |
25 | ( | 25 | AND '%s' NOT IN |
26 | SELECT source | 26 | ( |
27 | SELECT source | ||
28 | FROM forwardings_blacklisted | ||
29 | WHERE source = '%s' | ||
30 | ) UNION | ||
31 | SELECT 'devnull@immae.eu' | ||
27 | FROM forwardings_blacklisted | 32 | FROM forwardings_blacklisted |
28 | WHERE source = '%s' | 33 | WHERE source = '%s' |
29 | ) UNION | 34 | ''; |
30 | SELECT 'devnull@immae.eu' | 35 | } |
31 | FROM forwardings_blacklisted | 36 | { |
32 | WHERE source = '%s' | 37 | dest = "postfix/mysql_mailbox_maps"; |
33 | ''; | 38 | user = config.services.postfix.user; |
34 | } | 39 | group = config.services.postfix.group; |
35 | { | 40 | permissions = "0440"; |
36 | dest = "postfix/mysql_mailbox_maps"; | 41 | text = '' |
37 | user = config.services.postfix.user; | 42 | # We need to specify that option to trigger ssl connection |
38 | group = config.services.postfix.group; | 43 | tls_ciphers = TLSv1.2 |
39 | permissions = "0440"; | 44 | user = ${myconfig.env.mail.postfix.mysql.user} |
40 | text = '' | 45 | password = ${myconfig.env.mail.postfix.mysql.password} |
41 | # We need to specify that option to trigger ssl connection | 46 | hosts = unix:${myconfig.env.mail.postfix.mysql.socket} |
42 | tls_ciphers = TLSv1.2 | 47 | dbname = ${myconfig.env.mail.postfix.mysql.database} |
43 | user = ${myconfig.env.mail.postfix.mysql.user} | 48 | result_format = /%d/%u |
44 | password = ${myconfig.env.mail.postfix.mysql.password} | 49 | query = SELECT DISTINCT '%s' |
45 | hosts = unix:${myconfig.env.mail.postfix.mysql.socket} | 50 | FROM mailboxes |
46 | dbname = ${myconfig.env.mail.postfix.mysql.database} | 51 | WHERE active = 1 |
47 | result_format = /%d/%u | 52 | AND ( |
48 | query = SELECT DISTINCT '%s' | 53 | (domain = '%d' AND user = '%u' AND regex = 0) |
49 | FROM mailboxes | 54 | OR ( |
50 | WHERE active = 1 | 55 | regex = 1 |
51 | AND ( | 56 | AND '%d' REGEXP CONCAT('^',domain,'$') |
52 | (domain = '%d' AND user = '%u' AND regex = 0) | 57 | AND '%u' REGEXP CONCAT('^',user,'$') |
53 | OR ( | 58 | ) |
54 | regex = 1 | ||
55 | AND '%d' REGEXP CONCAT('^',domain,'$') | ||
56 | AND '%u' REGEXP CONCAT('^',user,'$') | ||
57 | ) | 59 | ) |
58 | ) | 60 | LIMIT 1 |
59 | LIMIT 1 | ||
60 | ''; | ||
61 | } | ||
62 | { | ||
63 | dest = "postfix/mysql_sender_login_maps"; | ||
64 | user = config.services.postfix.user; | ||
65 | group = config.services.postfix.group; | ||
66 | permissions = "0440"; | ||
67 | text = '' | ||
68 | # We need to specify that option to trigger ssl connection | ||
69 | tls_ciphers = TLSv1.2 | ||
70 | user = ${myconfig.env.mail.postfix.mysql.user} | ||
71 | password = ${myconfig.env.mail.postfix.mysql.password} | ||
72 | hosts = unix:${myconfig.env.mail.postfix.mysql.socket} | ||
73 | dbname = ${myconfig.env.mail.postfix.mysql.database} | ||
74 | query = SELECT DISTINCT destination | ||
75 | FROM forwardings_merge | ||
76 | WHERE | ||
77 | ((regex = 1 AND '%s' REGEXP CONCAT('^',source,'$') ) OR (regex = 0 AND source = '%s')) | ||
78 | AND active = 1 | ||
79 | UNION SELECT '%s' AS destination | ||
80 | ''; | 61 | ''; |
81 | } | 62 | } |
82 | ]; | 63 | { |
64 | dest = "postfix/mysql_sender_login_maps"; | ||
65 | user = config.services.postfix.user; | ||
66 | group = config.services.postfix.group; | ||
67 | permissions = "0440"; | ||
68 | text = '' | ||
69 | # We need to specify that option to trigger ssl connection | ||
70 | tls_ciphers = TLSv1.2 | ||
71 | user = ${myconfig.env.mail.postfix.mysql.user} | ||
72 | password = ${myconfig.env.mail.postfix.mysql.password} | ||
73 | hosts = unix:${myconfig.env.mail.postfix.mysql.socket} | ||
74 | dbname = ${myconfig.env.mail.postfix.mysql.database} | ||
75 | query = SELECT DISTINCT destination | ||
76 | FROM forwardings_merge | ||
77 | WHERE | ||
78 | ((regex = 1 AND '%s' REGEXP CONCAT('^',source,'$') ) OR (regex = 0 AND source = '%s')) | ||
79 | AND active = 1 | ||
80 | UNION SELECT '%s' AS destination | ||
81 | ''; | ||
82 | } | ||
83 | ]; | ||
83 | 84 | ||
84 | config.networking.firewall.allowedTCPPorts = [ 25 465 587 ]; | 85 | networking.firewall.allowedTCPPorts = [ 25 465 587 ]; |
85 | 86 | ||
86 | config.nixpkgs.overlays = [ (self: super: { | 87 | nixpkgs.overlays = [ (self: super: { |
87 | postfix = super.postfix.override { withMySQL = true; }; | 88 | postfix = super.postfix.override { withMySQL = true; }; |
88 | }) ]; | 89 | }) ]; |
89 | config.users.users."${config.services.postfix.user}".extraGroups = [ "keys" ]; | 90 | users.users."${config.services.postfix.user}".extraGroups = [ "keys" ]; |
90 | config.services.filesWatcher.postfix = { | 91 | services.filesWatcher.postfix = { |
91 | restart = true; | 92 | restart = true; |
92 | paths = [ | 93 | paths = [ |
93 | config.secrets.fullPaths."postfix/mysql_alias_maps" | 94 | config.secrets.fullPaths."postfix/mysql_alias_maps" |
94 | config.secrets.fullPaths."postfix/mysql_mailbox_maps" | 95 | config.secrets.fullPaths."postfix/mysql_mailbox_maps" |
95 | config.secrets.fullPaths."postfix/mysql_sender_login_maps" | 96 | config.secrets.fullPaths."postfix/mysql_sender_login_maps" |
96 | ]; | 97 | ]; |
97 | }; | 98 | }; |
98 | config.services.postfix = { | 99 | services.postfix = { |
99 | mapFiles = let | 100 | mapFiles = let |
100 | recipient_maps = let | 101 | recipient_maps = let |
101 | name = n: i: "relay_${n}_${toString i}"; | 102 | name = n: i: "relay_${n}_${toString i}"; |
102 | pair = n: i: m: lib.attrsets.nameValuePair (name n i) ( | 103 | pair = n: i: m: lib.attrsets.nameValuePair (name n i) ( |
103 | if m.type == "hash" | 104 | if m.type == "hash" |
104 | then pkgs.writeText (name n i) m.content | 105 | then pkgs.writeText (name n i) m.content |
105 | else null | ||
106 | ); | ||
107 | pairs = n: v: lib.imap1 (i: m: pair n i m) v.recipient_maps; | ||
108 | in lib.attrsets.filterAttrs (k: v: v != null) ( | ||
109 | lib.attrsets.listToAttrs (lib.flatten ( | ||
110 | lib.attrsets.mapAttrsToList pairs myconfig.env.mail.postfix.backup_domains | ||
111 | )) | ||
112 | ); | ||
113 | relay_restrictions = lib.attrsets.filterAttrs (k: v: v != null) ( | ||
114 | lib.attrsets.mapAttrs' (n: v: | ||
115 | lib.attrsets.nameValuePair "recipient_access_${n}" ( | ||
116 | if lib.attrsets.hasAttr "relay_restrictions" v | ||
117 | then pkgs.writeText "recipient_access_${n}" v.relay_restrictions | ||
118 | else null | 106 | else null |
119 | ) | 107 | ); |
120 | ) myconfig.env.mail.postfix.backup_domains | 108 | pairs = n: v: lib.imap1 (i: m: pair n i m) v.recipient_maps; |
121 | ); | 109 | in lib.attrsets.filterAttrs (k: v: v != null) ( |
122 | in | 110 | lib.attrsets.listToAttrs (lib.flatten ( |
123 | recipient_maps // relay_restrictions; | 111 | lib.attrsets.mapAttrsToList pairs myconfig.env.mail.postfix.backup_domains |
124 | config = { | 112 | )) |
125 | ### postfix module overrides | 113 | ); |
126 | readme_directory = "${pkgs.postfix}/share/postfix/doc"; | 114 | relay_restrictions = lib.attrsets.filterAttrs (k: v: v != null) ( |
127 | smtp_tls_CAfile = lib.mkForce ""; | 115 | lib.attrsets.mapAttrs' (n: v: |
128 | smtp_tls_cert_file = lib.mkForce ""; | 116 | lib.attrsets.nameValuePair "recipient_access_${n}" ( |
129 | smtp_tls_key_file = lib.mkForce ""; | 117 | if lib.attrsets.hasAttr "relay_restrictions" v |
118 | then pkgs.writeText "recipient_access_${n}" v.relay_restrictions | ||
119 | else null | ||
120 | ) | ||
121 | ) myconfig.env.mail.postfix.backup_domains | ||
122 | ); | ||
123 | in | ||
124 | recipient_maps // relay_restrictions; | ||
125 | config = { | ||
126 | ### postfix module overrides | ||
127 | readme_directory = "${pkgs.postfix}/share/postfix/doc"; | ||
128 | smtp_tls_CAfile = lib.mkForce ""; | ||
129 | smtp_tls_cert_file = lib.mkForce ""; | ||
130 | smtp_tls_key_file = lib.mkForce ""; | ||
130 | 131 | ||
131 | message_size_limit = "1073741824"; # Don't put 0 here, it's not equivalent to "unlimited" | 132 | message_size_limit = "1073741824"; # Don't put 0 here, it's not equivalent to "unlimited" |
132 | alias_database = "\$alias_maps"; | 133 | alias_database = "\$alias_maps"; |
133 | 134 | ||
134 | ### Virtual mailboxes config | 135 | ### Virtual mailboxes config |
135 | virtual_alias_maps = "mysql:${config.secrets.fullPaths."postfix/mysql_alias_maps"}"; | 136 | virtual_alias_maps = "mysql:${config.secrets.fullPaths."postfix/mysql_alias_maps"}"; |
136 | virtual_mailbox_domains = myconfig.env.mail.postfix.additional_mailbox_domains | 137 | virtual_mailbox_domains = myconfig.env.mail.postfix.additional_mailbox_domains |
137 | ++ lib.remove "localhost.immae.eu" (lib.remove null (lib.flatten (map | 138 | ++ lib.remove "localhost.immae.eu" (lib.remove null (lib.flatten (map |
138 | (zone: map | 139 | (zone: map |
139 | (e: if e.receive | 140 | (e: if e.receive |
140 | then "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}" | 141 | then "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}" |
141 | else null | 142 | else null |
143 | ) | ||
144 | (zone.withEmail or []) | ||
142 | ) | 145 | ) |
143 | (zone.withEmail or []) | 146 | myconfig.env.dns.masterZones |
144 | ) | 147 | ))); |
145 | myconfig.env.dns.masterZones | 148 | virtual_mailbox_maps = "mysql:${config.secrets.fullPaths."postfix/mysql_mailbox_maps"}"; |
146 | ))); | 149 | dovecot_destination_recipient_limit = "1"; |
147 | virtual_mailbox_maps = "mysql:${config.secrets.fullPaths."postfix/mysql_mailbox_maps"}"; | 150 | virtual_transport = "dovecot"; |
148 | dovecot_destination_recipient_limit = "1"; | ||
149 | virtual_transport = "dovecot"; | ||
150 | 151 | ||
151 | ### Relay domains | 152 | ### Relay domains |
152 | relay_domains = lib.flatten (lib.attrsets.mapAttrsToList (n: v: v.domains or []) myconfig.env.mail.postfix.backup_domains); | 153 | relay_domains = lib.flatten (lib.attrsets.mapAttrsToList (n: v: v.domains or []) myconfig.env.mail.postfix.backup_domains); |
153 | relay_recipient_maps = lib.flatten (lib.attrsets.mapAttrsToList (n: v: | 154 | relay_recipient_maps = lib.flatten (lib.attrsets.mapAttrsToList (n: v: |
154 | lib.imap1 (i: m: "${m.type}:/etc/postfix/relay_${n}_${toString i}") v.recipient_maps | 155 | lib.imap1 (i: m: "${m.type}:/etc/postfix/relay_${n}_${toString i}") v.recipient_maps |
155 | ) myconfig.env.mail.postfix.backup_domains); | 156 | ) myconfig.env.mail.postfix.backup_domains); |
156 | smtpd_relay_restrictions = [ | 157 | smtpd_relay_restrictions = [ |
157 | "permit_mynetworks" | 158 | "permit_mynetworks" |
158 | "permit_sasl_authenticated" | 159 | "permit_sasl_authenticated" |
159 | "defer_unauth_destination" | 160 | "defer_unauth_destination" |
160 | ] ++ lib.flatten (lib.attrsets.mapAttrsToList (n: v: | 161 | ] ++ lib.flatten (lib.attrsets.mapAttrsToList (n: v: |
161 | if lib.attrsets.hasAttr "relay_restrictions" v | 162 | if lib.attrsets.hasAttr "relay_restrictions" v |
162 | then [ "check_recipient_access hash:/etc/postfix/recipient_access_${n}" ] | 163 | then [ "check_recipient_access hash:/etc/postfix/recipient_access_${n}" ] |
163 | else [] | 164 | else [] |
164 | ) myconfig.env.mail.postfix.backup_domains); | 165 | ) myconfig.env.mail.postfix.backup_domains); |
165 | 166 | ||
166 | ### Additional smtpd configuration | 167 | ### Additional smtpd configuration |
167 | smtpd_tls_received_header = "yes"; | 168 | smtpd_tls_received_header = "yes"; |
168 | smtpd_tls_loglevel = "1"; | 169 | smtpd_tls_loglevel = "1"; |
169 | 170 | ||
170 | ### Email sending configuration | 171 | ### Email sending configuration |
171 | smtp_tls_security_level = "may"; | 172 | smtp_tls_security_level = "may"; |
172 | smtp_tls_loglevel = "1"; | 173 | smtp_tls_loglevel = "1"; |
173 | 174 | ||
174 | ### Force ip bind for smtp | 175 | ### Force ip bind for smtp |
175 | smtp_bind_address = myconfig.env.servers.eldiron.ips.main.ip4; | 176 | smtp_bind_address = myconfig.env.servers.eldiron.ips.main.ip4; |
176 | smtp_bind_address6 = builtins.head myconfig.env.servers.eldiron.ips.main.ip6; | 177 | smtp_bind_address6 = builtins.head myconfig.env.servers.eldiron.ips.main.ip6; |
177 | 178 | ||
178 | # #Unneeded if postfix can only send e-mail from "self" domains | 179 | # #Unneeded if postfix can only send e-mail from "self" domains |
179 | # #smtp_sasl_auth_enable = "yes"; | 180 | # #smtp_sasl_auth_enable = "yes"; |
180 | # #smtp_sasl_password_maps = "hash:/etc/postfix/relay_creds"; | 181 | # #smtp_sasl_password_maps = "hash:/etc/postfix/relay_creds"; |
181 | # #smtp_sasl_security_options = "noanonymous"; | 182 | # #smtp_sasl_security_options = "noanonymous"; |
182 | # #smtp_sender_dependent_authentication = "yes"; | 183 | # #smtp_sender_dependent_authentication = "yes"; |
183 | # #sender_dependent_relayhost_maps = "hash:/etc/postfix/sender_relay"; | 184 | # #sender_dependent_relayhost_maps = "hash:/etc/postfix/sender_relay"; |
184 | 185 | ||
185 | ### opendkim, opendmarc, openarc milters | 186 | ### opendkim, opendmarc, openarc milters |
186 | non_smtpd_milters = [ | 187 | non_smtpd_milters = [ |
187 | "unix:${config.myServices.mail.milters.sockets.opendkim}" | 188 | "unix:${config.myServices.mail.milters.sockets.opendkim}" |
188 | "unix:${config.myServices.mail.milters.sockets.opendmarc}" | 189 | "unix:${config.myServices.mail.milters.sockets.opendmarc}" |
189 | "unix:${config.myServices.mail.milters.sockets.openarc}" | 190 | "unix:${config.myServices.mail.milters.sockets.openarc}" |
190 | ]; | 191 | ]; |
191 | smtpd_milters = [ | 192 | smtpd_milters = [ |
192 | "unix:${config.myServices.mail.milters.sockets.opendkim}" | 193 | "unix:${config.myServices.mail.milters.sockets.opendkim}" |
193 | "unix:${config.myServices.mail.milters.sockets.opendmarc}" | 194 | "unix:${config.myServices.mail.milters.sockets.opendmarc}" |
194 | "unix:${config.myServices.mail.milters.sockets.openarc}" | 195 | "unix:${config.myServices.mail.milters.sockets.openarc}" |
195 | ]; | ||
196 | }; | ||
197 | enable = true; | ||
198 | enableSmtp = true; | ||
199 | enableSubmission = true; | ||
200 | submissionOptions = { | ||
201 | smtpd_tls_security_level = "encrypt"; | ||
202 | smtpd_sasl_auth_enable = "yes"; | ||
203 | smtpd_tls_auth_only = "yes"; | ||
204 | smtpd_sasl_tls_security_options = "noanonymous"; | ||
205 | smtpd_sasl_type = "dovecot"; | ||
206 | smtpd_sasl_path = "private/auth"; | ||
207 | smtpd_reject_unlisted_recipient = "no"; | ||
208 | smtpd_client_restrictions = "permit_sasl_authenticated,reject"; | ||
209 | # Refuse to send e-mails with a From that is not handled | ||
210 | smtpd_sender_restrictions = | ||
211 | "reject_sender_login_mismatch,reject_unlisted_sender,permit_sasl_authenticated,reject"; | ||
212 | smtpd_sender_login_maps = "mysql:${config.secrets.fullPaths."postfix/mysql_sender_login_maps"}"; | ||
213 | smtpd_recipient_restrictions = "permit_sasl_authenticated,reject"; | ||
214 | milter_macro_daemon_name = "ORIGINATING"; | ||
215 | smtpd_milters = "unix:${config.myServices.mail.milters.sockets.opendkim}"; | ||
216 | }; | ||
217 | # FIXME: Mail adressed to localhost.immae.eu will still have mx-1 as | ||
218 | # prioritized MX, which provokes "mail for localhost.immae.eu loops | ||
219 | # back to myself" errors. This transport entry forces to push | ||
220 | # e-mails to its right destination. | ||
221 | transport = '' | ||
222 | localhost.immae.eu smtp:[immae.eu]:25 | ||
223 | ''; | ||
224 | destination = ["localhost"]; | ||
225 | # This needs to reverse DNS | ||
226 | hostname = "eldiron.immae.eu"; | ||
227 | setSendmail = true; | ||
228 | sslCert = "/var/lib/acme/mail/fullchain.pem"; | ||
229 | sslKey = "/var/lib/acme/mail/key.pem"; | ||
230 | recipientDelimiter = "+"; | ||
231 | masterConfig = { | ||
232 | submissions = { | ||
233 | type = "inet"; | ||
234 | private = false; | ||
235 | command = "smtpd"; | ||
236 | args = ["-o" "smtpd_tls_wrappermode=yes" ] ++ (let | ||
237 | mkKeyVal = opt: val: [ "-o" (opt + "=" + val) ]; | ||
238 | in lib.concatLists (lib.mapAttrsToList mkKeyVal config.services.postfix.submissionOptions) | ||
239 | ); | ||
240 | }; | ||
241 | dovecot = { | ||
242 | type = "unix"; | ||
243 | privileged = true; | ||
244 | chroot = false; | ||
245 | command = "pipe"; | ||
246 | args = let | ||
247 | # rspamd could be used as a milter, but then it cannot apply | ||
248 | # its checks "per user" (milter is not yet dispatched to | ||
249 | # users), so we wrap dovecot-lda inside rspamc per recipient | ||
250 | # here. | ||
251 | dovecot_exe = "${pkgs.dovecot}/libexec/dovecot/dovecot-lda -f \${sender} -a \${original_recipient} -d \${user}@\${nexthop}"; | ||
252 | in [ | ||
253 | "flags=DRhu" "user=vhost:vhost" | ||
254 | "argv=${pkgs.rspamd}/bin/rspamc -h ${config.myServices.mail.rspamd.sockets.worker-controller} -c bayes -d \${user}@\${nexthop} --mime --exec {${dovecot_exe}}" | ||
255 | ]; | 196 | ]; |
256 | }; | 197 | }; |
198 | enable = true; | ||
199 | enableSmtp = true; | ||
200 | enableSubmission = true; | ||
201 | submissionOptions = { | ||
202 | smtpd_tls_security_level = "encrypt"; | ||
203 | smtpd_sasl_auth_enable = "yes"; | ||
204 | smtpd_tls_auth_only = "yes"; | ||
205 | smtpd_sasl_tls_security_options = "noanonymous"; | ||
206 | smtpd_sasl_type = "dovecot"; | ||
207 | smtpd_sasl_path = "private/auth"; | ||
208 | smtpd_reject_unlisted_recipient = "no"; | ||
209 | smtpd_client_restrictions = "permit_sasl_authenticated,reject"; | ||
210 | # Refuse to send e-mails with a From that is not handled | ||
211 | smtpd_sender_restrictions = | ||
212 | "reject_sender_login_mismatch,reject_unlisted_sender,permit_sasl_authenticated,reject"; | ||
213 | smtpd_sender_login_maps = "mysql:${config.secrets.fullPaths."postfix/mysql_sender_login_maps"}"; | ||
214 | smtpd_recipient_restrictions = "permit_sasl_authenticated,reject"; | ||
215 | milter_macro_daemon_name = "ORIGINATING"; | ||
216 | smtpd_milters = "unix:${config.myServices.mail.milters.sockets.opendkim}"; | ||
217 | }; | ||
218 | # FIXME: Mail adressed to localhost.immae.eu will still have mx-1 as | ||
219 | # prioritized MX, which provokes "mail for localhost.immae.eu loops | ||
220 | # back to myself" errors. This transport entry forces to push | ||
221 | # e-mails to its right destination. | ||
222 | transport = '' | ||
223 | localhost.immae.eu smtp:[immae.eu]:25 | ||
224 | ''; | ||
225 | destination = ["localhost"]; | ||
226 | # This needs to reverse DNS | ||
227 | hostname = "eldiron.immae.eu"; | ||
228 | setSendmail = true; | ||
229 | sslCert = "/var/lib/acme/mail/fullchain.pem"; | ||
230 | sslKey = "/var/lib/acme/mail/key.pem"; | ||
231 | recipientDelimiter = "+"; | ||
232 | masterConfig = { | ||
233 | submissions = { | ||
234 | type = "inet"; | ||
235 | private = false; | ||
236 | command = "smtpd"; | ||
237 | args = ["-o" "smtpd_tls_wrappermode=yes" ] ++ (let | ||
238 | mkKeyVal = opt: val: [ "-o" (opt + "=" + val) ]; | ||
239 | in lib.concatLists (lib.mapAttrsToList mkKeyVal config.services.postfix.submissionOptions) | ||
240 | ); | ||
241 | }; | ||
242 | dovecot = { | ||
243 | type = "unix"; | ||
244 | privileged = true; | ||
245 | chroot = false; | ||
246 | command = "pipe"; | ||
247 | args = let | ||
248 | # rspamd could be used as a milter, but then it cannot apply | ||
249 | # its checks "per user" (milter is not yet dispatched to | ||
250 | # users), so we wrap dovecot-lda inside rspamc per recipient | ||
251 | # here. | ||
252 | dovecot_exe = "${pkgs.dovecot}/libexec/dovecot/dovecot-lda -f \${sender} -a \${original_recipient} -d \${user}@\${nexthop}"; | ||
253 | in [ | ||
254 | "flags=DRhu" "user=vhost:vhost" | ||
255 | "argv=${pkgs.rspamd}/bin/rspamc -h ${config.myServices.mail.rspamd.sockets.worker-controller} -c bayes -d \${user}@\${nexthop} --mime --exec {${dovecot_exe}}" | ||
256 | ]; | ||
257 | }; | ||
258 | }; | ||
257 | }; | 259 | }; |
258 | }; | 260 | security.acme.certs."mail" = { |
259 | config.security.acme.certs."mail" = { | 261 | postRun = '' |
260 | postRun = '' | 262 | systemctl restart postfix.service |
261 | systemctl restart postfix.service | 263 | ''; |
262 | ''; | 264 | extraDomains = { |
263 | extraDomains = { | 265 | "smtp.immae.eu" = null; |
264 | "smtp.immae.eu" = null; | 266 | }; |
265 | }; | 267 | }; |
266 | }; | 268 | }; |
267 | } | 269 | } |