An exclusion list is an input to a decision. If the list cannot be read reliably, returning an empty list changes the decision: a recipient who should have been excluded may appear eligible.
Here is a small reproducible check of that boundary in my open-source UniSender Campaign Kit. The program prepares an offline plan; it does not send email. I ran the two cases below on version 0.1.0. Every address and permission identifier is synthetic.
Two contacts and one exclusion
Download and extract the existing 0.1.0 release. It needs Python 3.9+ and uses the standard library. Keep the supplied examples/campaign.example.json unchanged. That file is an example draft, not a provider configuration.
Inside the extracted directory, create a fixture directory with three files.
fixture/contacts.csv:
email,consent,consent_at,consent_evidence,unsubscribed
ok@people.example.invalid,true,2026-10-01T12:00:00Z,synthetic-permission-a,false
excluded@people.example.invalid,true,2026-10-01T12:00:00Z,synthetic-permission-b,false
fixture/suppression-valid.csv:
email,reason
excluded@people.example.invalid,synthetic-opt-out
fixture/suppression-invalid.csv:
email,reason
not-an-address,synthetic-invalid-row
Both contact rows declare consent=true. The second address is also in the valid exclusion list. That exclusion must remain effective.
Establish the positive case
The following command uses a POSIX shell. The explicit time makes the result repeatable.
python3 -B lookatshow_mail_plan.py plan \
--campaign examples/campaign.example.json \
--contacts fixture/contacts.csv \
--suppression fixture/suppression-valid.csv \
--at 2026-10-25T12:00:00Z
The process exited with code 0. The relevant result fields were:
{
"counts": {
"contact_rows": 2,
"eligible_under_supplied_rules": 1,
"excluded_rows": 1
},
"reason_counts": {"suppressed": 1},
"rows": [
{"ordinal": 1, "reasons": [], "status": "eligible_under_supplied_rules"},
{"ordinal": 2, "reasons": ["suppressed"], "status": "excluded"}
],
"sending_performed": false
}
This is an excerpt, not the complete response envelope. The output identifies source row numbers without echoing the addresses or permission evidence.
Change only the suppression input
Run the same command with --suppression fixture/suppression-invalid.csv. Leave the campaign, contacts and evaluation time unchanged.
The process exited with code 2. Its response had ok=false and this error:
{
"code": "SUPPRESSION_INVALID",
"input": "suppression",
"message": "Invalid suppression row makes exclusions uncertain.",
"ordinal": 1
}
There was no result object and no eligibility count. The malformed row did not become a harmless warning followed by a plan.
Give the wrapper the same stopping rule
An AI agent wrapping this CLI should inspect the process status and response envelope before explaining the plan. For this input, the next action is to report the suppression-file error and request a corrected source file.
Silently discarding the invalid row, replacing the file with an empty one, or continuing from a previous successful plan would defeat the check. Keep the failing input and its outcome together so another person can reproduce the stop.
The successful case also has a boundary: eligible_under_supplied_rules means the supplied fields passed local rules. The tool does not verify that the permission evidence is genuine, establish legal permission, contact UniSender, or prove delivery. Those checks remain separate; the two true fields in this fixture are deliberately invented claims.
For my Russian-language notes on checking AI-assisted marketing workflows, see my Telegram channel.
Prepared with an AI agent. The fixture, exit codes and output excerpts above were executed and checked; this is a synthetic exercise, not a customer campaign.
Top comments (0)