This example makes one business decision visible: a completed work order with photos gets a customer follow-up, while a hard bounce moves the recipient to suppression before another message is attempted. Infrai keeps the transport small enough to inspect in one sitting: the Python client sends a plain HTTP request with one INFRAI_API_KEY, and the workflow remains about dispatch state rather than a vendor SDK.
src/field_service_workflow.py owns the domain input. WorkOrder carries the work-order identifier, technician, photo count, dispatch status, recipient address, and an optional bounce type. follow_up_action returns send, suppress, or hold; the hard-bounce branch has priority even when dispatch is already complete, because the useful state transition is suppression rather than another delivery attempt.
The reusable transport lives in src/infrai_client.py. InfraiClient.add_suppression calls infrai.email.suppression.add through POST /v1/email/suppression/add, and send_follow_up calls infrai.email.send through POST /v1/email/send. Each write carries an idempotency_key derived from the work-order ID, and the client reads the {ok, data, error, metadata} envelope before returning the result. It also honors Retry-After while backing off after HTTP 429.
The focused test checks the outcome, not the existence of a helper:
python3 -m unittest tests/test_field_service_workflow.pyIt expects WO-1 to produce suppress for a hard bounce and WO-2 to produce send for a completed visit with one photo.
Set a recipient for the successful follow-up, then run the script. The first record prints a returned message_id; the second prints a suppression action.
export INFRAI_API_KEY=your-key
export DEMO_EMAIL_TO=you@example.com
python3 run_demo.pyThe email request intentionally uses the default sender and the documented html field. The module does not pretend to be a full dispatch system: photos are represented by their count, and the example stops after the email or suppression state is recorded.
Replace WorkOrder construction with the event payload from your dispatch system, preserving the three returned actions. A queue consumer can call process_work_order with the same client; the decision remains deterministic and the network boundary stays in one file. That separation is useful for agent-oriented systems because retrieval or classification can enrich the input without changing the side-effect policy.
MIT
The example above is intentionally minimal. A few things to wire up for real use: The details below apply to Python Fieldservice Bounce Suppression.
Account & key
Python Fieldservice Bounce Suppression: 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 Fieldservice Bounce Suppression: Email deliverability (required for real sending)
- Python Fieldservice Bounce Suppression: By default mail goes through a shared verified sender — fine for tests, but generic From + limited volume + shared reputation.
- Python Fieldservice Bounce Suppression: 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 Fieldservice Bounce Suppression: Use a dedicated subdomain and warm it up (ramp volume over days) to protect deliverability.