Files
govoplan-campaign/dev/mail-testbed/README.md

121 lines
4.8 KiB
Markdown

# Campaign SMTP/IMAP Test Bed
This test bed provides dedicated non-production SMTP/IMAP infrastructure for
campaign delivery checks. It uses GreenMail and must never be configured with
production recipients or credentials.
## Start
```bash
cd /mnt/DATA/git/govoplan-campaign/dev/mail-testbed
cp .env.example .env
docker compose --env-file .env up -d
```
Default endpoints:
- SMTP: `127.0.0.1:3025`, plain transport
- IMAP: `127.0.0.1:3143`, plain transport
- GreenMail API/UI endpoint: `127.0.0.1:38080`
## Smoke Test
Run the transport smoke from the core virtual environment after installing the
campaign and mail modules:
```bash
cd /mnt/DATA/git/govoplan-campaign/dev/mail-testbed
set -a
. ./.env
set +a
/mnt/DATA/git/govoplan-core/.venv/bin/python run_transport_smoke.py
```
The smoke sends and appends three messages:
- no attachment
- one normal attachment
- one password-protected AES ZIP attachment
It verifies SMTP authentication, IMAP authentication, folder listing, delivery
to `INBOX`, and append-to-Sent behavior.
If the smoke is started immediately after `docker compose up -d`, GreenMail may
bind the SMTP/IMAP ports before the services are fully ready. The smoke retries
login and folder setup for `GOVOPLAN_MAIL_TEST_READY_TIMEOUT_SECONDS`.
## Campaign Acceptance
The transport smoke proves the Mail adapters. The Campaign acceptance runner
proves the public composition: it creates an isolated temporary Core database,
creates a Mail-owned encrypted profile through the API, materializes the
credential-free [`greenmail-delivery`](../../examples/greenmail-delivery/campaign.json)
fixture with only that profile reference, validates/builds it, sends the exact
generated EML through Campaign once, appends it once, and cross-checks Campaign
report/audit state with one unique-subject message in the GreenMail INBOX and
Sent folders. Provider mailbox verification is not a byte-for-byte comparison
after provider-side header or storage transformations.
```bash
cd /mnt/DATA/git/govoplan-campaign/dev/mail-testbed
set -a
. ./.env
set +a
/mnt/DATA/git/govoplan/.venv/bin/python run_campaign_acceptance.py \
--evidence /tmp/govoplan-campaign-greenmail-evidence.json
```
The default run also uses controlled loopback protocol endpoints to prove that
an SMTP connection loss before transmission is temporary, an explicit SMTP
authentication rejection is permanent, and an IMAP authentication rejection
after SMTP acceptance leaves the send accepted while the append fails. A
second ordinary send must be rejected before another provider effect.
The bounded JSON contains no endpoint, account, address, credential, profile,
campaign, version, or job identifiers. It records module versions, the fixture
hash, normalized classifications/counts, the Mail-profile boundary, required
audit actions, provider mailbox increments, and coverage flags. Runtime version
declarations identify the exercised composition; they do not claim that the
sources are clean, tagged, signed, or release-provenanced. The evidence names
them `declared_module_versions` and keeps `source_artifact_provenance` false;
exact commit/artifact provenance belongs to the package and release gate.
This runner is restricted to literal loopback IP addresses and the synchronous
Campaign delivery mode. Hostnames such as `localhost` and every non-loopback
address fail before profile creation, avoiding a DNS change between validation
and connection. It is local target-like evidence, not approval of an
institution's SMTP/IMAP service. A post-DATA connection loss
with ambiguous SMTP outcome, an explicit temporary SMTP response, partial
recipient refusal, and a real worker restart remain separate drills and are
explicitly `false` in the coverage projection. Use `--success-only` only when
testing the success journey without the local failure endpoints.
Starting the maintained test bed requires a working Docker CLI, Compose plugin,
daemon/socket access, and permission to pull `greenmail/standalone:2.1.9`. The
Campaign runner needs only the already-running loopback endpoints; it neither
starts Docker nor claims that it did.
## Use With A Campaign
Use the same settings in a campaign mail profile:
- SMTP host `127.0.0.1`, port `3025`, security `plain`
- IMAP host `127.0.0.1`, port `3143`, security `plain`
- username and password from `.env`
- append folder from `GOVOPLAN_MAIL_TEST_SENT_FOLDER`
When changing the mailbox, keep `GOVOPLAN_MAIL_TEST_USER` equal to
`${GOVOPLAN_MAIL_TEST_LOCAL_PART}@${GOVOPLAN_MAIL_TEST_DOMAIN}` because the
compose file creates the GreenMail account from local part, password, and
domain while login uses the full email address.
Then run the controlled sending checklist from
`docs/CAMPAIGN_DELIVERY_RUNBOOK.md` for no attachment, one attachment, and
password-protected ZIP campaign variants.
## Stop
```bash
docker compose --env-file .env down -v
```