forked from NixOS/nixpkgs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Patrick Hilhorst <[email protected]>
- Loading branch information
1 parent
61123a6
commit ecd88f9
Showing
7 changed files
with
319 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
{ config, lib, pkgs, ... }: | ||
|
||
with lib; | ||
|
||
let | ||
name = "maddy"; | ||
cfg = config.services.maddy; | ||
defaultConfig = '' | ||
tls off | ||
auth.pass_table local_authdb { | ||
table sql_table { | ||
driver sqlite3 | ||
dsn credentials.db | ||
table_name passwords | ||
} | ||
} | ||
storage.imapsql local_mailboxes { | ||
driver sqlite3 | ||
dsn imapsql.db | ||
} | ||
table.chain local_rewrites { | ||
optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3" | ||
optional_step static { | ||
entry postmaster postmaster@$(primary_domain) | ||
} | ||
optional_step file /etc/maddy/aliases | ||
} | ||
msgpipeline local_routing { | ||
destination postmaster $(local_domains) { | ||
modify { | ||
replace_rcpt &local_rewrites | ||
} | ||
deliver_to &local_mailboxes | ||
} | ||
default_destination { | ||
reject 550 5.1.1 "User doesn't exist" | ||
} | ||
} | ||
smtp tcp://0.0.0.0:25 { | ||
limits { | ||
all rate 20 1s | ||
all concurrency 10 | ||
} | ||
dmarc yes | ||
check { | ||
require_mx_record | ||
dkim | ||
spf | ||
} | ||
source $(local_domains) { | ||
reject 501 5.1.8 "Use Submission for outgoing SMTP" | ||
} | ||
default_source { | ||
destination postmaster $(local_domains) { | ||
deliver_to &local_routing | ||
} | ||
default_destination { | ||
reject 550 5.1.1 "User doesn't exist" | ||
} | ||
} | ||
} | ||
submission tcp://0.0.0.0:587 { | ||
limits { | ||
all rate 50 1s | ||
} | ||
auth &local_authdb | ||
source $(local_domains) { | ||
check { | ||
authorize_sender { | ||
prepare_email &local_rewrites | ||
user_to_email identity | ||
} | ||
} | ||
destination postmaster $(local_domains) { | ||
deliver_to &local_routing | ||
} | ||
default_destination { | ||
modify { | ||
dkim $(primary_domain) $(local_domains) default | ||
} | ||
deliver_to &remote_queue | ||
} | ||
} | ||
default_source { | ||
reject 501 5.1.8 "Non-local sender domain" | ||
} | ||
} | ||
target.remote outbound_delivery { | ||
limits { | ||
destination rate 20 1s | ||
destination concurrency 10 | ||
} | ||
mx_auth { | ||
dane | ||
mtasts { | ||
cache fs | ||
fs_dir mtasts_cache/ | ||
} | ||
local_policy { | ||
min_tls_level encrypted | ||
min_mx_level none | ||
} | ||
} | ||
} | ||
target.queue remote_queue { | ||
target &outbound_delivery | ||
autogenerated_msg_domain $(primary_domain) | ||
bounce { | ||
destination postmaster $(local_domains) { | ||
deliver_to &local_routing | ||
} | ||
default_destination { | ||
reject 550 5.0.0 "Refusing to send DSNs to non-local addresses" | ||
} | ||
} | ||
} | ||
imap tcp://0.0.0.0:143 { | ||
auth &local_authdb | ||
storage &local_mailboxes | ||
} | ||
''; | ||
|
||
in { | ||
options = { | ||
services.maddy = { | ||
enable = mkEnableOption "Maddy, a free an open source mail server"; | ||
|
||
user = mkOption { | ||
default = "maddy"; | ||
type = with types; uniq string; | ||
description = '' | ||
Name of the user under which maddy will run. If not specified, a | ||
default user will be created. | ||
''; | ||
}; | ||
group = mkOption { | ||
default = "maddy"; | ||
type = with types; uniq string; | ||
description = '' | ||
Name of the group under which maddy will run. If not specified, a | ||
default group will be created. | ||
''; | ||
}; | ||
|
||
hostname = mkOption { | ||
default = "localhost"; | ||
type = with types; uniq string; | ||
example = ''example.com''; | ||
description = '' | ||
Hostname to use. It should be FQDN. | ||
''; | ||
}; | ||
primaryDomain = mkOption { | ||
default = "localhost"; | ||
type = with types; uniq string; | ||
example = ''mail.example.com''; | ||
description = '' | ||
Primary MX domain to use. It should be FQDN. | ||
''; | ||
}; | ||
localDomains = mkOption { | ||
type = with types; listOf str; | ||
default = ["$(primary_domain)"]; | ||
example = [ | ||
"$(primary_domain)" | ||
"example.com" | ||
"other.example.com" | ||
]; | ||
description = '' | ||
Define list of allowed domains. | ||
''; | ||
}; | ||
config = mkOption { | ||
type = with types; nullOr lines; | ||
default = defaultConfig; | ||
description = '' | ||
Server configuration. | ||
''; | ||
}; | ||
|
||
openFirewall = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
Open the configured incoming and outgoing mail server ports. | ||
''; | ||
}; | ||
|
||
}; | ||
}; | ||
|
||
config = mkIf cfg.enable { | ||
|
||
systemd = { | ||
packages = [ pkgs.maddy ]; | ||
services.maddy = { | ||
serviceConfig = { | ||
User = "${cfg.user}"; | ||
Group = "${cfg.group}"; | ||
}; | ||
wantedBy = [ "multi-user.target" ]; | ||
}; | ||
}; | ||
|
||
environment.etc."maddy/maddy.conf" = { | ||
text = '' | ||
$(hostname) = ${cfg.hostname} | ||
$(primary_domain) = ${cfg.primaryDomain} | ||
$(local_domains) = ${toString cfg.localDomains} | ||
hostname ${cfg.hostname} | ||
${cfg.config} | ||
''; | ||
}; | ||
|
||
users.users = optionalAttrs (cfg.user == "maddy") { | ||
maddy = { | ||
description = "Maddy service user"; | ||
group = cfg.group; | ||
home = "/var/lib/maddy"; | ||
createHome = true; | ||
isSystemUser = true; | ||
}; | ||
}; | ||
|
||
users.groups = mkIf (cfg.group == "maddy") { | ||
maddy = pkgs.lib.mkForce { | ||
name = cfg.group; | ||
}; | ||
}; | ||
|
||
networking.firewall = mkIf cfg.openFirewall { | ||
allowedTCPPorts = [ 25 143 587 ]; | ||
}; | ||
|
||
environment.systemPackages = [ | ||
pkgs.maddy | ||
]; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import ./make-test-python.nix ({ pkgs, ... }: { | ||
name = "maddy"; | ||
meta = with pkgs.lib.maintainers; { maintainers = [ onny ]; }; | ||
|
||
nodes = { | ||
server = { ... }: { | ||
services.maddy = { | ||
enable = true; | ||
hostname = "server"; | ||
primaryDomain = "server"; | ||
openFirewall = true; | ||
}; | ||
}; | ||
|
||
client = { ... }: { | ||
environment.systemPackages = [ | ||
(pkgs.writers.writePython3Bin "send-testmail" { } '' | ||
import smtplib | ||
from email.mime.text import MIMEText | ||
msg = MIMEText("Hello World") | ||
msg['Subject'] = 'Test' | ||
msg['From'] = "postmaster@server" | ||
msg['To'] = "postmaster@server" | ||
with smtplib.SMTP('server', 587) as smtp: | ||
smtp.login('postmaster@server', 'test') | ||
smtp.sendmail('postmaster@server', 'postmaster@server', msg.as_string()) | ||
'') | ||
(pkgs.writers.writePython3Bin "test-imap" { } '' | ||
import imaplib | ||
with imaplib.IMAP4('server') as imap: | ||
imap.login('postmaster@server', 'test') | ||
imap.select() | ||
status, refs = imap.search(None, 'ALL') | ||
assert status == 'OK' | ||
assert len(refs) == 1 | ||
status, msg = imap.fetch(refs[0], 'BODY[TEXT]') | ||
assert status == 'OK' | ||
assert msg[0][1].strip() == b"Hello World" | ||
'') | ||
]; | ||
}; | ||
}; | ||
|
||
testScript = '' | ||
start_all() | ||
server.wait_for_unit("maddy.service") | ||
server.wait_for_open_port(143) | ||
server.wait_for_open_port(587) | ||
server.succeed("echo test | maddyctl creds create postmaster@server") | ||
server.succeed("maddyctl imap-acct create postmaster@server") | ||
client.succeed("send-testmail") | ||
client.succeed("test-imap") | ||
''; | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters