# REPORT — App-email gap closure: calcom + nextcloud wired (plaintext :2526 + split-From) **Date:** 2026-06-29 **Task:** Wire cal.com + nextcloud now that the controller (v0.89.0) has the `:2526` plaintext-only listener (Gap 1) and `tls_mode`/`from_domain_var` mapping fields (Gap 2). Catalog-only; live send-tests. ## Mappings added - **nextcloud** (`tls_mode: plaintext`, split From): `host_var=SMTP_HOST`, `port_var=SMTP_PORT`, `from_var=MAIL_FROM_ADDRESS`, `from_domain_var=MAIL_DOMAIN`, `from_local=nextcloud`; no `security_var` (`SMTP_SECURE` stays empty = no TLS). Compose references the injected `${SMTP_*}` + `${MAIL_*}`. **Live send confirmed:** real password-reset → Symfony Mailer **plaintext to :2526** (no STARTTLS) → hub → Resend, From `nextcloud@felhom.eu` (split From), shim `hub=200`. nextcloud applied the env on redeploy (`occ` shows `mail_smtpport=2526`, `mail_from_address=nextcloud`, `mail_domain=felhom.eu`) — every-boot `getenv`, **no occ step needed (§8)**. - **cal.com** (`tls_mode: plaintext`): `host_var=EMAIL_SERVER_HOST`, `port_var=EMAIL_SERVER_PORT`, `from_var=EMAIL_FROM`, `from_name_var=EMAIL_FROM_NAME`, `from_local=calcom`; secure inferred from the port (2526 → plaintext). Compose references the injected `${EMAIL_*}`. Injected env verified in-container (`EMAIL_SERVER_PORT=2526`, `EMAIL_FROM=calcom@felhom.eu`). **Live send confirmed:** a real signup (201 "Created user") → Nodemailer **plaintext to :2526** (no STARTTLS) → hub → Resend, From `calcom@felhom.eu`, shim `hub=200`. ## Pre-existing cal.com template bugs fixed (never caught — bad pin meant calcom never deployed) 1. **Image pin `calcom/cal.com:v4.8.7` doesn't exist** as a published image (manifest unknown) → `v4.6.9` (nearest valid 4.x; same `EMAIL_SERVER_*` behaviour). 2. **Missing `DATABASE_DIRECT_URL`** — cal.com's Prisma schema declares `directUrl=env(DATABASE_DIRECT_URL)`; without it `prisma migrate deploy` fails (P1012) on startup → incomplete schema → `/api/health` 500s. Added (same direct Postgres URL). 3. **Healthcheck path `/api/health` is 404 in v4.x** → container stayed unhealthy → Traefik wouldn't route it. Changed to `/api/auth/providers` (stable 200) in both the docker healthcheck and the `.felhom.yml` probe. ## Validation - All four edited files YAML-validated; field names match the controller's `stacks.SMTPMapping` tags. - The `:2526` plaintext-no-STARTTLS mechanism is proven end-to-end by the nextcloud real send; cal.com uses the identical mechanism (Nodemailer) with its env verified. ## Notes - **immich still unwired by decision** (Gap 3 — no SMTP env; needs config-file injection). - Other email-capable apps (ghost, outline, grafana, …) now wire as `tls_mode: plaintext` with no per-app TLS determination. No secrets in any committed file.