Files
summercms/.planning/phases/04-cli-scaffolding-i18n-and-mail/04-03-SUMMARY.md
Jakub Zych 3b476cbf55 docs(04-03): complete postcard mail plan
Tasks completed: 3/3
- Render and send one registered template through memory
- Register plugin layouts and publish the mailer at Boot
- Add config-selected log and SMTP delivery

SUMMARY: .planning/phases/04-cli-scaffolding-i18n-and-mail/04-03-SUMMARY.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 14:03:11 +02:00

150 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 04-cli-scaffolding-i18n-and-mail
plan: 03
subsystem: mail
tags: [postcard, mail, goldmark, go-mail, smtp, wintercms]
requires:
- phase: 04-cli-scaffolding-i18n-and-mail
provides: pact.HasMailTemplates, party.Activate Register-then-Boot order
- phase: 01-framework-kernel-foundation
provides: backpack.Publish/Lookup, compass mail.* and SUMMER_MAIL__ layering
provides:
- postcard Mailer with Send(ctx, Message) through memory, log, and SMTP drivers
- Winter-shaped template and layout parser (INI, ==, Markdown body)
- Goldmark HTML with unsafe HTML disabled and header/address validation
- hello plugin mail templates, -en sibling, and hello layout
affects: [04-04-tests, plugin-porting, I18N-03]
tech-stack:
added: [github.com/yuin/goldmark@v1.8.6, github.com/wneessen/go-mail@v0.8.1]
patterns:
- html/template on Markdown then Goldmark HTML; substituted Markdown is the text part
- HasMailTemplates catalogs validate at Boot and publish Mailer before Boot
- mail.driver selects memory, log, or smtp with explicit TLS including opt-in NoTLS
key-files:
created:
- postcard/templates.go
- postcard/mailer.go
- postcard/drivers.go
- postcard/assets/default.htm
- postcard/mailer_test.go
- examples/hello/plugins/base/views/mail/hello.htm
- examples/hello/plugins/base/views/mail/hello-en.htm
- examples/hello/plugins/base/views/mail/layouts/hello.htm
- examples/hello/config/mail.yaml
modified:
- party/registry.go
- party/registry_test.go
- examples/hello/plugins/base/plugin.go
- examples/hello/hello_test.go
- go.mod
- go.sum
key-decisions:
- "Goldmark v1.8.6 is used without html.WithUnsafe; final HTML is rejected if script/iframe, event handlers, or javascript/vbscript/data schemes remain"
- "postcard.Mailer is published after Register and before Boot; each HasMailTemplates catalog is validated at that plugin's Boot transition"
- "mail.smtp.tls defaults to mandatory STARTTLS; none/notls is opt-in for Mailpit and is never inferred"
patterns-established:
- "Dotted names vendor.plugin::mail.name map to views/mail/<dot-path>.htm; short layout aliases resolve only within the owning plugin"
- "Send takes the full dotted name including any -en suffix and performs no locale lookup"
- "Driver errors return to Send with one postcard wrap and no retry; SMTP errors must not include credentials or bodies"
requirements-completed: [I18N-03]
duration: 6min
completed: 2026-09-18
---
# Phase 4 Plan 03: postcard mail Summary
**Winter-shaped mail templates and layouts render safe Markdown/HTML and send through memory, log, or go-mail SMTP selected by `mail.*`**
## Performance
- **Duration:** 6 min
- **Started:** 2026-09-18T11:56:07Z
- **Completed:** 2026-09-18T12:02:31Z
- **Tasks:** 3
- **Files modified:** 15
## Accomplishments
- `postcard` parses INI headers, `==` separators, and Markdown bodies; `html/template` substitutes vars, Goldmark renders HTML, and the substituted Markdown is the text part
- Plugins register dotted template names and short layout aliases; missing files and unknown layouts fail `party: boot <plugin ID>` with the full name
- `postcard.Mailer` is app-scoped; hello sends `golem15.hello::mail.hello` and `hello-en` through backpack, using the plugin `hello` layout
- `mail.driver` selects memory, log, or smtp (`SUMMER_MAIL__` overrides); SMTP uses explicit TLS, address/CRLF checks, and context-aware go-mail send without retries
## Task Commits
Each task was committed atomically:
1. **Task 1: Render and send one registered template through memory** - `b4fd833` (feat)
2. **Task 2: Register plugin layouts and publish the mailer at Boot** - `1e51597` (feat)
3. **Task 3: Add config-selected log and SMTP delivery** - `1b72456` (feat)
**Plan metadata:** (this commit)
## Files Created/Modified
- `postcard/templates.go` - Winter parser, catalog registration, Goldmark render, HTML safety
- `postcard/mailer.go` - Message/Mailer, Activate, BootPlugin, config-selected driver
- `postcard/drivers.go` - Driver interface plus memory, log, SMTP, and FailDriver
- `postcard/assets/default.htm` - Neutral framework layout
- `postcard/mailer_test.go` - render, layout, and driver smokes
- `party/registry.go` - Publish mailer before Boot; validate catalogs at Boot
- `examples/hello/plugins/base/plugin.go` - HasMailTemplates with hello and hello-en
- `examples/hello/plugins/base/views/mail/` - Distinct default-locale and -en templates plus hello layout
- `examples/hello/config/mail.yaml` - memory driver and documented smtp/NoTLS shape
- `go.mod` / `go.sum` - goldmark v1.8.6 and go-mail v0.8.1
## Decisions Made
- Goldmark stays on v1 (v2 is still a new line); unsafe HTML stays disabled and final HTML is re-checked
- Default layout is internal (`layout = default` or omitted); plugins cannot alias `default`
- TLS empty/mandatory maps to go-mail `TLSMandatory`; `none`/`notls` is explicit Mailpit opt-in; `starttls` is opportunistic only when named
- Mailpit real SMTP receipt stays Plan 04 (D-19); this plan uses an in-process FailDriver and a closed-port SMTP error
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 2 - Missing Critical] Three-section layout parser shipped with Task 1**
- **Found during:** Task 1 (embedded default layout)
- **Issue:** The neutral default layout is header + text wrapper + HTML wrapper, so memory-driver HTML/text wrapping could not wait for Task 2
- **Fix:** Parse two-`==` layouts in `templates.go` in Task 1; Task 2 still added plugin aliases, party Boot validation, and the hello layout
- **Files modified:** `postcard/templates.go`, `postcard/assets/default.htm`
- **Verification:** `TestMailRenderSmoke` asserts `content-body` from the default layout
- **Committed in:** `b4fd833` (Task 1 commit)
---
**Total deviations:** 1 auto-fixed (1 missing critical)
**Impact on plan:** No behavior divergence from D-06–D-09 or D-18–D-21. Layout parsing was required to honor the Task 1 default-layout artifact.
## Issues Encountered
None
## User Setup Required
None - no external service configuration required. Production SMTP credentials stay in `mail.*` / `SUMMER_MAIL__`; Mailpit is Plan 04.
## Next Phase Readiness
Ready for 04-04 (unit tests and Mailpit). Memory render, layout wrappers, named boot errors, log/SMTP driver contracts, and a failing-driver seam are in place. Do not treat `-short` as SMTP receipt.
## Verification
- `go test ./postcard -run 'TestMailRenderSmoke|TestMailLayoutSmoke|TestMailDriverSmoke' -short -count=1` — PASS
- `go -C examples/hello test ./...` — PASS
- `go vet ./... && go test ./...` — PASS
## Self-Check: PASSED
---
*Phase: 04-cli-scaffolding-i18n-and-mail*
*Completed: 2026-09-18*