1{
2 name = "dovecot";
3
4 nodes.machine =
5 { pkgs, ... }:
6 {
7 imports = [ common/user-account.nix ];
8 services.postfix.enable = true;
9 services.dovecot2 = {
10 enable = true;
11 protocols = [
12 "imap"
13 "pop3"
14 ];
15 mailUser = "vmail";
16 mailGroup = "vmail";
17 };
18 environment.systemPackages =
19 let
20 sendTestMail = pkgs.writeScriptBin "send-testmail" ''
21 #!${pkgs.runtimeShell}
22 exec sendmail -vt <<MAIL
23 From: root@localhost
24 To: alice@localhost
25 Subject: Very important!
26
27 Hello world!
28 MAIL
29 '';
30
31 sendTestMailViaDeliveryAgent = pkgs.writeScriptBin "send-lda" ''
32 #!${pkgs.runtimeShell}
33
34 exec ${pkgs.dovecot}/libexec/dovecot/deliver -d bob <<MAIL
35 From: root@localhost
36 To: bob@localhost
37 Subject: Something else...
38
39 I'm running short of ideas!
40 MAIL
41 '';
42
43 testImap = pkgs.writeScriptBin "test-imap" ''
44 #!${pkgs.python3.interpreter}
45 import imaplib
46
47 with imaplib.IMAP4('localhost') as imap:
48 imap.login('alice', 'foobar')
49 imap.select()
50 status, refs = imap.search(None, 'ALL')
51 assert status == 'OK'
52 assert len(refs) == 1
53 status, msg = imap.fetch(refs[0], 'BODY[TEXT]')
54 assert status == 'OK'
55 assert msg[0][1].strip() == b'Hello world!'
56 '';
57
58 testPop = pkgs.writeScriptBin "test-pop" ''
59 #!${pkgs.python3.interpreter}
60 import poplib
61
62 pop = poplib.POP3('localhost')
63 try:
64 pop.user('bob')
65 pop.pass_('foobar')
66 assert len(pop.list()[1]) == 1
67 status, fullmail, size = pop.retr(1)
68 assert status.startswith(b'+OK ')
69 body = b"".join(fullmail[fullmail.index(b""):]).strip()
70 assert body == b"I'm running short of ideas!"
71 finally:
72 pop.quit()
73 '';
74
75 in
76 [
77 pkgs.dovecot_pigeonhole
78 sendTestMail
79 sendTestMailViaDeliveryAgent
80 testImap
81 testPop
82 ];
83 };
84
85 testScript = ''
86 machine.wait_for_unit("postfix.service")
87 machine.wait_for_unit("dovecot.service")
88 machine.succeed("send-testmail")
89 machine.succeed("send-lda")
90 machine.wait_until_fails('[ "$(postqueue -p)" != "Mail queue is empty" ]')
91 machine.succeed("test-imap")
92 machine.succeed("test-pop")
93
94 machine.log(machine.succeed("systemd-analyze security dovecot.service | grep -v ✓"))
95 '';
96}