home / projects / cms-email-sync
Case 03 / 06 · X-Pipeline: content → inbox
Edit in the CMS. Render in the inbox. Touch nothing in between.
Web content and email content usually live double lives — the same announcement written twice, drifting apart by the second edit. This pipeline makes the CMS the single source of truth and treats email HTML as a compile target.
- Project
- Independent build
- Role
- Full-stack developer
- Timeline
- 2023 — 2024
- Stack
- Python · CMS · Templating · HTML email
The brief
Every content update was being produced twice: once as a web page in the CMS, once as an email hand-assembled from that page. Twice the work, and worse — two versions that disagreed within a week. The brief: let editors write once in the CMS and have correct, email-safe HTML fall out automatically.
The constraints
- Web HTML is not email HTML. The CMS's rendered output — divs, flexbox, external CSS, modern tags — is precisely what email clients mangle. The pipeline can't reuse web markup; it has to re-express content.
- Editors are not email developers. Whatever they can type into the CMS must produce something valid. There is no "please don't use that block" in a real workflow.
- Images and links need translation: absolute URLs, dimensions on every image, tracking-parameter injection — none of which editors should think about.
- The output has to survive the usual suspects: Outlook's Word engine, Gmail clipping, images-off rendering.
The build
The core decision: map structured content, don't transform markup. The pipeline reads the CMS's content model — headings, rich text, images, buttons, lists — as data, then renders each block type through a Python templating layer into table-based, fully-inlined email components. A heading block becomes an email heading component; a button block becomes a bulletproof link. Web markup never crosses the boundary.
- Block-type allowlist: content types without an email mapping fall back to a safe text rendering rather than leaking unsupported HTML into a send.
- Sanitisation pass: whatever rich-text quirks editors paste in (Word artifacts included) are normalised before templating.
- Asset handling: images get absolute HTTPS URLs and explicit width/height so layouts hold even before images load.
- Preview before send: the compiled email renders side-by-side with the web version, so editors verify the pair as one piece of content.
The outcome
One edit, two channels, zero drift. Non-technical editors ship email updates without ever seeing a table tag, and the email that goes out is built from components that have already survived client testing.