Knative function that receives CloudEvents, optionally filters them (typically via configuration injected by a Knative SinkBinding), renders Jinja2 templates (subject + plain/html), and sends an email notification.
- Accepts an incoming HTTP request carrying a CloudEvent (binary or structured).
- Loads configuration from environment variables (all
NA_*). - Applies attribute filters (e.g.
type,source,subject, extensions). - Selects templates based on CloudEvent
type. - Renders templates from either:
- inline templates provided via env vars (recommended for Knative manifest-based config), or
- template files on disk.
- Sends email using a pluggable client backend (default:
yagmail).
NA_LOG_LEVEL:DEBUG|INFO|WARNING|ERROR(default:INFO).- The service logs a startup line at process start:
na-emailer started (ready to receive events)
- For each request it logs: received event, filtered out / rendered / dry-run / send result.
NA_FILTERS_JSON: JSON object of required matches.- Example:
{"type":"com.acme.ready","source":"/sensor"} - Values can be scalars or arrays (array means “actual in expected”).
- Example:
NA_FILTER_MODE:all(default) orany.
NA_TEMPLATE_MAP_JSON: JSON object mapping CloudEvent type to template base name.- Example:
{"com.acme.job.done":"job_done"}
- Example:
NA_TEMPLATE_DEFAULT: fallback template base name (defaultdefault).NA_TEMPLATE_STRICT_UNDEFINED:true|false(defaultfalse).
The renderer chooses templates in this order:
- Inline templates from
NA_TEMPLATES_INLINE_JSON(if set and non-empty) - Filesystem templates from
NA_TEMPLATES_DIR
NA_TEMPLATES_INLINE_JSON: JSON object mapping template filenames to template content.
Example value:
{"default.subject.j2":"[{{ ce.type }}] Notification","default.txt.j2":"Hello {{ data.name }}"}
Notes:
- Keys must be the exact template filenames the renderer looks up, e.g.
default.subject.j2,default.txt.j2,default.html.j2. - When embedding JSON in YAML (Knative manifests), make sure to quote/escape properly (usually a YAML block scalar is easiest).
NA_TEMPLATES_DIR: templates folder.- Local default: the repo’s
./templatesdirectory (resolved automatically). - Container default:
/app/templates(the Dockerfile copies templates there).
- Local default: the repo’s
NA_EMAIL_CLIENT: email backend (defaultyagmail).NA_EMAIL_FROM: optional sender.NA_EMAIL_TO: comma-separated recipients.NA_EMAIL_CC,NA_EMAIL_BCC: optional.NA_EMAIL_SUBJECT_PREFIX: optional prefix.NA_DRY_RUN:true|false(if true, renders but doesn’t send).
Required when NA_EMAIL_CLIENT=yagmail and NA_DRY_RUN=false:
NA_YAGMAIL_USERNA_YAGMAIL_PASSWORD
Optional:
NA_YAGMAIL_HOST,NA_YAGMAIL_PORTNA_YAGMAIL_SMTP_STARTTLS,NA_YAGMAIL_SMTP_SSL
Templates are chosen by base name.
For base name default the renderer will look for:
default.subject.j2(required)default.txt.j2(optional)default.html.j2(optional)
The template context includes:
ce: CloudEvent attributes (plus extensions)data: the CloudEvent data
This prints an explicit “Waiting for CloudEvents...” line and defaults to dry-run.
python -m pip install -e '.[test]'
python start.pypython -m pip install -e '.[test]'
export NA_DRY_RUN=true
functions-framework --target handle --port 8080curl -i http://localhost:8080/ \
-H 'Content-Type: application/cloudevents+json' \
-d '{"specversion":"1.0","id":"1","source":"/local","type":"com.acme.test","datacontenttype":"application/json","data":{"hello":"world"}}'This repo is intentionally small and focused (core runtime + tests).
Add new email backends by implementing app.clients.base.EmailClient and wiring it in app.clients.factory.create_email_client.