1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2025-12-17 14:37:02 +00:00

test: Unify (most) SMTP client calls

To send mails, today some tests use msmtp and others our internal smtpc.py.

This works, but msmtp slows down the tests significantly, and smtpc.py
is also not particularly fast, and also has some limitations.

This patch introduces a new SMTP client tool written in Go, and makes
almost all the tests use it.

Some tests still remain on msmtp, mainly for client-check compatibility.
It's likely that this will be moved in later patches to a separate
special-purpose test.

With this patch, integration tests take ~20% less time than before.
This commit is contained in:
Alberto Bertogli
2024-03-09 19:10:08 +00:00
parent 7f44db008d
commit 5eded4edc3
54 changed files with 281 additions and 331 deletions

1
.gitignore vendored
View File

@@ -28,6 +28,7 @@ test/util/generate_cert/generate_cert
test/util/gocovcat/gocovcat
test/util/loadgen/loadgen
test/util/minidns/minidns
test/util/smtpc/smtpc
# Test binary, generated during coverage tests.
chasquid.test

View File

@@ -1,14 +0,0 @@
account default
host srv-chasquid
port 1587
tls on
tls_trust_file config/certs/srv-chasquid/fullchain.pem
from user@srv-chasquid
auth on
user user@srv-chasquid
password secretpassword

View File

@@ -10,9 +10,9 @@
# someone@srv-chasquid.
#
# Test:
# msmtp --> chasquid --> exim --> chasquid --> local delivery
# smtpc --> chasquid --> exim --> chasquid --> local delivery
#
# msmtp will auth as user@srv-chasquid to chasquid, and send an email with
# smtpc will auth as user@srv-chasquid to chasquid, and send an email with
# recipient someone@srv-exim.
#
# chasquid will deliver the mail to exim.
@@ -28,15 +28,15 @@ set -e
init
check_hostaliases
if ! .exim4/exim4 --version > /dev/null; then
skip "exim4 binary at .exim4/exim4 is not functional"
fi
# Create a temporary directory for exim4 to use, and generate the exim4
# config based on the template.
mkdir -p .exim4
EXIMDIR="$PWD/.exim4" envsubst < config/exim4.in > .exim4/config
if ! .exim4/exim4 -C "$PWD/.exim4/config" --version > /dev/null; then
skip "exim4 binary at .exim4/exim4 is not functional"
fi
# Build with the DNS override, so we can fake DNS records.
export GOTAGS="dnsoverride"
@@ -62,8 +62,8 @@ wait_until_ready 9053
.exim4/exim4 -bd -d -C "$PWD/.exim4/config" > .exim4/log 2>&1 &
wait_until_ready 2025
# msmtp will use chasquid to send an email to someone@srv-exim.
run_msmtp someone@srv-exim < content
# smtpc will use chasquid to send an email to someone@srv-exim.
smtpc someone@srv-exim < content
wait_for_file .mail/someone@srv-chasquid

View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert config/certs/srv-chasquid/fullchain.pem
user user@srv-chasquid
password secretpassword

View File

@@ -1,3 +1,4 @@
From: user@testserver
Subject: Prueba desde el test
Crece desde el test el futuro

View File

@@ -1,14 +0,0 @@
account default
host testserver
port 1587
tls on
tls_trust_file config/certs/testserver/fullchain.pem
from user@testserver
auth on
user user@testserver
password secretpassword

View File

