1# Rudimentary test checking that the Stalwart email server can:
2# - receive some message through SMTP submission, then
3# - serve this message through IMAP.
4
5let
6 certs = import ./common/acme/server/snakeoil-certs.nix;
7 domain = certs.domain;
8
9in import ./make-test-python.nix ({ lib, ... }: {
10 name = "stalwart-mail";
11
12 nodes.main = { pkgs, ... }: {
13 security.pki.certificateFiles = [ certs.ca.cert ];
14
15 services.stalwart-mail = {
16 enable = true;
17 settings = {
18 server.hostname = domain;
19
20 certificate."snakeoil" = {
21 cert = "file://${certs.${domain}.cert}";
22 private-key = "file://${certs.${domain}.key}";
23 };
24
25 server.tls = {
26 certificate = "snakeoil";
27 enable = true;
28 implicit = false;
29 };
30
31 server.listener = {
32 "smtp-submission" = {
33 bind = [ "[::]:587" ];
34 protocol = "smtp";
35 };
36
37 "imap" = {
38 bind = [ "[::]:143" ];
39 protocol = "imap";
40 };
41 };
42
43 resolver.public-suffix = [ ]; # do not fetch from web in sandbox
44
45 session.auth.mechanisms = "[plain]";
46 session.auth.directory = "'in-memory'";
47 storage.directory = "in-memory";
48
49 session.rcpt.directory = "'in-memory'";
50 queue.outbound.next-hop = "'local'";
51
52 directory."in-memory" = {
53 type = "memory";
54 principals = [
55 {
56 type = "individual";
57 name = "alice";
58 secret = "foobar";
59 email = [ "alice@${domain}" ];
60 }
61 {
62 type = "individual";
63 name = "bob";
64 secret = "foobar";
65 email = [ "bob@${domain}" ];
66 }
67 ];
68 };
69 };
70 };
71
72 environment.systemPackages = [
73 (pkgs.writers.writePython3Bin "test-smtp-submission" { } ''
74 from smtplib import SMTP
75
76 with SMTP('localhost', 587) as smtp:
77 smtp.starttls()
78 smtp.login('alice', 'foobar')
79 smtp.sendmail(
80 'alice@${domain}',
81 'bob@${domain}',
82 """
83 From: alice@${domain}
84 To: bob@${domain}
85 Subject: Some test message
86
87 This is a test message.
88 """.strip()
89 )
90 '')
91
92 (pkgs.writers.writePython3Bin "test-imap-read" { } ''
93 from imaplib import IMAP4
94
95 with IMAP4('localhost') as imap:
96 imap.starttls()
97 status, [caps] = imap.login('bob', 'foobar')
98 assert status == 'OK'
99 imap.select()
100 status, [ref] = imap.search(None, 'ALL')
101 assert status == 'OK'
102 [msgId] = ref.split()
103 status, msg = imap.fetch(msgId, 'BODY[TEXT]')
104 assert status == 'OK'
105 assert msg[0][1].strip() == b'This is a test message.'
106 '')
107 ];
108 };
109
110 testScript = /* python */ ''
111 main.wait_for_unit("stalwart-mail.service")
112 main.wait_for_open_port(587)
113 main.wait_for_open_port(143)
114
115 main.succeed("test-smtp-submission")
116 main.succeed("test-imap-read")
117 '';
118
119 meta = {
120 maintainers = with lib.maintainers; [ happysalada pacien ];
121 };
122})