An SMTP client and server library for Zig implementing RFC 5321.
0

Configure Feed

Select the types of activity you want to include in your feed.

zig-smtp / nix / interop-test.nix
4.7 kB 142 lines
1# SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us> 2# SPDX-License-Identifier: MIT 3 4# NixOS VM test exercising zsmtp against third-party implementations: 5# - zsmtp client -> Postfix: plaintext, STARTTLS (port 25), implicit TLS 6# (port 465), verified by checking local delivery to alice's spool 7# - swaks -> zsmtp server: plaintext and STARTTLS, verified by checking 8# the received message in the server's journal 9 10{ 11 testers, 12 callPackage, 13 runCommand, 14 openssl, 15}: 16let 17 zsmtp = callPackage ./package.nix { }; 18 19 snakeoil = 20 runCommand "zsmtp-test-cert" 21 { 22 nativeBuildInputs = [ openssl ]; 23 } 24 '' 25 mkdir -p $out 26 openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \ 27 -keyout $out/key.pem -out $out/cert.pem -days 36500 -nodes \ 28 -subj "/CN=localhost" \ 29 -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" 30 ''; 31in 32testers.runNixOSTest { 33 name = "zsmtp-interop"; 34 35 nodes.machine = 36 { pkgs, ... }: 37 { 38 environment.systemPackages = [ 39 zsmtp 40 pkgs.swaks 41 ]; 42 43 users.users.alice.isNormalUser = true; 44 45 services.postfix = { 46 enable = true; 47 # Implicit-TLS smtpd on port 465; allow loopback without SASL. 48 enableSubmissions = true; 49 submissionsOptions = { 50 smtpd_client_restrictions = "permit_mynetworks,reject"; 51 }; 52 settings.main = { 53 mydestination = [ 54 "localhost" 55 "$myhostname" 56 ]; 57 smtpd_tls_security_level = "may"; 58 smtpd_tls_chain_files = [ 59 "${snakeoil}/key.pem" 60 "${snakeoil}/cert.pem" 61 ]; 62 }; 63 }; 64 65 systemd.services.zsmtp-server = { 66 description = "zsmtp debug server (plaintext)"; 67 wantedBy = [ "multi-user.target" ]; 68 serviceConfig = { 69 ExecStart = "${zsmtp}/bin/zsmtp serve 2525"; 70 DynamicUser = true; 71 }; 72 }; 73 74 systemd.services.zsmtp-server-tls = { 75 description = "zsmtp debug server (STARTTLS)"; 76 wantedBy = [ "multi-user.target" ]; 77 serviceConfig = { 78 ExecStart = "${zsmtp}/bin/zsmtp serve --tls-cert ${snakeoil}/cert.pem --tls-key ${snakeoil}/key.pem 2526"; 79 DynamicUser = true; 80 }; 81 }; 82 }; 83 84 testScript = '' 85 machine.wait_for_unit("postfix.service") 86 machine.wait_for_open_port(25) 87 machine.wait_for_open_port(465) 88 machine.wait_for_unit("zsmtp-server.service") 89 machine.wait_for_unit("zsmtp-server-tls.service") 90 machine.wait_for_open_port(2525) 91 machine.wait_for_open_port(2526) 92 93 with subtest("zsmtp client to postfix, plaintext"): 94 machine.succeed( 95 "printf 'Subject: interop\\r\\n\\r\\nzsmtp to postfix plain\\r\\n'" 96 " | zsmtp send 127.0.0.1 25 bob@example.com alice@localhost" 97 ) 98 machine.wait_until_succeeds( 99 "grep -r 'zsmtp to postfix plain' /var/spool/mail/alice/", timeout=60 100 ) 101 102 with subtest("zsmtp client to postfix, STARTTLS"): 103 machine.succeed( 104 "printf 'Subject: interop\\r\\n\\r\\nzsmtp to postfix starttls\\r\\n'" 105 " | zsmtp send --starttls --insecure 127.0.0.1 25" 106 " bob@example.com alice@localhost" 107 ) 108 machine.wait_until_succeeds( 109 "grep -r 'zsmtp to postfix starttls' /var/spool/mail/alice/", timeout=60 110 ) 111 112 with subtest("zsmtp client to postfix, implicit TLS"): 113 machine.succeed( 114 "printf 'Subject: interop\\r\\n\\r\\nzsmtp to postfix smtps\\r\\n'" 115 " | zsmtp send --tls --insecure 127.0.0.1 465" 116 " bob@example.com alice@localhost" 117 ) 118 machine.wait_until_succeeds( 119 "grep -r 'zsmtp to postfix smtps' /var/spool/mail/alice/", timeout=60 120 ) 121 122 with subtest("swaks to zsmtp server, plaintext"): 123 machine.succeed( 124 "swaks --server 127.0.0.1:2525 --from bob@example.com" 125 " --to alice@example.net --header 'Subject: swaks plain'" 126 " --body 'swaks to zsmtp plain'" 127 ) 128 machine.wait_until_succeeds( 129 "journalctl -u zsmtp-server | grep 'swaks to zsmtp plain'", timeout=60 130 ) 131 132 with subtest("swaks to zsmtp server, STARTTLS"): 133 machine.succeed( 134 "swaks --tls --server 127.0.0.1:2526 --from bob@example.com" 135 " --to alice@example.net --header 'Subject: swaks starttls'" 136 " --body 'swaks to zsmtp starttls'" 137 ) 138 machine.wait_until_succeeds( 139 "journalctl -u zsmtp-server-tls | grep 'swaks to zsmtp starttls'", timeout=60 140 ) 141 ''; 142}