Ten runnable, numbered examples showing how to use the Inky
email framework from Python, via the inky binding at
inky/bindings/python — from the smallest possible transform up to a
transactional-email capstone and a Jinja2/Total-CMS-style integration.
This is a Stage C port of the flagship PHP example suite:
the same ten examples, against the same required output markers, defined
language-neutrally in that repo's SUITE.md.
Requires Inky v2. See the main inky repo.
- Python >= 3.9
- A Rust toolchain, to build the
libinkyshared library:(this repo must be checked out as a sibling ofcd ../inky && cargo build -p inky-ffi --release
inky/—bootstrap.py'ssys.pathinsertion and the binding's own dylib lookup both assume that layout) Jinja2(installed viarequirements.txt) — used only by example 10
This suite does not pip-install the inky package itself. Every
example's run.py adds inky/bindings/python/src to sys.path directly
— mirroring how inky/bindings/python/test.py loads it in development —
so there's no local package-manager path dependency (pip install -e,
etc.) in the loop at all. See bootstrap.py's docstring for the full
runtime note.
cd ../inky && cargo build -p inky-ffi --release # build libinky once
cd ../inky-example-python
python3 -m venv .venv # avoids PEP 668 "externally managed environment" on Homebrew Python
.venv/bin/pip install -r requirements.txt # installs Jinja2 (example 10 only)
.venv/bin/python3 run_all.py # runs every examples/*/run.py, writes dist/
.venv/bin/python3 run_all.py --verify # same, plus checks every output for its required markers(A Makefile is also provided: make examples / make verify do the
same two commands.)
.venv/bin/python3 run_all.py --verify prints ok for all ten examples.
Output lands in dist/NN-name/ (gitignored).
| # | Name | Teaches |
|---|---|---|
| 01-quickstart | quickstart | The smallest possible thing Inky does: transform turns a <button> into table markup, no layout or data involved. |
| 02-build-pipeline | build-pipeline | The full build pipeline in one call: shared layout + includes + a linked SCSS theme, all resolved and inlined. |
| 03-data-merge | data-merge | Merging JSON data into a template: variables, a conditional, and a loop rendered as real <tr> rows. |
| 04-theming | theming | Building the identical template twice with a different linked SCSS theme each time. |
| 05-plain-text | plain-text | Deriving a plain-text alternative alongside the HTML for multipart transactional email. |
| 06-validate-gate | validate-gate | Using validate as a pre-send CI gate: block on errors, let warnings through. |
| 07-migrate | migrate | Upgrading a v1 Inky template to v2 syntax programmatically, with a reviewable change report. |
| 08-outlook-hybrid | outlook-hybrid | Building for Outlook desktop: hybrid column layout, bulletproof VML buttons, <outlook>/<not-outlook> branching. |
| 09-transactional | transactional (capstone) | A real three-email transactional set (welcome, receipt, password reset) built through EmailRenderer, a small production-shaped service class. |
| 10-twig-cms | twig-cms | Integrating Inky into a Jinja2-based CMS (mirroring a Twig-based CMS like Total CMS): both valid processing orders, timed, plus the one <raw> rule that makes the fast path safe. |
Run any single example directly, e.g. python3 examples/03-data-merge/run.py —
every run.py is a self-contained, top-to-bottom tutorial with comments at
each decision point.
If you're wiring Inky into a Jinja2- or Twig-based CMS (Total CMS or
similar), start at 09-transactional to see
the production-shaped EmailRenderer wrapper (src/email_renderer.py),
then read 10-twig-cms for the CMS-specific
question: should the template engine or Inky run first? Both orders are
implemented, timed, and proven to agree — see that example's run.py and
newsletter.inky.jinja2's header comment for the full trade-off,
including the one <raw>-plus-inline_css=False rule that makes the
faster, build-once-per-template order safe.
requirements.txt Jinja2 (example 10 only)
bootstrap.py sys.path setup + inky_example() dist-dir helper, shared by every run.py
src/email_renderer.py small production-shaped render/theme/cache wrapper (example 09; the pattern example 10 adapts for a Jinja2 CMS)
shared/ brand layout, includes, SCSS themes used by examples 01-08
examples/NN-name/ one directory per example: run.py (tutorial) + verify.py (smoke test)
dist/ build output (generated, gitignored)
run_all.py runs every example (python3 run_all.py [--verify])
Makefile make examples / make verify
send.py multipart send demo reading example 05's output
tests/ plain-Python smoke test for src/email_renderer.py
python3 tests/email_renderer_test.py