NOTICE: All information contained herein is, and remains
the property of TechnoCore.
The intellectual and technical concepts contained
herein are proprietary to TechnoCore and dissemination of this information or reproduction of this material
is strictly forbidden unless prior written permission is obtained
from TechnoCore.
FastAPI routes for email-related web endpoints: banner image serving and open tracking pixels.
GET /email/{channel}/{source_code}/{tracking_guid}GET /email/{channel}/{source_code}GET /email/{channel}/Serves email banner images (header/footer) for a given channel. Reads the banner file from resource.images/package.{package}/ via ObjChannel.get_email_banner().
GET /email/pixel/{guid} (do_tracking_pixel_GET)Tracking pixel endpoint. Returns a 1x1 transparent GIF and records the email open event by calling ObjChannelmail.ChannelMail.mark_open(guid, client_ip, user_agent).
guid is the per-send UUID carried by the pixel that ObjChannel.render_email injects into the footer of each outgoing email (<img src=".../email/pixel/{guid}">).CF-Connecting-IP header support for Cloudflare)Cache-Control: no-store, no-cache, must-revalidate, max-age=0, Pragma: no-cache, Expires: 0) to prevent email client cachingRoute ordering (important): this pixel route MUST be registered before the generic /email/{channel}/{source_code} banner route (do_mailerimg_GET) in this file. FastAPI/Starlette matches routes by registration order, so if the generic route comes first it captures /email/pixel/<guid> (as channel="pixel") and returns HTTP 400. The pixel route is defined first to prevent this.
Deployment: the public pixel URL only works if the reverse proxy (Caddy) forwards /email/* to the Axion service, e.g. handle /email/* { reverse_proxy localhost:9400 }.
GET /email/unsubscribe/{guid} · POST /email/unsubscribe/{guid}Email unsubscribe. Calls ObjChannelmail.ChannelMail.unsubscribe(guid), which sets the recipient's def_ChannelMail row Active='N' (Status='UNSUBSCRIBED') so select_mailset_emails drops them from the active list.
.../email/unsubscribe/{guid}) returns a branded confirmation page (_unsubscribe_page).List-Unsubscribe-Post header that ObjWebMail.send_report adds (List-Unsubscribe: <https://{dns}/email/unsubscribe/{guid}>). Returns 200./email/{channel}/{source_code} banner route (same ordering rule as the pixel).GET /email/click/{guid} (do_click_GET)Email click tracking. Query param url carries the intended destination. Records the click by calling ObjChannelmail.ChannelMail.mark_click(guid, client_ip), then issues a 302 redirect to url.
http:///https:// targets are honoured; anything else falls back to https://wynbergrotary.co.za.ObjChannel.render_email rewrites body links to point at this route (.../email/click/{guid}?url=<target>&sig=<hmac>).config email.link_secret is set, the route honours only HMAC-signed targets (ObjChannel.verify_click_sig); unsigned/tampered/invalid → redirect to the site root. With no secret it degrades to a scheme-only check./email/{channel}/{source_code} banner route (same ordering rule as the pixel/unsubscribe routes).GET /email/confirm/{guid} (do_confirm_GET)Double opt-in confirmation. Calls ObjChannelmail.ChannelMail.confirm(guid), which flips the PENDING def_ChannelMail row to Active='Y', Status='SUBSCRIBED'. Returns a branded confirmation page (_confirm_page).
POST /email/subscribePublic subscribe. Body {channel, email, firstname?, surname?}. Calls ObjChannelmail.ChannelMail.subscribe(), which is now double opt-in: it creates a PENDING row (Active='N', Status='PENDING') and emails a confirmation link. Returns {status:"pending", message:"check your email to confirm…"} (or 400/500). The address only joins the active list once the recipient clicks the confirm link (/email/confirm/{guid}).
Rate-limited (_subscribe_rate_ok): each subscribe sends a confirmation email, so the endpoint caps email.subscribe_ip_max (default 5) per IP per email.subscribe_ip_window (600s) and enforces a per-email cooldown email.subscribe_email_cooldown (300s). Over the limit → HTTP 429. State is an in-memory sliding window (single-process daemon).
Pre-validated (_deliverable): the address is checked via
ObjServiceZeroBounce.validate_email (cached in data_zerobounce) before a
PENDING row is created. Clearly-bad statuses (invalid / do_not_mail /
spamtrap / abuse) → HTTP 400; fail-open if ZeroBounce is
unconfigured or errors.
POST /email/webhook/brevo (do_brevo_webhook_POST)ESP (Brevo) event webhook → suppression. Authenticated by a shared
?token= matching config email.webhook_token; fail-closed (403)
when no token is configured, so it can never be an open "suppress
arbitrary address" endpoint. Maps events: hard_bounce/blocked/
invalid_email → record_bounce (suppress); soft_bounce/deferred →
logged; spam → record_complaint; unsubscribed → suppress.
Delivery/open/click are ignored (covered by the pixel + click tracker).
Registered before the generic banner route.
GET /email/subscribe (do_subscribe_GET)Public opt-in landing form — the target of the "Subscribe a friend" link in email footers (?channel=<channel>). Renders _subscribe_page(channel): a branded page with an email field that POSTs JSON to POST /email/subscribe (the double opt-in above) via fetch, then shows the "check your email" message. Must be registered before the generic /email/{channel}/{source_code} banner route (same ordering rule as the other /email/* routes).
_brand_context, _status_page, _subscribe_page)The unsubscribe/confirm/subscribe pages share _brand_context(), which sources brand colours from the package palette (def_colour_palette) and the logo from config site.logo — nothing brand-specific is hardcoded (mirrors the email templates). Falls back to the rotary defaults if lookup fails.
XSS hardening: _subscribe_page whitelists the ?channel= query value to identifier chars ([A-Za-z0-9_.-]) before reflecting it into the page <script>, so a </script>… payload can't break out. _unsubscribe_page/_confirm_page html.escape() the DB-sourced channel name as defense-in-depth.
resource.test/pytests/factory.pages/test_WebPageMail.py (10 unit tests,
dependencies mocked, _brand_context monkeypatched — no DB):
_subscribe_rate_ok): allows up to the per-IP cap then_subscribe_page): parametrized hostile ?channel=</script>…, "><svg>, quote-breakout) all reduce to_unsubscribe_page / _confirm_pagepytest resource.test/pytests/factory.pages/test_WebPageMail.py -v
ObjChannel — banner image resolution, body-link rewriting (render_email)ObjChannelmail — open/click tracking, subscribe/confirm/unsubscribeWebServer — FastAPI app and get_client_ip() helpercythonize -3 -a -i WebPageMail.py
Updated : 2026-05-05