summary refs log tree commit diff
path: root/nixos/tests/opensmtpd.nix
blob: 4d3479168f70067719445b982827db9996875eae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import ./make-test.nix {
  name = "opensmtpd";

  nodes = {
    smtp1 = { pkgs, ... }: {
      imports = [ common/user-account.nix ];
      networking = {
        firewall.allowedTCPPorts = [ 25 ];
        useDHCP = false;
        interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
          { address = "192.168.1.1"; prefixLength = 24; }
        ];
      };
      environment.systemPackages = [ pkgs.opensmtpd ];
      services.opensmtpd = {
        enable = true;
        extraServerArgs = [ "-v" ];
        serverConfiguration = ''
          listen on 0.0.0.0
          action do_relay relay
          # DO NOT DO THIS IN PRODUCTION!
          # Setting up authentication requires a certificate which is painful in
          # a test environment, but THIS WOULD BE DANGEROUS OUTSIDE OF A
          # WELL-CONTROLLED ENVIRONMENT!
          match from any for any action do_relay
        '';
      };
    };

    smtp2 = { pkgs, ... }: {
      imports = [ common/user-account.nix ];
      networking = {
        firewall.allowedTCPPorts = [ 25 143 ];
        useDHCP = false;
        interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
          { address = "192.168.1.2"; prefixLength = 24; }
        ];
      };
      environment.systemPackages = [ pkgs.opensmtpd ];
      services.opensmtpd = {
        enable = true;
        extraServerArgs = [ "-v" ];
        serverConfiguration = ''
          listen on 0.0.0.0
          action dovecot_deliver mda \
            "${pkgs.dovecot}/libexec/dovecot/deliver -d %{user.username}"
          match from any for local action dovecot_deliver
        '';
      };
      services.dovecot2 = {
        enable = true;
        enableImap = true;
        mailLocation = "maildir:~/mail";
        protocols = [ "imap" ];
      };
    };

    client = { pkgs, ... }: {
      networking = {
        useDHCP = false;
        interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
          { address = "192.168.1.3"; prefixLength = 24; }
        ];
      };
      environment.systemPackages = let
        sendTestMail = pkgs.writeScriptBin "send-a-test-mail" ''
          #!${pkgs.python3.interpreter}
          import smtplib, sys

          with smtplib.SMTP('192.168.1.1') as smtp:
            smtp.sendmail('alice@[192.168.1.1]', 'bob@[192.168.1.2]', """
              From: alice@smtp1
              To: bob@smtp2
              Subject: Test

              Hello World
            """)
        '';

        checkMailLanded = pkgs.writeScriptBin "check-mail-landed" ''
          #!${pkgs.python3.interpreter}
          import imaplib

          with imaplib.IMAP4('192.168.1.2', 143) as imap:
            imap.login('bob', 'foobar')
            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'
            content = msg[0][1]
            print("===> content:", content)
            split = content.split(b'\r\n')
            print("===> split:", split)
            lastline = split[-3]
            print("===> lastline:", lastline)
            assert lastline.strip() == b'Hello World'
        '';
      in [ sendTestMail checkMailLanded ];
    };
  };

  testScript = ''
    startAll;

    $client->waitForUnit("network-online.target");
    $smtp1->waitForUnit('opensmtpd');
    $smtp2->waitForUnit('opensmtpd');
    $smtp2->waitForUnit('dovecot2');

    # To prevent sporadic failures during daemon startup, make sure
    # services are listening on their ports before sending requests
    $smtp1->waitForOpenPort(25);
    $smtp2->waitForOpenPort(25);
    $smtp2->waitForOpenPort(143);

    $client->succeed('send-a-test-mail');
    $smtp1->waitUntilFails('smtpctl show queue | egrep .');
    $smtp2->waitUntilFails('smtpctl show queue | egrep .');
    $client->succeed('check-mail-landed >&2');
  '';
}