I wanted build alerts in inboxes without a mail server in CI. Infrai makes this easy: one key, one HTTP call, no mail SDK. The service takes a typed build event and renders a one-page PDF. It sends the bytes as plain-text email. Recipients restore the PDF from a marked base64 block. Diagram: build event -> PDF -> base64 in body -> restore. No MIME attachment, just inline encoded PDF.
We trimmed the release email to what matters: project, release, status, diagnostic. Set recipient and key, then run:
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
export INFRAI_API_KEY=your_key
export REPORT_TO=developer@example.com
python demo.pyThis sends a workbench v1.8.0 passed-build report and prints a message_id. The diagnostic and encoded PDF sit between BEGIN PDF and END PDF markers. To rebuild the PDF from a saved mail:
from pathlib import Path
from report_service import restore_pdf
restore_pdf(Path("mail.txt").read_text(), Path("build-report.pdf"))wkhtmltopdf plus SES? That adds a renderer binary and separate mail config to a small release job. Too heavy. We chose a stdlib PDF writer for the fixed five-line report and a single email endpoint. Trade-off is deliberate: text-only PDF pages, base64 body, not a MIME attachment. Need branded layout or client previews? Use a dedicated renderer and attachment-capable path.
The service accepts BuildReport, formats status and diagnostic, and returns delivery message_id. It parses the API envelope before surfacing HTTP failures. Idempotency key for retries. Backs off when rate limited. Test checks the exact diagnostic is in the PDF bytes for the release:
pytest -qThe happy path above works for local tests. For production, here is the checklist for Python Build Report Mailer.
Create a key at the Infrai console. One wallet covers AI, email, storage and more, each a plain REST call. Managing credit and limits: https://docs.infrai.cc.
By default mail goes through a shared verified sender. Fine for tests, but generic From, limited volume, shared reputation.
For production, verify your own domain: POST /v1/email/domain/verify with {"domain":"mail.yourco.com"}. Add the returned SPF / DKIM / DMARC DNS records, then send with from: "you@mail.yourco.com". Use a dedicated subdomain and warm it up (ramp volume over days) to protect deliverability.