Changelog

Public release history, in the open.


squibble/email began as internal infrastructure in 2020, powering email for obseed.me across multiple internal iterations and adding linubra.com as the second production tenant in October 2025. The public release history below starts with v2.0 — the first version offered to external teams in April 2026 — and continues through every change since.

Versions follow SemVer. Breaking changes ship in major versions and are flagged in the Changed section. Security-relevant changes are called out separately.

  1. v2.5.2

    Current

    Mailbox From display name

    Operators can now set a human-readable display name on any mailbox. The name appears as the friendly sender label in mail clients ("Acme Corp <hello@example.com>") without affecting the sender-binding invariant — the email address remains irrevocably tied to the authenticated mailbox.

    Added

    • cli mailboxes:update --display-name "…" — sets the From display name for a mailbox. Pass an empty string to clear it (falls back to the IMAP username). Operator-only; no request-body or token-level override is possible.
    • db Migration 0014 — nullable display_name column on the mailboxes table. All existing mailboxes default to NULL (no behaviour change until explicitly set).
  2. v2.5.1

    Markdown CI fix

    Fixed

    • ci Markdown Docker image build now pulls node:22-alpine from Docker Hub directly — the internal registry mirror does not carry this image, causing the v2.5.0 pipeline to fail.
  3. v2.5.0

    Markdown renderer wired into production

    The app_markdown sidecar was present in development but never deployed to production — every POST /api/v1/messages/send-markdown call returned 503. v2.5.0 wires it fully into the Ansible/Docker Swarm stack.

    Added

    • ci Dedicated CI job builds and pushes the markdown Docker image (app_markdown/Dockerfile) on every tagged release.
    • deploy MARKDOWN_RENDERER_URL injected into the app environment via Ansible; app_email__markdown__* vars control replicas, CPU, memory, and port.

    Fixed

    • deploy POST /api/v1/messages/send-markdown returned 503 in production because the markdown sidecar service was missing from the Docker Swarm stack. Now deployed as a first-class service with health checks and resource limits.
  4. v2.3.7

    Outbound attachment support

    Both POST /api/v1/messages/send and POST /api/v1/messages/send-markdown now accept an attachments array. Files are base64-encoded by the client, decoded and validated server-side, and assembled into a MIME multipart message before dispatch.

    Added

    • api attachments field added to POST /api/v1/messages/send and POST /api/v1/messages/send-markdown — optional array of base64-encoded files with filename and content_type.
    • api Per-file size limit: 10 MiB decoded. Total size limit: 25 MiB across all attachments in a single request. Max 20 attachments per send.
    • api Attachment validation (base64 decode, per-file size, total size) runs synchronously at request time — the entire request is rejected with 422 if any attachment is invalid.
    • docs Attachments section added to the API reference (/docs) with limits, curl examples, and validation error shapes.
  5. v2.3.6

    Markdown send · emailmd sidecar

    New send-markdown endpoint accepts a Markdown body, renders it to HTML via the emailmd sidecar, and dispatches through the existing outbound pipeline — no client-side HTML templating required.

    Added

    • api POST /api/v1/messages/send-markdown — Markdown body rendered to HTML by the emailmd sidecar before delivery; all existing send constraints (idempotency, quotas, suppressions) apply.
    • markdown emailmd sidecar service (app_markdown/) bundled in the Docker Swarm stack; port configurable via MARKDOWN_RENDERER_PORT (default 3853).
    • docs send-markdown endpoint documented across /docs API reference, curl examples, and the /docs/features/markdown-send feature page.

    Fixed

    • api Markdown sidecar now emits RFC 9457 problem+json error bodies on render failures, consistent with the rest of the API.
    • docs API base URL corrected throughout docs — api.email.squibble.ch (not email.squibble.ch).
  6. v2.3.5

    Legal pages · nginx 404 fix

    Added

    • marketing Impressum, Datenschutzerklärung, and AGB pages shipped under /impressum, /datenschutz, and /agb; all linked from the site footer.

    Fixed

    • infra nginx now serves Astro's custom 404 and 5xx error pages instead of the raw nginx defaults.
  7. v2.3.1 – v2.3.4

    Observability hardening · deploy fixes

    Added

    • observability LOG_LEVEL environment variable controls runtime log verbosity (debug / info / warning / error) without a redeploy.

    Fixed

    • workers Graylog GELF handler wired into all background worker entry points — previously only the main API process shipped structured logs.
    • observability Health-check endpoint requests suppressed from access logs to reduce noise.
    • deploy Alembic migration now runs as a Docker Swarm one-shot service to avoid the non-attachable overlay network constraint.
    • deploy package.json path resolved correctly in both Docker and local-dev contexts.
    • ci docs/ directory copied into the nginx_marketing Docker build stage so /docs routes serve correctly after deploy.
  8. v2.3.0

    Waitlist double-opt-in · structlog · examples

    Waitlist signup gains a double-opt-in confirmation flow. Structured logging ships via structlog + Graylog. The examples directory adds a LangChain agent and a Playwright auth-flow demo.

    Added

    • waitlist Double-opt-in confirmation flow — HMAC-signed token emailed on signup; GET /confirm activates the entry. Adds 0012 migration (confirmation columns).
    • waitlist /waitlist/confirmed landing page shown after email link click.
    • observability structlog + Graylog GELF integration for structured, searchable log shipping from the API process.
    • examples LangChain email-agent demo (tools: send, list, read, reply) and Playwright auth-flow demo added to examples/.
    • examples Idempotent seed script for spinning up a reproducible demo tenant.
    • deploy Alembic migrations run as a pre-deploy one-shot step; prod and dev env templates aligned.
    • docs Architecture and feature pages from the repo published at /docs/architecture and /docs/features/* with sidebar cross-links.

    Fixed

    • marketing Admin notification emails HTML-escape user-supplied fields (waitlist XSS hardening).
    • waitlist Signup record refreshed from DB after mark_confirmed commit to avoid stale-cache render.
    • email IMAP account creation now accepts non-deliverable usernames (e.g. service accounts without an inbox).
  9. v2.2.0

    Legacy API host proxy

    Fixed

    • infra Legacy API hostname (email.squibble.ch/api) is now proxied to api.email.squibble.ch instead of issuing a 301 redirect — prevents reconnection loops in mail clients that do not follow redirects.
  10. v2.1.0

    Marketing site, /security, /team

    Public marketing surface ships. Trust-signal pages (/security, /team), AI-citation polish across home + docs, and full SEO baseline (robots, sitemap, JSON-LD, OG, CSP).

    Added

    • marketing /security page — threat model, JWT (RFC 7519) token model, fail-closed STARTTLS (RFC 3207), Fernet at-rest encryption, GDPR Art. 5 PII redaction, RFC 3463/8058 suppression, Switzerland/FADP jurisdiction.
    • marketing /team page — founder bio, full role history, Person + BreadcrumbList JSON-LD with sameAs link to canonical CV.
    • marketing Custom 404 and 500 error pages.
    • marketing Transactional-email integration walkthrough page under /docs/integration.
    • marketing curl examples in every section of the API reference docs.
    • marketing Waitlist endpoint + frontend form with backend persistence.
    • seo robots.txt, OG image, sitemap-index.xml, JSON-LD schemas (Organization, BreadcrumbList, TechArticle, Person).
    • infra CSP + Permissions-Policy headers on the marketing nginx.

    Changed

    • marketing Hero copy now names obseed.me (since 2020) and linubra.com (since October 2025) as live tenants.
    • marketing AI-citation polish: home + /docs claims now anchored to RFCs (3207, 7519, 3463) and named primitives (Stripe idempotency, Fernet AES-128-CBC+HMAC-SHA256).
    • docs /docs gains an Overview section framing the three API surfaces; sections renumbered 02–11.
    • errors API error type URIs migrated to email.squibble.ch/docs/errors path.
    • design Editorial serif palette aligned with squibble.ch brand system.
  11. v2.0.13

    API errors → RFC 9457

    Added

    • api Error handling upgraded from RFC 7807 to RFC 9457 (Problem Details for HTTP APIs, current standard).
    • repo Monorepo restructure — backend moved to app_backend/, marketing site scaffolded under app_marketing/ (Astro).
  12. v2.0.5 – v2.0.12

    CLI completeness · deploy hardening

    Added

    • cli mailboxes:update command with partial-update sentinel (ADR 0003).
    • cli tokens:issue alias for token issuance.
    • cli Per-mailbox progress + timeouts in mailboxes:validate.

    Fixed

    • deploy Wait for postgres before running migrations.
    • deploy Skip postgres hostname constraint when unset.
    • deploy Use docker provider for Traefik labels on Galaxy.
    • ci Connect to Galaxy as root, not ubuntu (ADR recorded).
  13. v2.0.0 – v2.0.4

    v2.0 — Outbound gateway production cutover

    First public production release of the outbound gateway. Five-phase build delivered an end-to-end SMTP send pipeline with signed tracking, RFC-compliant suppressions, and Prometheus observability.

    Added

    • api POST /api/v1/messages/send with size + recipient-count limits and Idempotency-Key dedup.
    • api Per-token send quotas and recipient-domain allowlists.
    • worker Async background worker with claim/deliver/finalize split (no double-send window).
    • worker List-Unsubscribe + List-Unsubscribe-Post headers on outbound MIME (RFC 8058 one-click).
    • unsubscribe POST + GET /api/v1/unsubscribe with HMAC-signed tokens; message_id embedded in token.
    • verp VERP Return-Path encoding + RFC 3464 bounce parser.
    • suppressions 422 enforcement at send-time; bounce cron syncs into the suppressions table; pagination + cancel-while-processing block.
    • tracking Signed tracking tokens — open redirects removed.
    • metrics Prometheus metrics module wired through delivery pipeline, bounce cron, and API.
    • deploy Ansible-based Docker Swarm deployment under .gitlab/deploy/.
    • infra Postgres 18.3 added to the production stack.
    • tooling bin/run task runner with gitlab:tags:create.
    • cli mailboxes:destroy command.

    Changed

    • schema Alembic migration framework introduced; baseline + outbound gateway migrations on top.

    Security

    • api Sender headers bound to authenticated mailbox (FEEDBACK §1.4) — prevents spoofing across tenants.
    • tls SMTP TLS dispatch by mailbox policy (smtp_tls_mode enum), not by port.
    • docs OpenAPI docs hidden in production.
  14. v1.0 – v1.2

    Inbound IMAP proxy hardening

    Pre-cutover hardening of the inbound IMAP proxy carried over from the internal era: secure authorization, rate limiting, admin CLI revamp.

    Added

    • imap Secure IMAP proxy authorization + per-key rate limiting.
    • cli Admin CLI revamp — namespacing, list views, backup command.
    • cli validate-mailboxes (now mailboxes:validate) — IMAP connection health checks.
    • cli Explicit help command.

Ready to integrate?

We onboard a small batch of teams each week and reply within one business day.