Umgebungsvariablen
Referenz zu jeder Umgebungsvariablen, die Owlat im Convex-Backend, in der Web-App, in der MTA, im IMAP-Server und im Mail-Sync-Worker liest.
Owlat nutzt Umgebungsvariablen, um Provider, Sicherheitsprüfungen, Authentifizierung und die Voraussetzungen von Feature-Flags zu konfigurieren. Variablen des Convex-Backends (alles, was über apps/api/convex/lib/env.ts gelesen wird) setzen Sie im Convex-Dashboard; Web-App, MTA, IMAP-Server und Mail-Sync-Worker lesen ihre eigene Prozessumgebung (im Self-Hosting stammt alles davon aus einer einzigen .env-Datei, die docker-compose.yml einliest).
Die meisten Leserinnen und Leser dieser Seite hosten Owlat selbst. Der Abschnitt Self-hosted configuration weiter unten ist die maßgebliche Referenz dafür, was in Ihre .env gehört. Variablen sind nur für die Funktionen relevant, die Sie aktiviert haben — der Setup-Assistent erfasst nur diejenigen, die Ihre aktivierten Flags benötigen, und jeden einzelnen Wert können Sie später mit owlat-setup env <KEY> <VALUE> setzen. Um genau aufzulisten, welche Variablen Ihr aktueller Flag-Zustand benötigt (und welche noch nicht gesetzt sind), führen Sie owlat-setup env --show aus.
Jeder Eintrag in packages/shared/src/featureFlags.ts kann requiredEnvVars deklarieren. Der Setup-Assistent erfasst nur die Variablen, die zu Ihren aktivierten Flags passen — Sie müssen nicht alles setzen. Die vollständige Registry finden Sie in der Entwicklerreferenz zu Feature-Flags.
Konfiguration beim Self-Hosting
Self-Hoster legen alles in einer einzigen .env-Datei im Wurzelverzeichnis des Repositorys ab. Beginnen Sie mit der Vorlage:
cp .env.selfhost.example .env
Die Vorlage und docker-compose.yml verweisen auf diese Variablen:
Erforderliche Geheimnisse
| Variable | Beschreibung | Erzeugen mit |
|---|---|---|
INSTANCE_SECRET | Root-Geheimnis des Convex-Backends. HKDF-Wurzel für die Verschlüsselung ruhender Zugangsdaten (Passwörter externer Postfächer, lib/credentialCrypto.ts) und gemeinsames Geheimnis, das die Dev-/Seed-Endpunkte absichert (/seed/admin, /seed/demo, /dev/reset). | openssl rand -hex 32 |
INSTANCE_SECRET_PREVIOUS | Optional. Das vorherige INSTANCE_SECRET, nur während einer Rotation des Geheimnisses aufbewahrt. Ist es gesetzt, lassen sich ruhende Geheimnisse, die noch unter der alten Wurzel versiegelt sind, weiterhin entschlüsseln, während e2ee/lifecycleNode.ts:reSealVault jede Zeile unter dem neuen INSTANCE_SECRET neu versiegelt. Entfernen Sie die Variable, sobald die Neuversiegelungs-Migration abgeschlossen ist. | (das alte INSTANCE_SECRET einfügen) |
CONVEX_ADMIN_KEY | Admin-Schlüssel zum Deployen von Funktionen. Nach dem ersten Start über docker compose exec convex ./generate_admin_key.sh erzeugen. | (siehe oben) |
MTA_API_KEY | API-Schlüssel, mit dem die Tenant-App Sendevorgänge in der MTA einreiht. | openssl rand -base64 32 |
MTA_WEBHOOK_SECRET | HMAC-Geheimnis für Zustellereignis-Callbacks von der MTA an Convex. | openssl rand -base64 32 |
Öffentliche URLs
| Variable | Beschreibung | Standard |
|---|---|---|
NUXT_PUBLIC_CONVEX_URL | Browserseitige Convex-URL. Muss dem entsprechen, was Sie über den Reverse Proxy veröffentlichen. | http://localhost:3210 |
NUXT_PUBLIC_CONVEX_SITE_URL | Browserseitige URL der Convex-HTTP-Actions. | http://localhost:3211 |
NUXT_PUBLIC_CONVEX_DASHBOARD_URL | Optional. Explizite URL des Convex-Admin-Dashboards (Port 6791), das aus dem Onboarding-Banner beim Self-Hosting verlinkt wird. Lassen Sie den Wert leer, wenn Sie das Dashboard über einen SSH-Tunnel erreichen — das Banner errät dann einen Standard, den der Betreiber in der App überschreiben kann. | (leer) |
NUXT_PUBLIC_SITE_URL | Öffentliche URL der Web-App. | http://localhost:3000 |
MTA (E-Mail-Versand)
| Variable | Beschreibung | Standard |
|---|---|---|
EHLO_HOSTNAME | Muss dem rDNS-PTR-Eintrag Ihres Servers entsprechen. Die Vorlage liefert mail.example.com aus. | mail.localhost (Compose-Fallback) |
EHLO_HOSTNAMES | Optionale JSON-Zuordnung von jeder sendenden IP zu ihrem PTR-passenden EHLO-Hostnamen. | — |
MTA_GENERIC_PTR_SUFFIXES | Zusätzliche, kommagetrennte PTR-Standardsuffixe von Providern, vor denen gewarnt werden soll. | — |
MTA_ALLOW_UNVERIFIED_FCRDNS | Umgehung der harten FCrDNS-Quarantäne, nur für Laborumgebungen. Der fehlgeschlagene Status bleibt sichtbar. | false |
MTA_IPV6_ENABLED | Explizites Opt-in für ausgehendes IPv6. Lassen Sie den Wert auf false, bis die geroutete Adresse, die IPv4-Identität, PTR/AAAA und der exakte ip6:-Mechanismus im Return-Path verifiziert sind. | false |
RETURN_PATH_DOMAIN | Domain für VERP-Return-Path-Adressen von Bounces. Die Vorlage liefert bounces.example.com aus. | bounces.localhost (Compose-Fallback) |
BOUNCE_VERP_KEY | Erforderliches Geheimnis, das VERP-Return-Path-Token signiert (BATV/HMAC). Eine exakte DSN-/FBL-Zuordnung setzt ein von der MTA signiertes Token voraus und verhindert, dass gefälschtes Feedback die Suppression vergiftet. Das Setup erzeugt es automatisch; bei manuellen Installationen können Sie openssl rand -base64 32 verwenden. Halten Sie den Wert stabil. Beispieldateien lassen ihn leer, damit eine kopierte, unkonfigurierte Umgebung fail-closed scheitert. | erforderlich (mindestens 32 Bytes; Platzhalter werden abgelehnt) |
IP_POOLS_TRANSACTIONAL | Kommagetrennte IP(s) für transaktionale Sendungen. | 127.0.0.1 |
IP_POOLS_CAMPAIGN | Kommagetrennte IP(s) für Marketingkampagnen. | 127.0.0.1 |
DKIM_KEYS | JSON: {"example.com":{"selector":"s1","privateKey":"..."}}. | {} |
WORKER_CONCURRENCY | Maximale Anzahl gleichzeitiger SMTP-Zustellungen. | 50 |
FBL_DEDUP_PROTOCOL | Erforderliches, versioniertes Reservierungsprotokoll für Beschwerden. Setzen Sie owned-v2; einen automatischen Legacy-/Shadow-Modus gibt es nicht. Siehe FBL deduplication upgrade. | erforderlich |
FBL_DEDUP_CUTOVER_ACK | Erforderliche betriebliche Bestätigung: fresh-install nur bei neuem Redis-/Installationszustand oder quiesced-v1-intake, nachdem jeder Legacy-FBL-Worker gestoppt und geleert wurde. | erforderlich |
MTA_LOG_LEVEL | Ausführlichkeit des Logs (debug/info/warn/error). Dies ist ein Alias in der Host-Umgebung von Compose — docker-compose.yml bildet ihn auf LOG_LEVEL ab, und das ist der Wert, den der MTA-Prozess tatsächlich liest. | info |
DANE_MODE | DANE-Haltung (RFC 7672) zur Sendezeit — off (Standard), report oder enforce. off ist Byte für Byte identisch mit dem bisherigen Verhalten (keine TLSA-Abfragen). report fragt das DNSSEC-validierte TLSA-RRset jedes empfangenden MX ab (_25._tcp.<mx>), bewertet das Zertifikat dagegen und gibt das TLS-RPT-Ergebnis aus (success/validation-failure unter der Policy tlsa), erzwingt aber niemals TLS und erzeugt keine Bounces. enforce authentifiziert das Zertifikat zusätzlich gegen das RRset (hat Vorrang vor MTA-STS; bei fehlender Übereinstimmung wird die Nachricht zurückgestellt, niemals im Klartext gesendet). report und enforce benötigen DANE_RESOLVER_URL. Wird aus der eigenen Prozessumgebung der MTA gelesen (apps/mta/src/config.ts), nicht aus dem Convex-Dashboard (apps/mta/src/smtp/daneVerify.ts). Ein unbekannter Wert lässt den Start fehlschlagen. | off |
DANE_RESOLVER_URL | Resolver-URL für DoH (DNS-over-HTTPS, RFC 8484 JSON) zur DNSSEC-fähigen MX-/Adressermittlung und für DANE-TLSA-Abfragen. Erforderlich, damit report/enforce laufen — ist sie nicht gesetzt, bleibt DANE in jedem Modus wirkungslos (keine Abfragen, historischer Pfad). Ist sie gesetzt, muss sie https:// sein (einfaches http:// wird nur für einen Loopback-Resolver akzeptiert, da das vertrauenswürdige DNSSEC-AD-Bit über einen Kanal übertragen werden muss, den ein On-Path-Angreifer nicht fälschen kann); die MTA validiert die URL beim Start in jedem Modus. Es muss ein validierender Resolver sein: Dem AD-Bit wird vertraut, DANE wird nicht über eine unsichere Adresskette angewendet, und eine Abfrage, die nicht abgeschlossen werden kann (SERVFAIL/Timeout), stellt die Zustellung im Modus enforce zurück (und ist in report wirkungslos), statt herabzustufen. Ein lokaler validierender Resolver (z. B. Unbound auf 127.0.0.1) ist die empfohlene Produktionskonfiguration. | nicht gesetzt |
Die Spalte Standard gibt den Fallback aus docker-compose.yml wieder, der greift, wenn eine Variable nicht gesetzt ist. Die in .env.selfhost.example ausgelieferten Werte weichen bei den beiden Domain-Variablen oben ab (mail.example.com / bounces.example.com), denn das ist es, was Sie tatsächlich kopieren und bearbeiten.
Deployment-Modus (Web-App & Compose)
Dies sind keine Convex-Backend-Variablen — sie werden nicht über lib/env.ts gelesen. OWLAT_DEPLOYMENT_MODE wird von der Web-App verwendet (apps/web/nuxt.config.ts, veröffentlicht als runtimeConfig.public.deploymentMode) und von docker-compose.yml an den Web-Container übergeben. OWLAT_HOSTED_MODE ist ein .env-Flag, das das Setup-CLI anhand des gewählten Deployment-Modus schreibt; in diesem OSS-Repository ist es wirkungslos (kein Dienst liest es), Self-Hoster lassen es also auf false.
| Variable | Beschreibung | Standard |
|---|---|---|
OWLAT_DEPLOYMENT_MODE | selfhost oder hosted. Steuert die Onboarding-UX beim ersten Start und blendet nur für Hosted gedachte UI (Abrechnung, Upgrade-Hinweise) in der Web-App aus. | selfhost |
OWLAT_HOSTED_MODE | .env-Flag, das das Setup-CLI aus dem gewählten Deployment-Modus schreibt. In diesem OSS-Repository wirkungslos — kein Dienst liest es. Self-Hoster lassen es auf false. | false |
OWLAT_VERSION | Zur Build-Zeit in die Images eingebettete Version für In-App-Update-Prüfungen. Wird von der CI automatisch gesetzt. | dev |
Port-Overrides (optional)
Alle Ports haben sinnvolle Standardwerte. Überschreiben Sie sie nur, wenn die Standardwerte kollidieren:
# CONVEX_PORT=3210
# CONVEX_SITE_PORT=3211
# DASHBOARD_PORT=6791
# WEB_PORT=3000
# MTA_HTTP_PORT=3100
# MTA_SMTP_PORT=25
# IMAP_PORT=993
Optional: PostHog-Analytics
# NUXT_PUBLIC_POSTHOG_API_KEY=
# NUXT_PUBLIC_POSTHOG_HOST=https://eu.i.posthog.com
Optional: LLM-Provider (Flag ai)
Nur nötig, wenn ein KI-Flag aktiv ist. Alle Details finden Sie unter Providers → LLM provider.
# LLM_PROVIDER=openai # openai | openrouter | ollama (Claude works via openai + an OpenAI-compatible LLM_BASE_URL)
# LLM_API_KEY=sk-...
# LLM_MODEL_FAST=gpt-4o-mini # used for classify/extract/guard/summarize
# LLM_MODEL_CAPABLE=gpt-4o # used for draft tasks
# LLM_MODEL= # single-model fallback for both tiers when *_FAST/*_CAPABLE are unset
# LLM_EMBEDDING_MODEL=text-embedding-3-small
# LLM_BASE_URL= # override for ollama / vLLM / LM Studio
# --- Local-by-default embedding plane (optional) ---
# LOCAL_EMBEDDING_BASE_URL=http://ollama:11434/v1 # an OpenAI-compatible /embeddings sidecar
# LOCAL_EMBEDDING_MODEL=nomic-embed-text # NOTE: its width must match the vector index
KI-Ausgabenbudget (Dollar-Obergrenze je Organisation)
Ein Gate vor dem Aufruf (convex/analytics/spendBudget.ts), das die LLM-Ausgaben in Dollar je Organisation deckelt — zusätzlich zu den Rate Limits nach Aufrufanzahl. Die Ausgaben werden aus analytics/llmUsage + lib/llm/pricing aggregiert. Ist eine Obergrenze erreicht, schaltet das Gate fail-closed: Der autonome Agent fällt auf reine Entwürfe zurück (E-Mail geht nie verloren — sie wird zur menschlichen Prüfung geleitet), und beratende, von Nutzenden ausgelöste KI wird pausiert, sobald der verbleibende Spielraum in die Reserve rutscht. Alle vier Variablen sind standardmäßig nicht gesetzt bzw. 0, wodurch das Gate wirkungslos ist.
| Variable | Bedeutung | Standard |
|---|---|---|
AI_SPEND_DAILY_BUDGET_USD | Tägliche USD-Obergrenze für alle LLM-Ausgaben einer Organisation. Nicht gesetzt oder 0 ⇒ kein Tageslimit (das Gate ist für den Tag wirkungslos). | nicht gesetzt (kein Limit) |
AI_SPEND_MONTHLY_BUDGET_USD | Monatliche USD-Obergrenze für alle LLM-Ausgaben einer Organisation. Nicht gesetzt oder 0 ⇒ kein Monatslimit. | nicht gesetzt (kein Limit) |
AI_SPEND_WARN_FRACTION | Anteil einer Obergrenze (0–1], ab dem im Admin-Dashboard vor der harten Sperre gewarnt wird. | 0.8 |
AI_SPEND_ADVISORY_RESERVE_FRACTION | Anteil einer Obergrenze [0–1), der für das autonome Entwerfen reserviert ist; beratende (von Nutzenden ausgelöste) KI wird pausiert, sobald der verbleibende Spielraum in diese Reserve rutscht, während der autonome Pfad weiter entwirft. | 0.2 |
Optional: Private E-Mail / IMAP (Flag postbox)
Der IMAP-Server (apps/imap) liest diese Werte beim Start. Nur relevant, wenn das Flag postbox aktiv ist.
# IMAP_PORT=993
# IMAP_LISTEN=0.0.0.0
# IMAP_GREETING_HOST=mail.example.com
# IMAP_TLS_CERT_FILE=/opt/owlat/certs/default.crt
# IMAP_TLS_KEY_FILE=/opt/owlat/certs/default.key
# TLS_CERT_DIR=/opt/owlat/certs # fallback if IMAP_TLS_* not set
# REDIS_URL= # see note below
Der IMAP-Server authentifiziert sich gegenüber Convex mit CONVEX_ADMIN_KEY (er setzt die Admin-Authentifizierung an einem ConvexHttpClient und ruft die Funktion mail/appPasswords:verify direkt auf — apps/imap/src/convex.ts). Er liest MTA_WEBHOOK_SECRET nicht. Sein Log-Level stammt aus LOG_LEVEL (die VPS-Compose-Datei bildet IMAP_LOG_LEVEL darauf ab).
REDIS_URL ist am ausgelieferten imap-Dienst in infra/templates/docker-compose.vps.yml nicht gesetzt. Ist die Variable nicht gesetzt, ist der Rate Limiter für die IMAP-Authentifizierung deaktiviert und schaltet fail-open (apps/imap/src/index.ts). Setzen Sie REDIS_URL ausdrücklich, wenn Sie eine Drosselung der Anmeldungen am IMAP-Listener benötigen.
Optional: Mail-Sync — externe Postfächer (Flag mail.external)
Ist das Flag mail.external aktiv, können Nutzerinnen und Nutzer eigene IMAP-/SMTP-Konten verbinden. Convex übergibt diese an einen separaten Mail-Sync-Worker (infra/templates/docker-compose.vps.yml, Compose-Profil external-mail). Convex erreicht den Worker auf demselben Weg wie die MTA — über Deployment-Umgebungsvariablen, die im Convex-Dashboard gesetzt werden:
| Variable | Beschreibung |
|---|---|
MAIL_SYNC_API_URL | Basis-URL der internen /send- + /test-API des Mail-Sync-Workers (z. B. http://mail-sync:3200). Ist sie nicht gesetzt, wird jede Empfängerin und jeder Empfänger eines Versands über ein externes Konto auf einen Zustellfehler überführt (errorCode EXTERNAL_NOT_CONFIGURED), statt versendet zu werden (apps/api/convex/mail/outbound.ts). |
MAIL_SYNC_API_KEY | Gemeinsamer API-Schlüssel, mit dem sich Convex gegenüber dem Mail-Sync-Worker authentifiziert. |
Optional: Eingehende Kanal-Webhooks (SMS / WhatsApp / generisch)
Diese Geheimnisse authentifizieren eingehende Webhook-Callbacks von Drittanbieter-Kanalprovidern. Sie werden von den Webhook-Adaptern in apps/api/convex/webhooks/adapters/ gelesen. (Nur eingehend — der ausgehende SMS-/WhatsApp-Versand ist nicht durchgängig verdrahtet; siehe Communication Channels.)
| Variable | Beschreibung |
|---|---|
TWILIO_AUTH_TOKEN | Validiert X-Twilio-Signature bei eingehenden SMS-/Voice-Webhooks (webhooks/adapters/twilio.ts). Der Endpunkt weist Anfragen ab, wenn der Wert fehlt. |
META_APP_SECRET | Validiert den HMAC X-Hub-Signature-256 bei eingehenden WhatsApp-/Messenger-Webhooks (webhooks/adapters/meta.ts). |
META_VERIFY_TOKEN | Muss beim Webhook-Abonnement-Challenge von Meta mit hub.verify_token übereinstimmen (webhooks/adapters/meta.ts). |
GENERIC_WEBHOOK_SECRET | Wird mit dem Header x-webhook-secret am generischen Adapter für eingehende Kanäle verglichen (webhooks/adapters/generic.ts). |
Optional: Weitere Convex-Backend-Variablen
Einige weitere Variablen werden über lib/env.ts gelesen und im Convex-Dashboard gesetzt. Keine davon ist für ein einfaches Self-Hosting erforderlich:
| Variable | Beschreibung | Standard |
|---|---|---|
OWLAT_DEV_MODE | Schaltet die nur für die Entwicklung gedachten Endpunkte frei (/seed/demo, /dev/reset, forceVerifyDomain). Fail-closed: Bleibt die Variable in einem Produktions-Deployment ungesetzt, weisen diese Endpunkte Anfragen ab (devShortcuts/_guard.ts). Für Demo-Inhalte in einer echten Installation wird sie nicht benötigt — verwenden Sie owlat sample-data install (/sample-data/*). | nicht gesetzt (aus) |
ALLOWED_ORIGINS | Kommagetrennte CORS-Allowlist für die Convex-HTTP-API (lib/cors.ts). | http://localhost:3000 |
ADMIN_SITE_URL | Optionale alternative Site-URL, der für Auth-Weiterleitungen vertraut wird (auth/auth.ts). | — |
MTA_SPF_INCLUDE | SPF-include:-Host, der in den generierten DNS-Einträgen ausgegeben wird. Ist die Variable nicht gesetzt, entfällt der SPF-Eintrag (die DKIM+DMARC-Ausrichtung funktioniert weiterhin) (domains/providers/mta/index.ts). | — |
SPF_QUALIFIER | Qualifizierer des abschließenden all-Mechanismus in den generierten SPF-Einträgen: ~all (Soft-Fail, der sichere Standard, solange sich Ihr autorisierter IP-Bestand noch einpendelt), -all (Hard-Fail, sobald der IP-Bestand stabil ist), ?all oder +all. Ungültig oder nicht gesetzt fällt auf ~all zurück (RFC 7208 §5.1) (domains/spf.ts). | ~all |
MTA_RETURN_PATH_DOMAIN | VERP-Return-Path-Domain für Bounces (entspricht RETURN_PATH_DOMAIN der MTA, z. B. bounces.example.com). Gemeinsam mit MTA_IP_POOLS gesetzt, enthält das generierte DNS-Bündel einen Return-Path-SPF-TXT-Eintrag, der die Pool-IPs autorisiert, sodass der Bounce-Envelope SPF besteht (domains/providers/mta/index.ts). | — |
MTA_BOUNCE_VERP_KEY | Der VERP-Signierschlüssel der MTA (derselbe Wert wie BOUNCE_VERP_KEY der MTA). Setzen Sie ihn zusammen mit MTA_RETURN_PATH_DOMAIN, damit RELAY-Sendungen Owlats eigenen VERP-Envelope-Absender tragen; so kommen Bounces, die ein Drittanbieter-Relay erzeugt, beim Bounce-Server der eingebauten MTA an, und der Relay-Arm liefert Bounce-Daten, die mit der direkten MX-Zustellung vergleichbar sind. Additiv: Ist die Variable nicht gesetzt (oder ist nicht erwiesen, dass das Relay einen eigenen Return-Path respektiert), behalten Relay-Sendungen den Envelope-Absender des Composers, und dieser Transport wird schlicht als „degraded measurement“ bewertet — blockiert wird nichts (lib/sendProviders/smtp/index.ts). | — |
MTA_RETURN_PATH_RELAY_SPF | SPF-Mechanismus-Terme (durch Leerzeichen oder Kommas getrennt; nur include:/a:/mx:/ip4:/ip6:), die Ihr RELAY autorisieren, mit einem Envelope-Absender bounce+…@<return-path host> zu senden. Sie werden in den generierten Return-Path-SPF-Eintrag ausgegeben und sind erforderlich — veröffentlicht und verifiziert —, bevor eine Relay-Sendung unsere VERP-Adresse trägt: Andernfalls autorisiert der Eintrag nur den MTA-Pool, sodass ein Aufprägen auf eine Relay-Sendung genau auf dem gemessenen Arm SPF scheitern ließe und das SPF-Bein von DMARC entfernen würde. Es werden höchstens 5 Terme akzeptiert (RFC 7208 §4.6.4 veranschlagt zehn DNS-Abfragen je Auswertung, und der Eintrag verbraucht bereits einige) — Überzähliges wird verworfen, nie abgelehnt. Diese Terme ergänzen die Pool-Autorisierung, statt sie zu ersetzen, und werden daher nur ausgegeben, wenn auch MTA_IP_POOLS gesetzt ist; für sich allein veröffentlicht der Wert nichts. Nicht gesetzt ⇒ keine Relay-Prägung, degradierte Messung, nichts blockiert (domains/spf.ts). | — |
MTA_IP_POOLS | Kommagetrennte Liste der kanonischen IP-Pool-Adressen, aus denen der Return-Path-SPF erzeugt wird (ip4: für IPv4 und ip6: für IPv6). Ungültige Token werden abgelehnt. | — |
SNDS_DATA_FEED_URLS | Durch Kommas oder Leerraum getrennte Feed-URLs des Automated Data Access von Microsoft SNDS (nur https), eine je registriertem IP-Bereich. Werden alle sechs Stunden abgefragt und in Bänder von Beschwerden je IP und Tag, Filterergebnisse und Spamtrap-Treffer überführt (delivery/sndsPoll.ts). Jede URL ist eine Bearer-Berechtigung für Ihre SNDS-Daten — halten Sie sie geheim. Rein additiv: Nicht gesetzt ist eine unterstützte Konfiguration; die Microsoft-Rampe stützt sich dann auf die Ergebnisse der eigenen Sendungen, mit doppelter Verweildauer und einer um eine Phase niedrigeren Obergrenze, und nichts erzeugt Fehler oder Nachfragen. Ist MTA_IP_POOLS gesetzt, wirkt es als Allowlist, sodass Feed-Zeilen für Adressen, die Ihnen nicht gehören, verworfen werden. | — |
OUTBOUND_DKIM_DOMAIN | Die DKIM-d=-Domain, mit der der AKTIVE Transport signiert, wenn es nicht die From-Domain der jeweiligen Nachricht ist. Die eingebaute MTA signiert je From-Domain (Variable ungesetzt lassen); setzen Sie hier die Signierdomain Ihres Relays (z. B. sendgrid.net), damit der Guard für die ausgehende DMARC-Ausrichtung warnen kann, wenn die Signatur eines Relays nicht zu Ihren Sendedomains passt (lib/outboundAlignment.ts). | — |
MTA_DMARC_RUA | Reporting-URI für DMARC-Aggregatberichte (rua), die im generierten _dmarc-Eintrag ausgegeben wird, z. B. mailto:dmarc-reports@yourdomain.com. Ist die Variable nicht gesetzt, trägt der Eintrag kein rua=-Tag — Owlat richtet kein kundenspezifisches Postfach dmarc@<domain> ein, sodass Berichte sonst ungelesen blieben (domains/dmarc.ts). | — |
MTA_TLSRPT_RUA | Ziel für SMTP TLS Reporting (rua), das im generierten TXT-Eintrag _smtp._tls ausgegeben wird (v=TLSRPTv1; rua=…, RFC 8460 §3), z. B. mailto:tls-reports@yourdomain.com oder https://yourdomain.com/tlsrpt. Ermöglicht es Empfängern, Fehler bei der TLS-Aushandlung bei der Zustellung an Ihre Domain zu melden. Ist die Variable nicht gesetzt, entfällt der Eintrag _smtp._tls (domains/tlsRpt.ts). | — |
MTA_BIMI_LOGO_URL | HTTPS-URL Ihres Markenlogos im Format SVG Tiny PS, ausgegeben als l=-Tag des BIMI-Eintrags, den der Domain-Assistent ANBIETET, sobald DMARC einer Sendedomain auf p=quarantine oder strenger steht (domains/bimi.ts). Nicht gesetzt ⇒ der Assistent erklärt BIMI und die VMC-Anforderung und generiert keinen Eintrag; es ist nie ein Blocker, keine Warnung und keine Setup-Mahnung. Ein Wert, der keine schlichte https://-URL ist (oder der Leerraum oder ; enthält), wird abgelehnt und auf dem Bildschirm benannt, statt veröffentlicht zu werden. | — |
MTA_BIMI_VMC_URL | HTTPS-URL des PEM Ihres Verified Mark Certificate, ausgegeben als a=-Tag des BIMI-Eintrags. Gmail und Apple Mail zeigen ein BIMI-Logo nur mit VMC; andere Empfänger zeigen es allein aufgrund des Eintrags. Gleiche Validierung und gleiche Optionalität wie bei MTA_BIMI_LOGO_URL. | — |
MTA_BIMI_SELECTOR | Selektor-Label für den Host des BIMI-Eintrags (<selector>._bimi.<domain>). Ein Wert, der kein einzelnes DNS-Label ist, fällt auf den Standard zurück. | default |
OUTBOUND_TLS_MODE | Ausgehende TLS-Haltung für die direkte MX-Zustellung der eingebauten MTA: opportunistic (verschlüsseln, wenn angeboten, nie bei fehlendem/ungültigem TLS bouncen — der Standard, Byte für Byte identisch mit dem bisherigen Verhalten), require (STARTTLS-Upgrade verpflichtend) oder require-verified (TLS und ein gültiges Zertifikat verpflichtend — kann E-Mails an Empfänger mit defektem TLS bouncen). Wird vom Transport-Editor unter „Zustellung“ geschrieben und ihm über delivery/status.ts:getStatus schreibgeschützt angezeigt; die MTA liest den Wert aus ihrer eigenen Konfiguration (apps/mta/src/config.ts). | opportunistic |
RATE_LIMIT_TRUSTED_PROXY | Welchem Forwarded-Header beim Rate Limiting je IP an öffentlichen Endpunkten vertraut wird: cloudflare (CF-Connecting-IP), xforwarded / xforwarded:<hops> (X-Forwarded-For) oder xrealip (X-Real-IP). Sicherheitsrelevant — lassen Sie den Wert ungesetzt, sofern das Convex-Backend nicht hinter einem vertrauenswürdigen Proxy steht. Ist er nicht gesetzt, wird Forwarded-Headern NICHT vertraut, und alle öffentlichen Aufrufer teilen sich einen Rate-Limit-Bucket, sodass ein gefälschter Header keine Buckets vervielfachen kann (publicRateLimit.getClientIp). | nicht gesetzt (Headern wird nicht vertraut) |
GITHUB_WEBHOOK_SECRET | HMAC-Geheimnis, das GitHub-Webhooks zum Mergen von PRs für die Code-Work-Funktion validiert (webhooks/githubHttp.ts). | — |
OPENROUTER_API_KEY | Alternativer API-Schlüssel für den LLM-Provider OpenRouter; wird vom einheitlichen LLM-Resolver (lib/llmProvider.ts) nach LLM_API_KEY und vor OPENAI_API_KEY verwendet. | — |
LLM_COMPLEXITY_ROUTING | Auf 1 gesetzt, verteilt diese Variable jede LLM-Anfrage anhand der geschätzten Komplexität zwischen dem schnellen und dem leistungsfähigen Modell, statt immer eine Stufe zu verwenden (lib/llmProvider.ts). | nicht gesetzt (aus) |
CALENDAR_FREEBUSY_ICS_URL | Schreibgeschützte Frei/Belegt-Quelle für Terminvorschläge in Antworten: eine iCalendar-Abonnement-URL (.ics), die das Deployment serverseitig abruft, um die offenen Zeitfenster der Inhaberin oder des Inhabers zu berechnen und bei Terminabsicht in Antworten einzufügen (mail/aiScheduling.ts, mail/availability.ts). Wird innerhalb des Deployments abgerufen, um die Datenschutzhaltung zu wahren. Fail-soft: nicht gesetzt, nicht erreichbar oder nicht parsebar → exakt das heutige Verhalten, das allein auf Formulierungen der absendenden Person beruht. | nicht gesetzt (Funktion aus) |
CALENDAR_TIMEZONE | IANA-Zeitzone (z. B. Europe/Berlin), in der die offenen Frei/Belegt-Zeitfenster in Terminantworten dargestellt werden. | UTC |
Dieses OSS-Repository enthält keine Variablen für Stripe-Abrechnung, Tarifverwaltung oder Provisionierung — diese sind zusammen mit der Nest-Control-Plane in das separate Repository der verwalteten Cloud gewandert. Die einzige nur für Hosted gedachte Variable, die hier überlebt, ist OWLAT_HOSTED_MODE (ein .env-Flag, das das Setup-CLI schreibt und das in diesem OSS-Repository wirkungslos ist) sowie das optionale Analytics-Ziel CONTROL_PLANE_URL; Self-Hoster lassen beide ungesetzt. Die folgenden Abschnitte beschreiben allgemeine Konfiguration, die für jedes Deployment gilt.
Wo Variablen gesetzt werden
Convex-Backend (alle process.env-Referenzen in apps/api/):
npx convex env set VAR_NAME value
Oder setzen Sie sie im Convex-Dashboard unter „Settings > Environment Variables“ Ihres Deployments.
Nuxt-Frontend (apps/web/.env):
NUXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud
NUXT_PUBLIC_CONVEX_SITE_URL=https://your-deployment.convex.site
NUXT_PUBLIC_SITE_URL=http://localhost:3000
E-Mail-Versand
Providerauswahl
Welche Sendetransporte existieren, was jeder von ihnen benötigt und was er kann, wird genau einmal deklariert, in packages/shared/src/sendProviderCatalog.ts (ADR-0055). Dieser Abschnitt gibt diese Deklaration wieder und nichts sonst: apps/docs/__tests__/providerCatalogDocs.test.ts liest beides und schlägt fehl, wenn ein Kind, eine erforderliche Variable — oder ein ganzer Provider — hier fehlt. Setzen Sie EMAIL_PROVIDER auf einen Wert aus der ersten Spalte, um jede Sendung über dieses Kind zu leiten; eine Provider-Route je Organisation überschreibt das pro Nachrichtentyp. Es gibt keinen impliziten Standard: Die Variable ungesetzt zu lassen bedeutet nicht „die MTA verwenden“ — die Auflösung ist fail-closed, sodass eine Instanz ohne Routenkonfiguration und ohne Wert hier ihre Sendungen verweigert, statt an eine Phantom-MTA zu übergeben.
EMAIL_PROVIDER | Provider | Erforderlich | Optional | Einrichtung |
|---|---|---|---|---|
mta | Owlat MTA — der eingebaute Sender; damit wird .env.selfhost.example ausgeliefert | MTA_API_URL, MTA_API_KEY | OUTBOUND_TLS_MODE, MTA_WEBHOOK_SECRET | Custom MTA |
ses | Amazon SES | AWS_SES_REGION, AWS_SES_ACCESS_KEY_ID, AWS_SES_SECRET_ACCESS_KEY | SES_CONFIGURATION_SET, SES_SNS_TOPIC_ARN | AWS SES |
resend | Resend | RESEND_API_KEY | RESEND_WEBHOOK_SECRET | Resend |
smtp | SMTP-Relay — Mailgun, Postmark, SendGrid, Brevo oder Ihr eigener Submission-Host | SMTP_RELAY_HOST, SMTP_RELAY_USERNAME, SMTP_RELAY_PASSWORD | SMTP_RELAY_PORT, SMTP_RELAY_SECURE | Generic SMTP relay |
mandrill | Mailchimp Transactional (Mandrill) | MANDRILL_API_KEY | MANDRILL_WEBHOOK_KEY, MANDRILL_SUBACCOUNT, MANDRILL_IP_POOL | Mailchimp Transactional (Mandrill) |
emailit | Emailit | EMAILIT_API_KEY | EMAILIT_WEBHOOK_SECRET | Emailit |
npx convex env set EMAIL_PROVIDER mandrill # or any other value from the table above
Erforderlich ist das Vorhandensein-Gate, das der Rest des Systems liest: Solange nicht jede Variable in dieser Zelle gesetzt ist, gilt das Kind als nicht konfiguriert — es kann nicht angesteuert werden und kommt auch nicht als Fallback-Relay für die Zustellbarkeit infrage. Optionale Variablen verfeinern einen bereits funktionierenden Transport (ein Signierschlüssel für Feedback, eine TLS-Untergrenze, ein dedizierter IP-Pool), sodass ein Convex-Deployment, das nie eine davon setzt, dennoch versendet.
Beide Spalten beschreiben die Convex-Seite, die einzige Seite, von der der Katalog weiß. Ein selbst betriebener Dienst kann darüber hinaus einen eigenen Vertrag haben: MTA_WEBHOOK_SECRET ist für das obige Gate optional und für apps/mta verpflichtend, dessen loadConfig() ohne den Wert den Start verweigert — setzen Sie ihn in einem selbst gehosteten Stack also dort, wo es die eigene Referenz der MTA weiter unten verlangt.
Die optionale Spalte darf mehr nennen als der Katalog, nie weniger, und bei SES stehen beide Fälle nebeneinander. SES_CONFIGURATION_SET wird vom Transport bei jeder Sendung gelesen: Der Adapter prägt es dem SendEmail-/SendRawEmail-Befehl auf, damit die Ereignisveröffentlichung von SES das entstehende Feedback zuordnen kann — deshalb deklariert der Katalog es als optional (eine Sendung ohne den Wert funktioniert; verloren geht nur die Zuordnung, und ein späteres Setzen wirkt nur auf spätere Sendungen, nie rückwirkend). SES_SNS_TOPIC_ARN wird ausschließlich vom Feedback-Verifizierer gelesen (webhooks/adapters/ses.ts) — der Sendepfad sieht es nie an, und ein Signierschlüssel ist es auch nicht, da SNS mit einem Zertifikat signiert —, weshalb kein Katalogfeld es beschreibt und diese Referenz der einzige Ort ist, an dem es festgehalten wird. Keine der beiden Variablen entscheidet darüber, ob SES senden kann, weshalb keine im Vorhandensein-Gate steht. Ein mitgelieferter Plugin-Transport deklariert seine eigenen Variablen stattdessen in seinem Contribution — sie tragen das Präfix PLUGIN_, erreichen lib/env.ts nie und werden daher in der README des Plugins dokumentiert, nicht hier.
AWS SES
| Variable | Beschreibung |
|---|---|
AWS_SES_REGION | AWS-Region für SES (z. B. eu-west-1, us-east-1). Erforderlich. |
AWS_SES_ACCESS_KEY_ID | IAM-Access-Key-ID mit SES-Berechtigungen. Erforderlich. |
AWS_SES_SECRET_ACCESS_KEY | Geheimer IAM-Access-Key. Erforderlich. |
SES_CONFIGURATION_SET | Optional. Name eines SES Configuration Set, das auf jede Sendung angewendet wird, damit dessen Ereignisveröffentlichung Bounce-, Beschwerde- und Zustellfeedback der ursprünglichen Nachricht zuordnet. Empfohlen, wenn Sie den unten beschriebenen Feedback Loop aktivieren. |
SES_SNS_TOPIC_ARN | Erforderlich, um den unten beschriebenen Feedback Loop zu aktivieren. Der exakte ARN des SNS-Topics, das SES-Feedback an /webhooks/ses zustellt. Eine gültige SNS-Signatur belegt nur, dass die Nachricht von AWS stammt, nicht aus Ihrem Topic — deshalb weist Owlat Feedback aus jedem anderen Topic ab und hält den Endpunkt geschlossen, bis dieser Wert gesetzt ist. |
Einrichtungsschritte
- Legen Sie in AWS einen IAM-Benutzer mit programmatischem Zugriff und der Policy
AmazonSESFullAccessan (oder mit einer eingeschränkten Policy, dieses:SendEmailundses:SendRawEmailerlaubt). - Verifizieren Sie Ihre Sendedomain in der SES-Konsole. SES verlangt die Domain-Verifizierung, bevor Sie E-Mails senden können.
- Beantragen Sie den Produktionszugang, falls sich Ihr SES-Konto im Sandbox-Modus befindet. Der Sandbox-Modus erlaubt den Versand ausschließlich an verifizierte Adressen.
- Setzen Sie die Umgebungsvariablen:
npx convex env set EMAIL_PROVIDER ses npx convex env set AWS_SES_REGION eu-west-1 npx convex env set AWS_SES_ACCESS_KEY_ID AKIA... npx convex env set AWS_SES_SECRET_ACCESS_KEY ... - (Empfohlen) Aktivieren Sie den Feedback Loop für Bounces und Beschwerden. Ohne ihn
nimmt SES Ihre E-Mails an, teilt Owlat aber nie mit, wenn eine Nachricht hart bounct oder
als Spam markiert wird; diese Adressen werden dann nicht unterdrückt und Ihre
Absenderreputation verfällt still und leise. Owlat empfängt SES-Feedback über ein
Amazon-SNS-Topic:
- Legen Sie ein SNS-Topic an (z. B.
owlat-ses-feedback) und fügen Sie ein HTTPS- Abonnement hinzu, das aufhttps://<your-convex-site-url>/webhooks/seszeigt. Owlat bestätigt das Abonnement automatisch (es prüft die Signatur der SNS-Nachricht und ruft anschließend dieSubscribeURLauf). - Setzen Sie
SES_SNS_TOPIC_ARNauf den ARN dieses Topics, damit Owlat Feedback nur aus Ihrem Topic akzeptiert (bis der Wert gesetzt ist, bleibt der Endpunkt geschlossen):npx convex env set SES_SNS_TOPIC_ARN arn:aws:sns:eu-west-1:123456789012:owlat-ses-feedback - Legen Sie in der SES-Konsole ein Configuration Set an, fügen Sie ein Event
Destination hinzu, das die Ereignisse
Bounce,ComplaintundDeliveryan dieses SNS-Topic veröffentlicht, und setzen SieSES_CONFIGURATION_SETauf dessen Namen, damit jede Sendung zugeordnet wird:npx convex env set SES_CONFIGURATION_SET owlat-ses - Die Zustellungsseite (Einstellungen → Zustellung) zeigt eine Live-Zeile „zuletzt empfangenes Ereignis“, an der Sie erkennen, dass Feedback eintrifft.
Jede SNS-Anfrage wird fail-closed signaturgeprüft: IhreSigningCertURList auf einen Hostsns.*.amazonaws.comfestgelegt, ihrTimestampmuss aktuell sein und ihrTopicArnmussSES_SNS_TOPIC_ARNentsprechen, sodass gefälschtes oder erneut eingespieltes Feedback abgewiesen wird. - Legen Sie ein SNS-Topic an (z. B.
Resend
| Variable | Beschreibung |
|---|---|
RESEND_API_KEY | Resend-API-Schlüssel. Bei Verwendung von Resend erforderlich. |
RESEND_WEBHOOK_SECRET | Signiergeheimnis für Webhooks (Format: whsec_<base64>). Für die Verfolgung von Zustellereignissen erforderlich. |
Einrichtungsschritte
- Legen Sie ein Resend-Konto auf resend.com an und fügen Sie Ihre Sendedomain hinzu.
- Erzeugen Sie einen API-Schlüssel im Resend-Dashboard.
- (Optional) Richten Sie Webhooks für die Zustellverfolgung ein:
- Legen Sie in Resend einen Webhook an, der auf den Webhook-Endpunkt Ihrer Convex-Site-URL zeigt
- Kopieren Sie das Signiergeheimnis des Webhooks
- Setzen Sie die Umgebungsvariablen:
npx convex env set EMAIL_PROVIDER resend npx convex env set RESEND_API_KEY re_... npx convex env set RESEND_WEBHOOK_SECRET whsec_...
Emailit
| Variable | Beschreibung |
|---|---|
EMAILIT_API_KEY | Bearer-Token für die Send- und Setup-Probe-APIs von Emailit v2. Bei Verwendung von Emailit erforderlich. |
EMAILIT_WEBHOOK_SECRET | Vollständiges Signiergeheimnis whsec_… für POST /webhooks/emailit. Für verifiziertes Zustellfeedback erforderlich. |
Setzen Sie EMAIL_PROVIDER=emailit und EMAILIT_API_KEY und legen Sie dann einen Emailit-Webhook an, der auf <CONVEX_SITE_URL>/webhooks/emailit zeigt. Aktivieren Sie die E-Mail-Ereignisse accepted, attempted, delivered, bounced, complained, failed, rejected und suppressed. Owlat prüft X-Emailit-Signature als HMAC-SHA256 über <X-Emailit-Timestamp>.<raw body> mit einer Frischegrenze von fünf Minuten. Das Öffnungs- und Klick-Tracking des Providers bleibt bei Sendungen deaktiviert, weil Owlats First-Party-Tracking maßgeblich bleibt.
npx convex env set EMAIL_PROVIDER emailit
npx convex env set EMAILIT_API_KEY em_...
npx convex env set EMAILIT_WEBHOOK_SECRET whsec_...
Generisches SMTP-Relay
Wenn Sie bereits einen SMTP-Submission-Host haben — Mailgun, Postmark, SendGrid, Brevo oder ein selbst betriebenes Relay —, setzen Sie EMAIL_PROVIDER=smtp und richten Owlat darauf aus. Es gibt keinen API-Adapter je Provider: Jedes Relay, das SMTP spricht, funktioniert.
| Variable | Beschreibung |
|---|---|
SMTP_RELAY_HOST | Hostname des Relays (z. B. smtp.mailgun.org). Bei Verwendung eines SMTP-Relays erforderlich. |
SMTP_RELAY_PORT | Submission-Port. Optional — Standard ist 587 (STARTTLS). Verwenden Sie 465 für implizites TLS. |
SMTP_RELAY_SECURE | true für eine Verbindung mit implizitem TLS (Port 465); nicht gesetzt bzw. false verbindet und aktualisiert über STARTTLS (Port 587). Optional. |
SMTP_RELAY_USERNAME | Benutzername für die SMTP-Authentifizierung. Bei Verwendung eines SMTP-Relays erforderlich. |
SMTP_RELAY_PASSWORD | Passwort für die SMTP-Authentifizierung. Bei Verwendung eines SMTP-Relays erforderlich. |
Bei einem Relay gehören die sendenden IPs und die DKIM-Signierung dem Relay-Provider — konfigurieren Sie SPF und DKIM für Ihre From-Domain im Dashboard des Relays, nicht über das DNS-Bündel der eingebauten MTA.
Mailchimp Transactional (Mandrill)
Setzen Sie EMAIL_PROVIDER=mandrill, um über ein bestehendes Mailchimp-Transactional-Konto zu senden. Das ist der Migrationsarm: Ein Team, das von Mailchimp kommt, behält am ersten Tag seine bisherige Zustellbarkeit, und Owlats Ramp-Controller verschiebt den Traffic anschließend Zelle für Zelle auf die eingebaute MTA, so wie es die Messungen zulassen.
| Variable | Beschreibung |
|---|---|
MANDRILL_API_KEY | Mandrill-API-Schlüssel (Settings → API keys). Bei Verwendung von Mandrill erforderlich. |
MANDRILL_WEBHOOK_KEY | Signierschlüssel je Webhook, der nach dem Anlegen des Webhooks angezeigt wird. Für die Verfolgung von Zustell- und Bounce-Ereignissen erforderlich. |
MANDRILL_SUBACCOUNT | Subaccount, der Owlats Traffic — und dessen Reputation — innerhalb eines gemeinsam genutzten Mandrill-Kontos isoliert. Optional. |
MANDRILL_IP_POOL | Standardname des Pools dedizierter IPs. Der eigene IP-Pool einer Provider-Route überschreibt ihn je Sendung. Optional. |
Owlat baut die gesamte MIME-Nachricht selbst zusammen und schickt sie an Mandrills messages/send-raw, wobei Mandrills Öffnungs- und Klick-Tracking, Link-Rewriting und automatische Textgenerierung ausdrücklich aus sind. Das Tracking bleibt First Party, sodass beide Sendearme mit identischer Instrumentierung gemessen werden — aktivieren Sie am Webhook send, deferral, hard_bounce, soft_bounce, spam, unsub und reject, aber nicht open/click.
Legen Sie den Webhook unter Mailchimp Transactional → Settings → Webhooks an und richten Sie ihn auf <CONVEX_SITE_URL>/webhooks/mandrill. Mandrill zeigt den Signierschlüssel einmalig an, direkt nach dem Speichern — dieser Wert ist MANDRILL_WEBHOOK_KEY. Bis er gesetzt ist, weist Owlat jeden übermittelten Batch ab, statt einem unsignierten zu vertrauen; der Versand wirkt dann gesund, während Bounces, Beschwerden und Treffer der Reject-Liste stillschweigend nie eintreffen. Unter Zustellung → Provider sehen Sie die exakte URL, die Ereignisliste und ob der Schlüssel vorhanden ist. Nur MANDRILL_API_KEY wird vom Transport-Editor in der App geschrieben; die anderen drei sind ausschließlich .env-seitig, sodass das Rotieren des Sendeschlüssels niemals einen funktionierenden Feedback Loop deaktivieren kann.
Zwei Transporte desselben Kinds
Jedes Transport-Kind oben erhält kostenlos eine Standardinstanz, deren Id das Kind selbst ist (mta, ses, resend, smtp, mandrill, emailit) und die die unsuffigierten Variablen liest. Deklarieren Sie benannte Instanzen, wenn Sie zwei Konfigurationen desselben Kinds nebeneinander betreiben wollen — etwa um ein warmes Fallback-Relay zu behalten, während Sie ein zweites erproben.
| Variable | Beschreibung |
|---|---|
SEND_TRANSPORT_INSTANCES | Kommagetrennte Liste zusätzlicher Transportinstanzen, jeweils <kind>#<instanceKey> (z. B. smtp#backup,resend#trial). Instanzschlüssel sind kleingeschrieben [a-z0-9][a-z0-9_-]{0,31}. Optional — nicht gesetzt bedeutet genau ein Transport je Kind. |
Eine benannte Instanz liest die Variablen ihres Kinds mit dem Suffix __<INSTANCEKEY>, sodass smtp#backup die Werte SMTP_RELAY_HOST__BACKUP, SMTP_RELAY_USERNAME__BACKUP und SMTP_RELAY_PASSWORD__BACKUP liest:
npx convex env set SEND_TRANSPORT_INSTANCES smtp#backup
npx convex env set SMTP_RELAY_HOST__BACKUP smtp.postmarkapp.com
npx convex env set SMTP_RELAY_USERNAME__BACKUP ...
npx convex env set SMTP_RELAY_PASSWORD__BACKUP ...
Entfernen Sie eine Instanz aus der Liste oder entfernen Sie deren Variablen, scheitern Sendungen an diese Transport-Id fail-closed — sie fallen nie stillschweigend auf die Zugangsdaten eines anderen Transports zurück. Fehlerhafte Einträge werden ignoriert, statt den Dispatch abstürzen zu lassen; dasselbe gilt für einen zweiten Eintrag, dessen Schlüssel dasselbe Variablensuffix ergibt wie ein früherer (a-b und a_b ergeben beide __A_B). Auch ein von einem Plugin beigesteuerter Transport kann benannte Instanzen haben, zu denselben Bedingungen, sofern sein Contribution eigene Konfigurationsvariablen deklariert — diese tragen das Präfix PLUGIN_ und lesen dasselbe Suffix __<INSTANCEKEY>. Ein Transport, der keine deklariert, liest die deployment-weiten Variablen des Plugins, die kein Suffix erreicht; eine Instanz davon zu deklarieren wird deshalb abgelehnt, statt stillschweigend mit den Zugangsdaten der Standardinstanz zu senden.
Einrichtungsschritte
- Legen Sie im Dashboard Ihres Relay-Providers SMTP-Zugangsdaten an (einen domain- oder kontobezogenen SMTP-Benutzernamen samt Passwort).
- Verifizieren Sie Ihre Sendedomain beim Relay (veröffentlichen Sie dessen SPF-/DKIM-Einträge), damit Ihre E-Mails authentifiziert werden.
- Setzen Sie die Umgebungsvariablen:
npx convex env set EMAIL_PROVIDER smtp npx convex env set SMTP_RELAY_HOST smtp.mailgun.org npx convex env set SMTP_RELAY_PORT 587 npx convex env set SMTP_RELAY_USERNAME postmaster@mg.example.com npx convex env set SMTP_RELAY_PASSWORD ...
Eigene MTA
Bei Verwendung der eigenen MTA (EMAIL_PROVIDER=mta) verbindet sich das Convex-Backend über HTTP mit dem MTA-Dienst. Alle Architekturdetails finden Sie in der Dokumentation zum MTA System.
| Variable | Beschreibung |
|---|---|
MTA_API_URL | URL des MTA-Dienstes (z. B. http://mta.internal:3100). Bei Verwendung der MTA erforderlich. |
MTA_API_KEY | Gemeinsamer API-Schlüssel für die MTA-Authentifizierung (Bearer-Token). Bei Verwendung der MTA erforderlich. |
MTA_WEBHOOK_SECRET | Gemeinsames HMAC-Geheimnis. Authentifiziert Zustellereignis-Callbacks von der MTA an Convex und signiert — wenn das Flag postbox aktiv ist — die Prüfungen der SMTP-Submission-Zugangsdaten der MTA gegen den Endpunkt /webhooks/mta-verify-credential (apps/mta/src/auth/postboxAuth.ts, apps/api/convex/mail/authHttp.ts). Setzen Sie es auf beiden Seiten. Es liegt außerhalb des Vorhandensein-Gates auf Convex-Seite — der Katalog deklariert es neben OUTBOUND_TLS_MODE, es entscheidet also nicht darüber, ob mta als konfiguriert gilt —, wird aber vom MTA-Dienst selbst beim Start benötigt (apps/mta/src/config.ts liest es über requiredEnv, sodass der Container bei einem nicht gesetzten oder leeren Wert beendet wird), ist für den Empfang von Zustellereignis-Callbacks erforderlich und immer dann erforderlich, wenn das Flag postbox aktiv ist. |
Wenn ein Desktop-Mailclient (Apple Mail, Thunderbird, …) E-Mails über SMTP einliefert, verifiziert die MTA das Paar (mailbox-address, app-password), indem sie eine Anfrage (mit MTA_WEBHOOK_SECRET) HMAC-signiert an den Convex-Endpunkt /webhooks/mta-verify-credential schickt. Das ist die SMTP-Submission-Prüfung der MTA — sie unterscheidet sich vom Auth-Pfad des IMAP-Servers, der CONVEX_ADMIN_KEY verwendet, um mail/appPasswords:verify direkt aufzurufen. Siehe Postbox Architecture.
Einrichtungsschritte
- Deployen Sie den MTA-Dienst aus
apps/mta/(Konfigurationsdetails in der MTA-System-Dokumentation). - Setzen Sie die Umgebungsvariablen im Convex-Dashboard:
npx convex env set EMAIL_PROVIDER mta npx convex env set MTA_API_URL http://mta.internal:3100 npx convex env set MTA_API_KEY your-shared-api-key npx convex env set MTA_WEBHOOK_SECRET your-webhook-secret
Allgemeine E-Mail-Konfiguration
Diese Variablen gelten unabhängig davon, welchen Provider Sie verwenden:
| Variable | Beschreibung | Standard |
|---|---|---|
DEFAULT_FROM_EMAIL | Standard-Absenderadresse für transaktionale E-Mails | noreply@example.com |
DEFAULT_FROM_NAME | Standard-Anzeigename des Absenders | Owlat |
DEFAULT_FROM_DOMAIN | Domain für System-E-Mails (z. B. Einladungs-E-Mails). Wird noreply@ vorangestellt. | mail.owlat.app |
CONVEX_SITE_URL | Ihre Convex-Site-URL. Wird für Tracking-Pixel und Abmeldelinks in Kampagnen-E-Mails verwendet. | — |
UNSUBSCRIBE_SECRET | Geheimer Schlüssel zum Erzeugen HMAC-signierter Abmelde-Token. Erforderlich. | — |
E-Mail-Sicherheit
Optionale Umgebungsvariablen für die Prüfung von E-Mail-Inhalten und Anhängen. Details zur Prüf-Pipeline finden Sie in der Dokumentation zur E-Mail-Sicherheit.
Variablen
Im Convex-Dashboard setzen:
| Variable | Beschreibung |
|---|---|
GOOGLE_SAFE_BROWSING_API_KEY | Schlüssel für die Google Safe Browsing API v4 zur Prüfung der URL-Reputation. Kostenlose Stufe: 10.000 Anfragen/Tag. |
MTA_INTERNAL_URL | Interne MTA-URL für die Prüfung von Anhängen (z. B. http://mta.internal:3100). Für die ClamAV-Integration erforderlich. |
In der MTA-Umgebung setzen:
| Variable | Standard | Beschreibung |
|---|---|---|
CLAMAV_HOST | clamav | Hostname des ClamAV-Daemons (entspricht dem Namen des clamav-Sidecar-Dienstes; docker-compose.yml verdrahtet ihn fest) |
CLAMAV_PORT | 3310 | Port des ClamAV-Daemons |
Einrichtungsschritte
- (Optional) Prüfung der URL-Reputation aktivieren — holen Sie sich einen Google-Safe-Browsing-API-Schlüssel aus der Google Cloud Console:
npx convex env set GOOGLE_SAFE_BROWSING_API_KEY AIza... - (Optional) ClamAV-Malware-Prüfung aktivieren — deployen Sie ClamAV neben der MTA (siehe MTA System > ClamAV Sidecar) und setzen Sie die interne URL:
npx convex env set MTA_INTERNAL_URL http://mta.internal:3100
Die Inhaltsprüfung (Spam-Schlüsselwörter, Phishing-URLs, Homoglyphen) und die Dateitypvalidierung (Magic Bytes, doppelte Endungen) funktionieren ohne zusätzliche Konfiguration sofort. Nur URL-Reputation und ClamAV benötigen Umgebungsvariablen.
Analytics (PostHog)
Owlat integriert PostHog für Produktanalytik und Fehlererfassung. Die Integration ist optional — alles funktioniert auch ohne sie.
Variablen
Convex-Dashboard:
| Variable | Beschreibung |
|---|---|
POSTHOG_API_KEY | Projekt-API-Schlüssel von PostHog (beginnt mit phc_). Erforderlich, um serverseitiges Tracking zu aktivieren. |
POSTHOG_HOST | URL der PostHog-Instanz. Standard ist https://eu.i.posthog.com (EU-Cloud). |
Nuxt-Frontend (apps/web/.env):
| Variable | Beschreibung |
|---|---|
NUXT_PUBLIC_POSTHOG_API_KEY | Projekt-API-Schlüssel von PostHog. Erforderlich, um clientseitiges Tracking zu aktivieren. |
NUXT_PUBLIC_POSTHOG_HOST | URL der PostHog-Instanz. Standard ist https://eu.i.posthog.com. |
Einrichtungsschritte
- Legen Sie ein PostHog-Projekt auf posthog.com an und kopieren Sie den Projekt-API-Schlüssel.
- Fügen Sie den Gruppentyp
organizationin PostHog hinzu: Gehen Sie zu Settings → Groups und legen Sie einen Gruppentyp namensorganizationan. Damit wird Analytik auf Organisationsebene möglich. - Setzen Sie die Umgebungsvariablen:
# Convex (server-side events) npx convex env set POSTHOG_API_KEY phc_... npx convex env set POSTHOG_HOST https://eu.i.posthog.com # apps/web/.env (client-side events) NUXT_PUBLIC_POSTHOG_API_KEY=phc_... NUXT_PUBLIC_POSTHOG_HOST=https://eu.i.posthog.com
Erfasste Ereignisse
Clientseitig (automatisch):
$pageview— SPA-Seitennavigationen$pageleave— Ereignisse beim Verlassen einer Seite$exception— Vue-Fehler und unbehandelte Promise-Rejections- Nutzeridentifikation und Zuordnung zur Organisationsgruppe
Serverseitig (Fire-and-forget aus Mutations):
campaign_created,campaign_sentcontact_createdautomation_created,automation_activated,automation_pausedtopic_created
Alle Serverereignisse enthalten organizationId als Eigenschaft und als PostHog-Gruppe.
LLM-Provider (KI-Funktionen)
Das Flag ai und jedes davon abhängige Flag benötigen einen LLM-Provider. Derselbe Provider treibt Übersetzungen von E-Mail-Templates, den KI-Agenten, die Embeddings des Wissensgraphen und die Dashboard-Generierung an. Den Interface-Vertrag und die Schritte zum Hinzufügen eines neuen Providers finden Sie unter Providers → LLM provider.
Variablen
| Variable | Beschreibung | Standard |
|---|---|---|
LLM_PROVIDER | openai (Standard), openrouter oder ollama. Claude funktioniert nur über openai mit einer OpenAI-kompatiblen LLM_BASE_URL — anthropic ist kein anerkannter Wert. | openai |
LLM_API_KEY | API-Schlüssel für den gewählten Provider. Akzeptierte Fallback-Schlüssel in dieser Reihenfolge: LLM_API_KEY, OPENROUTER_API_KEY, OPENAI_API_KEY. | — |
LLM_MODEL_FAST | Modell-Id für Aufgaben vom Typ classify/extract/guard/summarize | providerabhängig |
LLM_MODEL_CAPABLE | Modell-Id für Entwurfsaufgaben | providerabhängig |
LLM_MODEL | Einzelmodell-Fallback für beide Stufen, wenn LLM_MODEL_FAST/LLM_MODEL_CAPABLE nicht gesetzt sind | — |
LLM_EMBEDDING_MODEL | Modell-Id für Embeddings im Wissensgraphen (Env-Fallback) | providerabhängig |
LLM_BASE_URL | Override für OpenAI-kompatible Endpunkte (Ollama, vLLM, LM Studio) | — |
LOCAL_EMBEDDING_BASE_URL | Basis-URL eines lokalen, OpenAI-kompatiblen /embeddings-Sidecars (z. B. Ollama). Die Embedding-Ebene ist standardmäßig lokal, damit das Retrieval mit jedem Sprachprovider funktioniert. | Adapterstandard (http://localhost:11434/v1) |
LOCAL_EMBEDDING_MODEL | Id des lokalen Embedding-Modells (z. B. nomic-embed-text). Seine native Vektorbreite muss zum Vektorindex passen (EMBEDDING_DIMENSIONS), sonst weist der Dimensions-Guard Schreibvorgänge ab. | nomic-embed-text |
Einrichtung
npx convex env set LLM_PROVIDER openai
npx convex env set LLM_API_KEY sk-...
# Override defaults if you want a specific model:
npx convex env set LLM_MODEL_FAST gpt-4o-mini
npx convex env set LLM_MODEL_CAPABLE gpt-4o
Für ein lokales Ollama:
npx convex env set LLM_PROVIDER ollama
npx convex env set LLM_BASE_URL http://host.docker.internal:11434/v1
npx convex env set LLM_MODEL_FAST llama3.1:8b
npx convex env set LLM_MODEL_CAPABLE llama3.1:70b
Benachrichtigungen
Benachrichtigungen werden clientseitig von der Desktop-App abgewickelt; eine
serverseitige Umgebungsvariable für einen Benachrichtigungsprovider gibt es nicht. Das gesamte
Wissens-Retrieval nutzt den eingebauten Vektorindex von Convex (ctx.vectorSearch),
sodass es auch keine Umgebungsvariable für einen Vektorspeicher gibt.
Private E-Mail / IMAP (apps/imap)
Diese Werte liest der IMAP-Server, nicht das Convex-Backend. Nur relevant, wenn das Flag postbox aktiv ist.
| Variable | Beschreibung | Standard |
|---|---|---|
IMAP_PORT | TCP-Port, auf dem gelauscht wird | 993 |
IMAP_LISTEN | Bind-Adresse | 0.0.0.0 |
IMAP_GREETING_HOST | Hostname in der Begrüßung * OK | Hostname des Betriebssystems |
IMAP_TLS_CERT / IMAP_TLS_CERT_FILE | TLS-Zertifikat (Inline-PEM oder Pfad) | — |
IMAP_TLS_KEY / IMAP_TLS_KEY_FILE | Privater TLS-Schlüssel (Inline-PEM oder Pfad) | — |
TLS_CERT_DIR | Fallback-Verzeichnis mit default.crt und default.key | /opt/owlat/certs |
CONVEX_URL | URL des Convex-Deployments (erforderlich) | — |
CONVEX_ADMIN_KEY | Convex-Admin-Schlüssel, mit dem sich der IMAP-Server gegenüber Convex authentifiziert (erforderlich) | — |
LOG_LEVEL | Ausführlichkeit des Logs. Die VPS-Compose-Datei bildet IMAP_LOG_LEVEL darauf ab. | info |
REDIS_URL | Optionale Redis-URL für die Speicherung der Rate Limits. Am ausgelieferten Compose-Dienst nicht gesetzt → Rate Limiting schaltet fail-open. | — |
Der IMAP-Server authentifiziert sich gegenüber Convex mit CONVEX_ADMIN_KEY (er setzt die Admin-Authentifizierung an einem ConvexHttpClient und ruft mail/appPasswords:verify direkt auf — apps/imap/src/convex.ts). Er liest MTA_WEBHOOK_SECRET nicht. Der HMAC-Endpunkt /webhooks/mta-verify-credential ist demgegenüber die Prüfung der SMTP-Submission-Zugangsdaten der MTA (siehe den Abschnitt Custom MTA oben sowie Postbox Architecture).
Authentifizierung
| Variable | Beschreibung | Standard |
|---|---|---|
BETTER_AUTH_SECRET | Geheimer Schlüssel zum Signieren der BetterAuth-Sitzungen. Erforderlich. | — |
SITE_URL | Öffentliche Site-URL für Auth-Weiterleitungen und Callbacks. | http://localhost:3000 |
Setzen Sie BETTER_AUTH_SECRET im Convex-Dashboard. Verwenden Sie eine lange, zufällige Zeichenkette:
npx convex env set BETTER_AUTH_SECRET $(openssl rand -base64 32)
Nuxt-Frontend
Diese gehören in apps/web/.env:
| Variable | Beschreibung |
|---|---|
NUXT_PUBLIC_CONVEX_URL | URL Ihres Convex-Deployments (z. B. https://your-deployment.convex.cloud) |
NUXT_PUBLIC_CONVEX_SITE_URL | Ihre Convex-Site-URL (z. B. https://your-deployment.convex.site). Wird für den Auth-Proxy verwendet. |
NUXT_PUBLIC_SITE_URL | Öffentliche Site-URL. Muss der in Convex gesetzten SITE_URL entsprechen. |
Vollständige Referenz
Tenant-App (apps/api)
| Variable | Wo | Erforderlich | Standard | Zweck |
|---|---|---|---|---|
INSTANCE_SECRET | Convex | Ja | — | HKDF-Wurzel für die Verschlüsselung ruhender Zugangsdaten (lib/credentialCrypto.ts); gemeinsames Geheimnis, das /seed/admin, /seed/demo, /dev/reset absichert |
INSTANCE_SECRET_PREVIOUS | Convex | Nein | — | Vorheriges INSTANCE_SECRET, nur während eines Rotationsfensters gesetzt: Unter der alten Wurzel versiegelte ruhende Geheimnisse lassen sich weiterhin entschlüsseln, während e2ee/lifecycleNode.ts:reSealVault jede Zeile unter dem neuen Geheimnis neu versiegelt. Nach Abschluss der Neuversiegelung entfernen |
SITE_URL | Convex | Ja | http://localhost:3000 | Öffentliche Site-URL für Weiterleitungen |
ADMIN_SITE_URL | Convex | Nein | — | Alternative Site-URL, der für Auth-Weiterleitungen vertraut wird |
ALLOWED_ORIGINS | Convex | Nein | http://localhost:3000 | Kommagetrennte CORS-Allowlist für die Convex-HTTP-API |
OWLAT_DEV_MODE | Convex | Nein | aus | Aktiviert Dev-/Seed-Endpunkte; fail-closed, wenn nicht gesetzt |
EMAIL_PROVIDER | Convex | Nein | — | Instanzweiter E-Mail-Provider (mta, ses, resend, smtp, mandrill oder emailit); kein Standard — nicht gesetzt bedeutet nicht konfiguriert, und Sendungen werden verweigert. Eine Provider-Route je Organisation überschreibt ihn |
AWS_SES_REGION | Convex | Bei SES | — | AWS-Region für SES |
AWS_SES_ACCESS_KEY_ID | Convex | Bei SES | — | AWS-IAM-Access-Key |
AWS_SES_SECRET_ACCESS_KEY | Convex | Bei SES | — | Geheimer AWS-IAM-Schlüssel |
SES_CONFIGURATION_SET | Convex | Nein | — | SES Configuration Set, das für die Feedback-Zuordnung auf jede Sendung angewendet wird |
SES_SNS_TOPIC_ARN | Convex | Bei SES-Feedback | — | ARN des SNS-Topics, das SES-Feedback an /webhooks/ses zustellen darf |
RESEND_API_KEY | Convex | Bei Resend | — | Resend-API-Schlüssel |
RESEND_WEBHOOK_SECRET | Convex | Nein | — | Signiergeheimnis für Resend-Webhooks |
SMTP_RELAY_HOST | Convex | Bei SMTP | — | Hostname des generischen SMTP-Relays |
SMTP_RELAY_PORT | Convex | Nein | 587 | SMTP-Submission-Port (465 für implizites TLS) |
SMTP_RELAY_SECURE | Convex | Nein | false | true für implizites TLS (465); sonst STARTTLS |
SMTP_RELAY_USERNAME | Convex | Bei SMTP | — | Benutzername für die Authentifizierung am SMTP-Relay |
SMTP_RELAY_PASSWORD | Convex | Bei SMTP | — | Passwort für die Authentifizierung am SMTP-Relay |
MANDRILL_API_KEY | Convex | Bei Mandrill | — | API-Schlüssel für Mailchimp Transactional (Mandrill) |
MANDRILL_WEBHOOK_KEY | Convex | Bei Mandrill-Feedback | — | Signierschlüssel je Webhook für /webhooks/mandrill |
EMAILIT_API_KEY | Convex | Bei Emailit-Sendungen | — | Bearer-Token für Emailit v2 |
EMAILIT_WEBHOOK_SECRET | Convex | Bei Emailit-Feedback | — | HMAC-Geheimnis für /webhooks/emailit |
MANDRILL_SUBACCOUNT | Convex | Nein | — | Mandrill-Subaccount, der Owlats Traffic und dessen Reputation isoliert |
MANDRILL_IP_POOL | Convex | Nein | — | Standardmäßiger dedizierter IP-Pool bei Mandrill; der eigene Pool einer Provider-Route überschreibt ihn |
MTA_API_URL | Convex | Bei MTA | — | URL des MTA-Dienstes |
MTA_API_KEY | Convex | Bei MTA | — | Authentifizierungsschlüssel für die MTA-API |
MTA_WEBHOOK_SECRET | Convex | Bei MTA | — | HMAC-Geheimnis für MTA-Zustell-Callbacks und (bei Postbox) die Prüfung der SMTP-Submission-Zugangsdaten der MTA. Liegt außerhalb des Convex-seitigen Sende-Vorhandensein-Gates, doch der mta-Container selbst startet ohne den Wert nicht |
MTA_INTERNAL_URL | Convex | Nein | — | MTA-URL für die Prüfung von Anhängen |
MTA_SPF_INCLUDE | Convex | Nein | — | SPF-include:-Host in den generierten DNS-Einträgen (entfällt, wenn nicht gesetzt) |
SPF_QUALIFIER | Convex | Nein | ~all | Qualifizierer des abschließenden all in generierten SPF-Einträgen (~all/-all/?all/+all) |
MTA_RETURN_PATH_DOMAIN | Convex | Nein | — | VERP-Return-Path-Domain; erzeugt zusammen mit MTA_IP_POOLS einen Return-Path-SPF-Eintrag |
MTA_BOUNCE_VERP_KEY | Convex | Nein | — | VERP-Signierschlüssel (identisch mit BOUNCE_VERP_KEY der MTA); lässt Relay-Sendungen unseren eigenen VERP-Return-Path tragen, sodass relayed Bounces zuordenbar sind |
MTA_RETURN_PATH_RELAY_SPF | Convex | Nein | — | SPF-Terme, die das Relay am Return-Path-Host autorisieren; erforderlich, bevor eine Relay-Sendung unseren VERP-Envelope-Absender trägt |
MTA_IP_POOLS | Convex | Nein | — | Kommagetrennte sendende IPs, aus denen der Return-Path-SPF-Eintrag gebaut wird |
SNDS_DATA_FEED_URLS | Convex | Nein | — | Feed-URLs des Microsoft-SNDS-Automated-Data-Access; rein additives externes Reputationssignal für die Microsoft-Zelle |
OUTBOUND_DKIM_DOMAIN | Convex | Nein | — | DKIM-d=-Domain des aktiven Transports, wenn es nicht die From-Domain ist; treibt den Guard für die ausgehende DMARC-Ausrichtung an (Warnung bei Relay-Fehlausrichtung) |
MTA_DMARC_RUA | Convex | Nein | — | rua=-URI für DMARC-Aggregatberichte im generierten _dmarc-Eintrag (entfällt, wenn nicht gesetzt) |
MTA_TLSRPT_RUA | Convex | Nein | — | TLS-RPT-rua=-Ziel im generierten _smtp._tls-Eintrag (entfällt, wenn nicht gesetzt) |
MTA_BIMI_LOGO_URL | Convex | Nein | — | HTTPS-URL des SVG-Logos im angebotenen BIMI-Eintrag (l=); nicht gesetzt ⇒ kein Eintrag, nie ein Blocker |
MTA_BIMI_VMC_URL | Convex | Nein | — | HTTPS-URL des VMC-PEM im angebotenen BIMI-Eintrag (a=); nur von Gmail/Apple verlangt |
MTA_BIMI_SELECTOR | Convex | Nein | default | Selektor-Label für <selector>._bimi.<domain> |
OUTBOUND_TLS_MODE | MTA + Convex | Nein | opportunistic | Ausgehende TLS-Untergrenze der eingebauten MTA (opportunistic/require/require-verified); dem Transport-Editor schreibgeschützt angezeigt |
MAIL_SYNC_API_URL | Convex | Wenn mail.external aktiv | — | Basis-URL der internen Send-/Test-API des Mail-Sync-Workers |
MAIL_SYNC_API_KEY | Convex | Wenn mail.external aktiv | — | Gemeinsamer Schlüssel, mit dem sich Convex gegenüber dem Mail-Sync-Worker authentifiziert |
TWILIO_AUTH_TOKEN | Convex | Bei SMS-Kanal | — | Validiert Signaturen eingehender Twilio-Webhooks |
META_APP_SECRET | Convex | Bei WhatsApp-/Messenger-Kanal | — | Validiert den HMAC eingehender Meta-Webhooks |
META_VERIFY_TOKEN | Convex | Bei WhatsApp-/Messenger-Kanal | — | Challenge-Token für das Meta-Webhook-Abonnement |
GENERIC_WEBHOOK_SECRET | Convex | Bei generischem Kanal | — | Gemeinsames Geheimnis für den generischen Adapter eingehender Kanäle |
DEFAULT_FROM_EMAIL | Convex | Nein | noreply@example.com | Standard-Absenderadresse |
DEFAULT_FROM_NAME | Convex | Nein | Owlat | Standard-Absendername |
DEFAULT_FROM_DOMAIN | Convex | Nein | mail.owlat.app | Domain für System-E-Mails |
CONVEX_SITE_URL | Convex | Ja | — | Eingebaute Convex-Site-URL (Tracking/Abmeldung) — automatisch aus NUXT_PUBLIC_CONVEX_SITE_URL abgeleitet; nicht per convex env set setzen (wird als EnvVarNameForbidden abgelehnt) |
UNSUBSCRIBE_SECRET | Convex | Ja | — | HMAC-Geheimnis für Abmelde-Token |
BETTER_AUTH_SECRET | Convex | Ja | — | Geheimnis zum Signieren von Sitzungen |
LLM_PROVIDER | Convex | Wenn ai aktiv | openai | LLM-Provider (openai, openrouter, ollama; Claude über openai + OpenAI-kompatible LLM_BASE_URL) |
LLM_API_KEY | Convex | Wenn ai aktiv | — | API-Schlüssel für den gewählten LLM-Provider |
LLM_MODEL_FAST | Convex | Nein | providerabhängig | Modell-Id der schnellen Stufe |
LLM_MODEL_CAPABLE | Convex | Nein | providerabhängig | Modell-Id der leistungsfähigen Stufe |
LLM_MODEL | Convex | Nein | — | Einzelmodell-Fallback für beide Stufen |
LLM_EMBEDDING_MODEL | Convex | Nein | providerabhängig | Modell-Id für Embeddings (Env-Fallback) |
LLM_BASE_URL | Convex | Nein | — | Override für OpenAI-kompatible Endpunkte |
LOCAL_EMBEDDING_BASE_URL | Convex | Nein | http://localhost:11434/v1 | Lokales, OpenAI-kompatibles /embeddings-Sidecar für die standardmäßig lokale Embedding-Ebene |
LOCAL_EMBEDDING_MODEL | Convex | Nein | nomic-embed-text | Id des lokalen Embedding-Modells; seine Breite muss zum Vektorindex passen |
POSTHOG_API_KEY | Convex | Wenn analytics.posthog aktiv | — | PostHog-Projekt-API-Schlüssel (serverseitig) |
POSTHOG_HOST | Convex | Nein | https://eu.i.posthog.com | URL der PostHog-Instanz (serverseitig) |
CONTROL_PLANE_URL | Convex | Nein (nur Hosted) | — | Ziel des Analytics-Reporters für die verwaltete Control Plane |
GOOGLE_SAFE_BROWSING_API_KEY | Convex | Wenn scan.urls aktiv | — | Prüfung der URL-Reputation (Safe-Browsing-API) |
Frontend (apps/web)
| Variable | Wo | Erforderlich | Standard | Zweck |
|---|---|---|---|---|
NUXT_PUBLIC_CONVEX_URL | Nuxt-.env | Ja | — | URL des Convex-Deployments |
NUXT_PUBLIC_CONVEX_SITE_URL | Nuxt-.env | Ja | — | Convex-Site-URL für die Authentifizierung |
NUXT_PUBLIC_SITE_URL | Nuxt-.env | Ja | — | Öffentliche Site-URL |
NUXT_PUBLIC_POSTHOG_API_KEY | Nuxt-.env | Nein | — | PostHog-Projekt-API-Schlüssel (clientseitig) |
NUXT_PUBLIC_POSTHOG_HOST | Nuxt-.env | Nein | https://eu.i.posthog.com | URL der PostHog-Instanz (clientseitig) |
MTA (apps/mta)
| Variable | Wo | Erforderlich | Standard | Zweck |
|---|---|---|---|---|
CLAMAV_HOST | MTA-Env | Nein | clamav | Hostname des ClamAV-Daemons (docker-compose.yml verdrahtet den Sidecar-Namen fest) |
CLAMAV_PORT | MTA-Env | Nein | 3310 | Port des ClamAV-Daemons |
LOG_LEVEL | MTA-Env | Nein | info | Ausführlichkeit des Logs. docker-compose.yml bildet die Host-Variable MTA_LOG_LEVEL darauf ab. |
IMAP-Server (apps/imap)
Wird nur gestartet, wenn das Flag postbox aktiv ist (über das Docker-Compose-Profil personal-mail).
| Variable | Wo | Erforderlich | Standard | Zweck |
|---|---|---|---|---|
IMAP_PORT | IMAP-Env | Nein | 993 | TCP-Port, auf dem gelauscht wird |
IMAP_LISTEN | IMAP-Env | Nein | 0.0.0.0 | Bind-Adresse |
IMAP_GREETING_HOST | IMAP-Env | Nein | Hostname des Betriebssystems | Hostname in der Begrüßung * OK |
IMAP_TLS_CERT / IMAP_TLS_CERT_FILE | IMAP-Env | Nein (TLS aus) | — | TLS-Zertifikat (PEM oder Pfad) |
IMAP_TLS_KEY / IMAP_TLS_KEY_FILE | IMAP-Env | Nein (TLS aus) | — | Privater TLS-Schlüssel (PEM oder Pfad) |
TLS_CERT_DIR | IMAP-Env | Nein | /opt/owlat/certs | Fallback-Verzeichnis für default.crt/default.key |
CONVEX_URL | IMAP-Env | Ja | — | URL des Convex-Deployments |
CONVEX_ADMIN_KEY | IMAP-Env | Ja | — | Convex-Admin-Schlüssel — die einzige Authentifizierung des IMAP-Servers gegenüber Convex (ruft mail/appPasswords:verify direkt auf) |
LOG_LEVEL | IMAP-Env | Nein | info | Ausführlichkeit des Logs. Die VPS-Compose-Datei bildet IMAP_LOG_LEVEL darauf ab. |
REDIS_URL | IMAP-Env | Nein | — | Redis-URL für die Speicherung der Rate Limits. Am ausgelieferten Compose-Dienst nicht gesetzt → Rate Limiting schaltet fail-open. |
Der IMAP-Server liest MTA_WEBHOOK_SECRET nicht. Seine einzige erforderliche Convex-Zugangsberechtigung ist CONVEX_ADMIN_KEY.