The package-doc examples showed a fictional launcher.Register / health.Register
API (and launcher.Append as a package func). Corrected to the real wiring:
lc.Append + web/health.NewHandler(...).ServeHTTP.
Documentation-only. No code, API, or dependency changes; version stays v1.1.0
(the v1.1.0 tag is moved to include this fix). Verified by compiling the
corrected pattern against the real API.
Patch of the coordinated framework release: einherjar modules move to v1.1.0
in lockstep, so smtp is bumped alongside the rest.
- go.mod: contracts, core -> v1.1.0 (via go get + go mod tidy)
No code or API changes. ModuleVersion() reports v1.1.0 automatically from
build info once tagged. Badge bumped to v1.1.0.
Reviewed-on: #1
Co-authored-by: Rene Nochebuena Guerrero <rene@nochebuena.dev>
Co-committed-by: Rene Nochebuena Guerrero <rene@nochebuena.dev>
Introduces code.nochebuena.dev/einherjar/smtp — the email delivery starter for the
Einherjar framework. New module with no micro-lib counterpart. Pure stdlib — no
external dependencies beyond contracts and core.
Interfaces (CT-6: one TypeSpec per file):
- Sender — Send(ctx context.Context, msg Message) error
- Component — lifecycle.Component + observability.Checkable + Sender
- Message — To, CC, BCC, ReplyTo, Subject, Body, ContentType, Attachments
- Attachment — Name, ContentType string; Data io.Reader (consumed once on Send)
- Template — wraps html/template for email rendering
Implementation:
- New(logger, cfg) Component — returns noopClient when cfg.Host is empty;
SMTP absence must never block a transaction (e.g. account creation)
- noopClient: all lifecycle and Send methods return nil; Send logs Warn;
Priority LevelDegraded; Name "smtp"
- smtpClient: OnInit/OnStart/OnStop are no-ops (stateless stdlib client);
HealthCheck: TCP dial to Host:Port; Priority LevelDegraded
- Send: buildRawMessage → netsmtp.SendMail; BCC passed in SMTP envelope
(RCPT TO) but never written to message headers (RFC 5321/5322 compliance)
- buildRawMessage: plain message without attachments; multipart/mixed with
quoted-printable body + base64 attachments when Attachments non-empty;
multipart.NewWriter created first to obtain boundary before headers are written
- ParseFS(fsys, patterns...) (*Template, error) — wraps html/template.ParseFS
- Template.Render(name, data) (string, error) — executes named template
- net/smtp aliased as netsmtp to avoid package-name collision in package smtp
Config (EINHERJAR_SMTP_* env vars):
Host, Port(587), User, Password, From
- Component interface embeds observability.Identifiable; identifiable.go implements
ModulePath and ModuleVersion on both smtpClient and noopClient via
runtime/debug.ReadBuildInfo() — prints in launcher banner