@@ -14,7 +14,7 @@ chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config &
wait_until_ready 1025
function send_and_check() {
run_msmtp "$1@testserver" < content
smtpc "$1@testserver" < content
shift
for i in "$@"; do
wait_for_file ".mail/$i@testserver"
@@ -42,7 +42,7 @@ send_and_check añil+blah azul índigo
# Test the pipe alias separately.
rm -f .data/pipe_alias_worked
run_msmtp tubo@testserver < content
smtpc tubo@testserver < content
wait_for_file .data/pipe_alias_worked
mail_diff content .data/pipe_alias_worked
@@ -58,17 +58,17 @@ send_and_check vic.uña+abc uña
# Test the pipe alias separately.
rm -f .data/pipe_alias_worked
run_msmtp ñandú@testserver < content
smtpc ñandú@testserver < content
wait_for_file .data/pipe_alias_worked
mail_diff content .data/pipe_alias_worked
# Test when alias-resolve exits with an error
if run_msmtp roto@testserver < content 2> .logs/msmtp.out; then
if smtpc roto@testserver < content 2> .logs/smtpc.out; then
fail "expected delivery to roto@ to fail, but succeeded"
fi
# Test a non-existent alias.
if run_msmtp nono@testserver < content 2> .logs/msmtp.out; then
if smtpc nono@testserver < content 2> .logs/smtpc.out; then
fail "expected delivery to nono@ to fail, but succeeded"
fi

View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert config/certs/testserver/fullchain.pem
user user@testserver
password secretpassword

View File

@@ -54,7 +54,6 @@ Received: from localhost
tls *
(over *
; *
Date: *
From: Mailer daemon <somewhere@báratro>
Subject: I've come to haunt you
Message-Id: <booooo>

View File

@@ -1,13 +0,0 @@
account default
host testserver
port 1587
tls on
tls_trust_file config/certs/testserver/fullchain.pem
from user@testserver
auth on
user user@testserver
password secretpassword

View File

@@ -22,7 +22,7 @@ rm -f .mail/user@testserver
# Test that we get mail back for a failed delivery
run_msmtp fail@testserver < content
smtpc fail@testserver < content
wait_for_file .mail/user@testserver
mail_diff expected_dsr .mail/user@testserver

View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert config/certs/testserver/fullchain.pem
user user@testserver
password secretpassword

View File

@@ -1,5 +1,6 @@
smtp_address: ":1025"
submission_address: ":1587"
submission_over_tls_address: ":1465"
monitoring_address: ":1099"
mail_delivery_agent_bin: "test-mda"

View File

@@ -1,5 +1,6 @@
smtp_address: ":2025"
submission_address: ":2587"
submission_over_tls_address: ":2465"
monitoring_address: ":2099"
mail_delivery_agent_bin: "test-mda"

View File

@@ -8,8 +8,6 @@ check_hostaliases
rm -rf .data-A .data-B .mail
skip_if_python_is_too_old
# Build with the DNS override, so we can fake DNS records.
export GOTAGS="dnsoverride"
@@ -37,20 +35,22 @@ chasquid -v=2 --logfile=.logs-B/chasquid.log --config_dir=B \
--testing__dns_addr=127.0.0.1:9053 \
--testing__outgoing_smtp_port=1025 &
wait_until_ready 1025
wait_until_ready 2025
wait_until_ready 1465
wait_until_ready 2465
wait_until_ready 9053
# Send from A to B.
smtpc.py --server=localhost:1025 --user=nadaA@nadaA --password=nadaA \
< from_A_to_B
smtpc --addr=localhost:1465 --user=nadaA@nadaA --password=nadaA \
--server_cert=A/certs/srv-ñ/fullchain.pem \
pingüino@srv-ü < from_A_to_B
wait_for_file .mail/pingüino@srv-ü
mail_diff from_A_to_B .mail/pingüino@srv-ü
# Send from B to A.
smtpc.py --server=localhost:2025 --user=nadaB@nadaB --password=nadaB \
< from_B_to_A
smtpc --addr=localhost:2465 --user=nadaB@nadaB --password=nadaB \
--server_cert=B/certs/srv-ü/fullchain.pem \
ñangapirí@srv-ñ < from_B_to_A
wait_for_file .mail/ñangapirí@srv-ñ
mail_diff from_B_to_A .mail/ñangapirí@srv-ñ

View File

@@ -1,5 +1,6 @@
smtp_address: ":1025"
submission_address: ":1587"
submission_over_tls_address: ":1465"
monitoring_address: ":1099"
mail_delivery_agent_bin: "test-mda"

View File

@@ -9,25 +9,23 @@ set -e
init
skip_if_python_is_too_old
generate_certs_for ñoños
# Intentionally have a config directory for upper case; this should be
# normalized to lowercase internally (and match the cert accordingly).
add_user ñandú@ñoñOS araño
add_user ñangapirí@ñoñOS antaño
# Python doesn't support UTF8 for auth, use an ascii user and domain.
add_user nada@nada nada
mkdir -p .logs
chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config &
wait_until_ready 1025
wait_until_ready 1465
# The envelope from and to are taken from the content, and use a mix of upper
# and lower case.
smtpc.py --server=localhost:1025 --user=nada@nada --password=nada \
< content
# Use a mix of upper and lower case in the from, to, and username, to check
# normalization is well handled end-to-end.
smtpc --addr=localhost:1465 \
--server_cert=config/certs/ñoños/fullchain.pem \
--user=ñanDÚ@ñoños --password=araño \
Ñangapirí@Ñoños < content
# The MDA should see the normalized users and domains, in lower case.
wait_for_file .mail/ñangapirí@ñoños

View File

@@ -1,14 +0,0 @@
account default
host srv-A
port 1587
tls on
tls_trust_file A/certs/srv-A/fullchain.pem
from userA@srv-A
auth on
user userA@srv-A
password userA

View File

@@ -40,7 +40,7 @@ wait_until_ready 1025
wait_until_ready 2025
wait_until_ready 9053
run_msmtp aliasB@srv-B < content
smtpc aliasB@srv-B < content
# Get some of the debugging pages, for troubleshooting, and to make sure they
# work reasonably well.

View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert A/certs/srv-A/fullchain.pem
user userA@srv-A
password userA

View File

@@ -1,5 +1,6 @@
smtp_address: ":1025"
submission_address: ":1587"
submission_over_tls_address: ":1465"
monitoring_address: ":1099"
mail_delivery_agent_bin: "test-mda"

View File

@@ -1,15 +0,0 @@
account default
host testserver
port 1587
tls on
tls_trust_file config/certs/testserver/fullchain.pem
from user@testserver
auth on
user user@testserver
password secretpassword
logfile .logs/msmtp

View File

@@ -18,7 +18,7 @@ wait_until_ready 1025
cp config/hooks/post-data.good config/hooks/post-data
run_msmtp someone@testserver < content
smtpc someone@testserver < content
wait_for_file .mail/someone@testserver
@@ -51,20 +51,20 @@ check "SPF_PASS=0"
# Check that failures in the script result in failing delivery.
# Transient failure.
if run_msmtp blockme@testserver < content 2>/dev/null; then
if smtpc blockme@testserver < content >.logs/smtpc.log 2>&1; then
fail "ERROR: hook did not block email as expected"
fi
if ! tail -n 1 .logs/msmtp | grep -q "smtpstatus=451"; then
tail -n 1 .logs/msmtp
if ! grep -q "451 ¡No pasarán!" .logs/smtpc.log; then
cat .logs/smtpc.log
fail "ERROR: transient hook error not returned correctly"
fi
# Permanent failure.
if run_msmtp permanent@testserver < content 2>/dev/null; then
if smtpc permanent@testserver < content >.logs/smtpc.log 2>&1; then
fail "ERROR: hook did not block email as expected"
fi
if ! tail -n 1 .logs/msmtp | grep -q "smtpstatus=554"; then
tail -n 1 .logs/msmtp
if ! grep -q "554 Nos hacemos la permanente" .logs/smtpc.log; then
cat .logs/smtpc.log
fail "ERROR: permanent hook error not returned correctly"
fi
@@ -72,7 +72,7 @@ fi
for i in config/hooks/post-data.bad*; do
cp "$i" config/hooks/post-data
run_msmtp someone@testserver < content
smtpc someone@testserver < content
wait_for_file .mail/someone@testserver
mail_diff content .mail/someone@testserver
done

View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert config/certs/testserver/fullchain.pem
user user@testserver
password secretpassword

View File

@@ -1,3 +1,4 @@
From: user@srv
Subject: Prueba desde el test
Crece desde el test el futuro

View File

@@ -1,33 +0,0 @@
account default
host srv
port 1587
tls on
tls_trust_file config/certs/srv/fullchain.pem
from user@srv
auth on
user user@srv
password password
account smtpport : default
port 1025
account subm_tls : default
port 1465
tls_starttls off
account baduser : default
user unknownuser@srv
password secretpassword
account badpasswd : default
user user@srv
password badsecretpassword
account naked : default
from naked@srv
user naked
password gun

View File

@@ -52,33 +52,33 @@ chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config &
wait_until_ready 1025
# Send an email as "user@srv" successfully.
run_msmtp user@srv < content
smtpc user@srv < content
wait_for_file .mail/user@srv
mail_diff content .mail/user@srv
# Send an email as "naked" successfully.
rm .mail/user@srv
run_msmtp -a naked user@srv < content
smtpc --user=naked --password=gun --from=naked@srv user@srv < content
wait_for_file .mail/user@srv
mail_diff content .mail/user@srv
# Send an email to the "naked" user successfully.
run_msmtp naked@srv < content
smtpc naked@srv < content
wait_for_file .mail/naked@srv
mail_diff content .mail/naked@srv
# Fail to send to nobody@srv (user does not exist).
if run_msmtp nobody@srv < content 2> /dev/null; then
if smtpc nobody@srv < content 2> /dev/null; then
fail "successfully sent an email to a non-existent user"
fi
# Fail to send from baduser@srv (user does not exist).
if run_msmtp -a baduser user@srv < content 2> /dev/null; then
# Fail to send from unknownuser@srv (user does not exist).
if smtpc --user=unknownuser@srv user@srv < content 2> /dev/null; then
fail "successfully sent an email with a bad user"
fi
# Fail to send with an incorrect password.
if run_msmtp -a badpasswd user@srv < content 2> /dev/null; then
if smtpc --password=badpasswd user@srv < content 2> /dev/null; then
fail "successfully sent an email with a bad password"
fi

View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert config/certs/srv/fullchain.pem
user user@srv
password password

View File

@@ -1,5 +1,6 @@
smtp_address: ":1025"
submission_address: ":1587"
submission_over_tls_address: ":1465"
monitoring_address: ":1099"
mail_delivery_agent_bin: "test-mda"

View File

@@ -1,14 +0,0 @@
account default
host testserver
port 1587
tls on
tls_trust_file config/certs/testserver/fullchain.pem
from someone@testserver
auth on
user someone@testserver
password password222

View File

@@ -22,7 +22,7 @@ chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config \
wait_until_ready 1025
# First, check that delivery fails with the "wrong" password.
if run_msmtp someone@testserver < content 2>/dev/null; then
if smtpc someone@testserver < content 2>/dev/null; then
fail "success using the wrong password"
fi
@@ -32,7 +32,7 @@ chasquid-util-user-add someone@testserver password222
echo "analias: someone" > config/domains/testserver/aliases
sleep 0.2
run_msmtp analias@testserver < content
smtpc analias@testserver < content
wait_for_file .mail/someone@testserver
@@ -50,7 +50,7 @@ sleep 0.2
# Send another mail.
rm .mail/someone@testserver
run_msmtp analias@testserver < content
smtpc analias@testserver < content
wait_for_file .mail/someone@testserver
# Check there are new entries.

View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert config/certs/testserver/fullchain.pem
user someone@testserver
password password222

View File

@@ -1,14 +0,0 @@
account default
host srv-A
port 1587
tls on
tls_trust_file A/certs/srv-A/fullchain.pem
from userA@srv-A
auth on
user userA@srv-A
password userA

View File

@@ -45,7 +45,7 @@ wait_until_ready 1025
wait_until_ready 2025
wait_until_ready 9053
run_msmtp userB@srv-B < content
smtpc userB@srv-B < content
wait_for_file .mail/userb@srv-b
mail_diff content .mail/userb@srv-b

View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert A/certs/srv-A/fullchain.pem
user userA@srv-A
password userA

View File

@@ -1,5 +1,6 @@
smtp_address: ":1025"
submission_address: ":1587"
submission_over_tls_address: ":1465"
monitoring_address: ":1099"
mail_delivery_agent_bin: "test-mda"

View File

@@ -1,14 +0,0 @@
account default
host testserver
port 1587
tls on
tls_trust_file config/certs/testserver/fullchain.pem
from user@testserver
auth on
user user@testserver
password secretpassword

View File

@@ -23,11 +23,14 @@ add_user someone@testserver secretpassword
mkdir -p .logs
chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config &
wait_until_ready 1025
wait_until_ready 1465
# Authenticated: user@testserver -> someone@testserver
# Should be signed.
run_msmtp someone@testserver < content
smtpc --addr=localhost:1465 \
--server_cert=config/certs/testserver/fullchain.pem \
--user=user@testserver --password=secretpassword \
someone@testserver < content
wait_for_file .mail/someone@testserver
mail_diff content .mail/someone@testserver
grep -q "DKIM-Signature:" .mail/someone@testserver
@@ -40,11 +43,14 @@ dkimverify -txt .dkimcerts/dns.txt < .mail/someone@testserver
tail -n +2 .mail/someone@testserver > .signed_content
# Not authenticated: someone@testserver -> someone@testserver
smtpc.py --server=localhost:1025 < .signed_content
smtpc --addr=localhost:1025 \
--from=someone@testserver someone@testserver < .signed_content
# Check that the signature fails on modified content.
echo "Added content, invalid and not signed" >> .signed_content
if smtpc.py --server=localhost:1025 < .signed_content 2> /dev/null; then
if smtpc --addr=localhost:1025 \
--from=someone@testserver someone@testserver < .signed_content \
> /dev/null 2>&1 ; then
fail "DKIM verification succeeded on modified content"
fi

View File

@@ -54,8 +54,6 @@ Received: from localhost
tls *
(over *
; *
From: userA@srv-A
Date: *
Subject: Prueba desde el test
Crece desde el test el futuro

View File

@@ -1,14 +0,0 @@
account default
host srv-A
port 1587
tls on
tls_trust_file A/certs/srv-A/fullchain.pem
from userA@srv-A
auth on
user userA@srv-A
password userA

View File

@@ -54,7 +54,7 @@ function launch_minidns() {
# T0: Successful.
launch_minidns zones.t0
run_msmtp userB@srv-B < content
smtpc userB@srv-B < content
wait_for_file .mail/userb@srv-b
mail_diff content .mail/userb@srv-b
@@ -62,7 +62,7 @@ mail_diff content .mail/userb@srv-b
# Check that userA got a DSN about it.
rm .mail/*
launch_minidns zones.t1
run_msmtp userB@srv-B < content
smtpc userB@srv-B < content
wait_for_file .mail/usera@srv-a
mail_diff expected_dsn .mail/usera@srv-a

4
test/t-16-spf/smtpc.conf Normal file
View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert A/certs/srv-A/fullchain.pem
user userA@srv-A
password userA

View File

@@ -1,28 +0,0 @@
account default
host testserver
port 1587
tls on
tls_trust_file config/certs/testserver/fullchain.pem
from user@testserver
auth on
user user@testserver
password secretpassword
account smtpport : default
port 1025
account subm_tls : default
port 1465
tls_starttls off
account baduser : default
user unknownuser@testserver
password secretpassword
account badpasswd : default
user user@testserver
password badsecretpassword

View File

@@ -20,7 +20,7 @@ function send_one() {
> .logs/stdout 2> .logs/stderr &
wait_until_ready 1025
run_msmtp someone@testserver < content
smtpc someone@testserver < content
wait_for_file .mail/someone@testserver
mail_diff content .mail/someone@testserver

View File

@@ -0,0 +1,4 @@
addr localhost:1465
server_cert config/certs/testserver/fullchain.pem
user user@testserver
password secretpassword

View File

@@ -1,5 +1,6 @@
smtp_address: ":1025"
submission_address: ":1587"
submission_over_tls_address: ":1465"
monitoring_address: ":1099"
mail_delivery_agent_bin: "test-mda"

View File

@@ -1,14 +0,0 @@
account default
host testserver
port 1587
tls on
tls_trust_file config/certs/testserver/fullchain.pem
from user@testserver
auth on
user user@testserver
password secretpassword

View File

@@ -47,7 +47,10 @@ wait_until_ready 1025
# Authenticated: user@testserver -> someone@testserver
# Should be signed.
run_msmtp someone@testserver < content
smtpc --addr=localhost:1465 \
--server_cert=config/certs/testserver/fullchain.pem \
--user=user@testserver --password=secretpassword \
someone@testserver < content
wait_for_file .mail/someone@testserver
mail_diff content .mail/someone@testserver
if ! grep -q "DKIM-Signature:" .mail/someone@testserver; then
@@ -65,11 +68,14 @@ dkimverify -txt .dkimcerts/private.dns < .mail/someone@testserver
tail -n +2 .mail/someone@testserver > .signed_content
# Not authenticated: someone@testserver -> someone@testserver
smtpc.py --server=localhost:1025 < .signed_content
smtpc --addr=localhost:1025 \
--from=someone@testserver someone@testserver < .signed_content
# Check that the signature fails on modified content.
echo "Added content, invalid and not signed" >> .signed_content
if smtpc.py --server=localhost:1025 < .signed_content 2> /dev/null; then
if smtpc --addr=localhost:1025 \
--from=someone@testserver someone@testserver < .signed_content \
> /dev/null 2>&1 ; then
fail "DKIM verification succeeded on modified content"
fi

View File

@@ -1,5 +1,6 @@
smtp_address: ":1025"
submission_address: ":1587"
submission_over_tls_address: ":1465"
monitoring_address: ":1099"
mail_delivery_agent_bin: "test-mda"

View File

@@ -1,5 +1,6 @@
smtp_address: ":2025"
submission_address: ":2587"
submission_over_tls_address: ":2465"
monitoring_address: ":2099"
mail_delivery_agent_bin: "test-mda"

View File

@@ -8,8 +8,6 @@ check_hostaliases
rm -rf .data-A .data-B .mail
skip_if_python_is_too_old
# Build with the DNS override, so we can fake DNS records.
export GOTAGS="dnsoverride"
@@ -45,20 +43,24 @@ chasquid -v=2 --logfile=.logs-B/chasquid.log --config_dir=B \
--testing__dns_addr=127.0.0.1:9053 \
--testing__outgoing_smtp_port=1025 &
wait_until_ready 1025
wait_until_ready 2025
wait_until_ready 1465
wait_until_ready 2465
wait_until_ready 9053
# Send from A to B.
smtpc.py --server=localhost:1025 --user=user-a@srv-a --password=nadaA \
< from_A_to_B
smtpc --addr=localhost:1465 \
--server_cert=A/certs/srv-A/fullchain.pem \
--user=user-a@srv-a --password=nadaA \
user-b@srv-b < from_A_to_B
wait_for_file .mail/user-b@srv-b
mail_diff from_A_to_B.expected .mail/user-b@srv-b
# Send from B to A.
smtpc.py --server=localhost:2025 --user=user-b@srv-b --password=nadaB \
< from_B_to_A
smtpc --addr=localhost:2465 \
--server_cert=B/certs/srv-B/fullchain.pem \
--user=user-b@srv-b --password=nadaB \
user-a@srv-a < from_B_to_A
wait_for_file .mail/user-a@srv-a
mail_diff from_B_to_A.expected .mail/user-a@srv-a

View File

@@ -120,10 +120,6 @@ function run_msmtp() {
"${UTILDIR}/.msmtp-bin" -C msmtprc "$@"
}
function smtpc.py() {
"${UTILDIR}/smtpc.py" "$@"
}
function mail_diff() {
"${UTILDIR}/mail_diff" "$@"
}
@@ -158,6 +154,11 @@ function fexp() {
"${UTILDIR}/fexp/fexp" "$@"
}
function smtpc() {
go-build-cached "${UTILDIR}/smtpc/"
"${UTILDIR}/smtpc/smtpc" "$@"
}
function timeout() {
MYPID=$$
(
@@ -232,16 +233,6 @@ function generate_certs_for() {
cp -p "${CACHEDIR}/$1"/* "${CONFDIR}/certs/$1/"
}
# Check the Python version, and skip if it's too old.
# This will check against the version required for smtpc.py.
function skip_if_python_is_too_old() {
# We need Python >= 3.5 to be able to use SMTPUTF8.
check='import sys; sys.exit(0 if sys.version_info >= (3, 5) else 1)'
if ! python3 -c "${check}" > /dev/null 2>&1; then
skip "python3 >= 3.5 not available"
fi
}
function chasquid_ram_peak() {
# Find the pid of the daemon, which we expect is running on the
# background somewhere within our current session.

View File

@@ -1,43 +0,0 @@
#!/usr/bin/env python3
#
# Simple SMTP client for testing purposes.
import argparse
import email.parser
import email.policy
import re
import smtplib
import sys
ap = argparse.ArgumentParser()
ap.add_argument("--server", help="SMTP server to connect to")
ap.add_argument("--user", help="Username to use in SMTP AUTH")
ap.add_argument("--password", help="Password to use in SMTP AUTH")
args = ap.parse_args()
# Parse the email using the "default" policy, which is not really the default.
# If unspecified, compat32 is used, which does not support UTF8.
rawmsg = sys.stdin.buffer.read()
msg = email.parser.Parser(policy=email.policy.default).parsestr(
rawmsg.decode('utf8'))
s = smtplib.SMTP(args.server)
s.starttls()
if args.user:
s.login(args.user, args.password)
# Send the raw message, not parsed, because the parser does not handle some
# corner cases that well (for example, DKIM-Signature headers get mime-encoded
# incorrectly).
# Replace \n with \r\n, which is normally done by the library, but will not do
# it in this case because we are giving it bytes and not a string (which we
# cannot do because it tries to incorrectly escape the headers).
crlfmsg = re.sub(br'(?:\r\n|\n|\r(?!\n))', b"\r\n", rawmsg)
s.sendmail(
from_addr=msg['from'], to_addrs=msg.get_all('to'),
msg=crlfmsg,
mail_options=['SMTPUTF8'])
s.quit()

142
test/util/smtpc/smtpc.go Normal file
View File

@@ -0,0 +1,142 @@
package main
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"flag"
"io"
"net"
"net/smtp"
"os"
"strings"
)
var (
addr = flag.String("addr", "", "Address of the SMTP server")
user = flag.String("user", "", "Username to use in SMTP AUTH")
password = flag.String("password", "", "Password to use in SMTP AUTH")
from = flag.String("from", "", "From address to use in the message")
serverCert = flag.String("server_cert", "",
"Path to the server certificate to expect")
confPath = flag.String("c", "smtpc.conf",
"Path to the configuration file")
)
func main() {
flag.Parse()
loadConfig()
// Read message from stdin.
rawMsg, err := io.ReadAll(os.Stdin)
notnil(err)
// RCPT TO from the command line.
tos := make([]string, len(flag.Args()))
for i, to := range flag.Args() {
tos[i] = to
}
// Connect to the server.
var conn net.Conn
if *serverCert != "" {
cert := loadCert(*serverCert)
rootCAs := x509.NewCertPool()
rootCAs.AddCert(cert)
tlsConfig := &tls.Config{
ServerName: cert.DNSNames[0],
RootCAs: rootCAs,
}
conn, err = tls.Dial("tcp", *addr, tlsConfig)
defer conn.Close()
} else {
conn, err = net.Dial("tcp", *addr)
}
notnil(err)
// Send the message.
client, err := smtp.NewClient(conn, *addr)
notnil(err)
if *user != "" {
auth := smtp.PlainAuth("", *user, *password, *addr)
err = client.Auth(auth)
notnil(err)
}
if *from == "" {
*from = *user
}
err = client.Mail(*from)
notnil(err)
for _, to := range tos {
err = client.Rcpt(to)
notnil(err)
}
w, err := client.Data()
notnil(err)
_, err = io.Copy(w, bytes.NewReader(rawMsg))
notnil(err)
err = w.Close()
notnil(err)
err = client.Quit()
notnil(err)
}
func loadConfig() {
data, err := os.ReadFile(*confPath)
if errors.Is(err, os.ErrNotExist) {
return
}
notnil(err)
for _, line := range strings.Split(string(data), "\n") {
k, v, ok := strings.Cut(line, " ")
if !ok {
continue
}
k = strings.TrimSpace(k)
// Set the flag but only if it wasn't already set.
// Command-line flags take precedence.
isSet := false
flag.Visit(func(f *flag.Flag) {
if f.Name == k {
isSet = true
}
})
if !isSet {
flag.Lookup(k).Value.Set(strings.TrimSpace(v))
}
}
}
func loadCert(path string) *x509.Certificate {
data, err := os.ReadFile(path)
notnil(err)
block, _ := pem.Decode(data)
cert, err := x509.ParseCertificate(block.Bytes)
notnil(err)
return cert
}
func notnil(err error) {
if err != nil {
panic(err)
}
}