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>
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
---
|
||||
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*
|
||||
Reference in New Issue
Block a user