feat: mail service

This commit is contained in:
Ilia Denisov
2026-04-17 18:39:16 +02:00
committed by GitHub
parent 23ffcb7535
commit 5b7593e6f6
183 changed files with 31215 additions and 248 deletions
+187
View File
@@ -0,0 +1,187 @@
# Runtime and Components
The diagram below focuses on the deployed `galaxy/mail` process and its runtime
dependencies.
```mermaid
flowchart LR
subgraph Callers
Auth["Auth / Session Service"]
Notify["Notification Service"]
Ops["Trusted operators"]
end
subgraph Mail["Mail Service process"]
InternalHTTP["Trusted internal HTTP listener\n/api/v1/internal/*"]
Consumer["Redis Stream command consumer"]
Scheduler["Attempt scheduler"]
Workers["Attempt worker pool"]
Cleanup["Index cleanup worker"]
Services["Application services"]
Templates["Immutable template catalog"]
Telemetry["Logs, traces, metrics"]
end
Redis["Redis\nstate + streams + indexes"]
Provider["SMTP or stub provider"]
Auth --> InternalHTTP
Ops --> InternalHTTP
Notify --> Redis
InternalHTTP --> Services
Consumer --> Services
Scheduler --> Services
Workers --> Services
Cleanup --> Services
Services --> Templates
Services --> Redis
Services --> Provider
InternalHTTP --> Telemetry
Consumer --> Telemetry
Scheduler --> Telemetry
Workers --> Telemetry
```
## Listener
`mail` exposes exactly one HTTP listener:
| Listener | Default addr | Purpose |
| --- | --- | --- |
| Internal HTTP | `:8080` | Trusted intake, operator reads, and resend |
Shared listener defaults:
- read-header timeout: `2s`
- read timeout: `10s`
- idle timeout: `1m`
Intentional omissions:
- no public listener
- no `/healthz`
- no `/readyz`
- no `/metrics`
## Startup Wiring
`cmd/mail` loads config, constructs logging, and builds the runtime through
`internal/app.NewRuntime`.
The runtime wires:
- Redis clients for state access and blocking stream consumption
- filesystem-backed template catalog
- provider adapter selected by `MAIL_SMTP_MODE`
- acceptance, render, execution, operator-read, and resend services
- internal HTTP server
- command consumer
- scheduler
- attempt worker pool
- cleanup worker
Before startup completes, the process performs bounded `PING` checks for both
Redis clients and validates the template catalog. Startup fails fast on invalid
configuration or unavailable Redis.
## Background Components
### Command consumer
- reads one plain `XREAD` stream
- starts from stored offset or `0-0`
- advances offset only after durable command acceptance or durable malformed
command recording
### Scheduler
- polls due work every `250ms`
- recovers stale claims every `30s`
- derives recovery deadline from `MAIL_SMTP_TIMEOUT + 30s`
### Attempt worker pool
- processes only already claimed work items
- concurrency is controlled by `MAIL_ATTEMPT_WORKER_CONCURRENCY`
### Cleanup worker
- removes stale delivery-index members after primary delivery expiry
- does not clean `mail:attempt_schedule`
- does not clean malformed-command index entries
## Configuration Groups
Required for all starts:
- `MAIL_REDIS_ADDR`
Core process config:
- `MAIL_SHUTDOWN_TIMEOUT`
- `MAIL_LOG_LEVEL`
Internal HTTP config:
- `MAIL_INTERNAL_HTTP_ADDR`
- `MAIL_INTERNAL_HTTP_READ_HEADER_TIMEOUT`
- `MAIL_INTERNAL_HTTP_READ_TIMEOUT`
- `MAIL_INTERNAL_HTTP_IDLE_TIMEOUT`
Redis connectivity:
- `MAIL_REDIS_USERNAME`
- `MAIL_REDIS_PASSWORD`
- `MAIL_REDIS_DB`
- `MAIL_REDIS_TLS_ENABLED`
- `MAIL_REDIS_OPERATION_TIMEOUT`
- `MAIL_REDIS_COMMAND_STREAM`
- `MAIL_REDIS_ATTEMPT_SCHEDULE_KEY`
- `MAIL_REDIS_DEAD_LETTER_PREFIX`
SMTP provider:
- `MAIL_SMTP_MODE`
- `MAIL_SMTP_ADDR`
- `MAIL_SMTP_USERNAME`
- `MAIL_SMTP_PASSWORD`
- `MAIL_SMTP_FROM_EMAIL`
- `MAIL_SMTP_FROM_NAME`
- `MAIL_SMTP_TIMEOUT`
- `MAIL_SMTP_INSECURE_SKIP_VERIFY`
Templates and workers:
- `MAIL_TEMPLATE_DIR`
- `MAIL_ATTEMPT_WORKER_CONCURRENCY`
- `MAIL_STREAM_BLOCK_TIMEOUT`
- `MAIL_OPERATOR_REQUEST_TIMEOUT`
- `MAIL_IDEMPOTENCY_TTL`
- `MAIL_DELIVERY_TTL`
- `MAIL_ATTEMPT_TTL`
Telemetry:
- `OTEL_SERVICE_NAME`
- `OTEL_TRACES_EXPORTER`
- `OTEL_METRICS_EXPORTER`
- `OTEL_EXPORTER_OTLP_PROTOCOL`
- `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL`
- `OTEL_EXPORTER_OTLP_METRICS_PROTOCOL`
- `MAIL_OTEL_STDOUT_TRACES_ENABLED`
- `MAIL_OTEL_STDOUT_METRICS_ENABLED`
## Runtime Notes
- `MAIL_REDIS_COMMAND_STREAM` is the only Redis key override that currently
changes runtime behavior
- `MAIL_SMTP_INSECURE_SKIP_VERIFY` is a local-development escape hatch for
self-signed SMTP capture only and should remain disabled in production
- attempt-schedule and dead-letter key overrides are parsed but not yet wired
into Redis adapters
- retention overrides are parsed but storage still uses the fixed `7d`, `30d`,
and `90d` values
- template catalog parsing is eager and immutable
- auth deliveries in `MAIL_SMTP_MODE=stub` surface as `suppressed`
- auth deliveries in `MAIL_SMTP_MODE=smtp` surface as `queued` and later move
through normal attempt execution