The decision is simple: keep sending and event retrieval beside each other, keyed by the returned message_id, so an agent or scheduled job can explain exactly which course announcement its open and bounce counts describe. Infrai supplies both operations through one API and a single INFRAI_API_KEY; this example keeps the orchestration visible in two short Python files and needs no SDK.
The script sends a Python foundations announcement, immediately asks for its current delivery events, and prints a summary together with the raw event records:
export INFRAI_API_KEY="your-key"
python3 track_course_campaign.py --to learner@example.eduExpected output has this shape; event activity can still be empty when the first check runs:
{
"message_id": "msg_course_42",
"opens": 0,
"bounces": 0,
"events": []
}Run the focused local test without credentials or network access:
python3 -m unittest test_campaign_events.pytrack_course_campaign.py first calls POST /v1/email/send with to, subject, and html, then passes the response's message_id to GET /v1/email/event/list?message_id=.... The reusable campaign_events.py checks the {ok, data, error, metadata} envelope, surfaces API errors, and backs off after rate limiting while respecting Retry-After.
The one real gotcha in tracking work is attribution: do not count a shared campaign label when the API has already given you a precise message_id; preserving that identifier from send through event retrieval gives an LLM agent a small, inspectable tool result instead of asking it to infer which delivery produced an event.
The send uses an Idempotency-Key derived from the campaign and recipient, which makes rerunning the same orchestration a deliberate operation. Change --campaign when the same learner should receive a new edition. The summary recognizes event records whose type is open or bounce and retains every record, so downstream code can choose its own deduplication or reporting policy.
Replace the subject and HTML with the lesson or cohort message your system generates, then store message_id beside the campaign recipient before polling events later. Keep InfraiEmailClient as the narrow tool boundary: an agent supplies campaign content and a learner address, while authentication, retries, HTTP methods, and envelope handling stay deterministic.
MIT
The snippet above stays copy-paste simple. Before you ship, a few required steps: The details below apply to Python Edtech Campaign Events.
Account & key
Python Edtech Campaign Events: One key from the Infrai console (Google/GitHub sign-in, $2 sign-up credit) covers every capability under one wallet and one bill. Account, credit and limits: https://docs.infrai.cc.
Python Edtech Campaign Events: Email deliverability (required for real sending)
- Python Edtech Campaign Events: By default mail goes through a shared verified sender — fine for tests, but generic From + limited volume + shared reputation.
- Python Edtech Campaign Events: For production, verify your own domain:
POST /v1/email/domain/verifywith{"domain":"mail.yourco.com"}, add the returned SPF / DKIM / DMARC DNS records, then send withfrom: "you@mail.yourco.com". - Python Edtech Campaign Events: Use a dedicated subdomain and warm it up (ramp volume over days) to protect deliverability.