Skip to documentation

Self-hosting

SMTP gateway

Expose authenticated submission with trusted TLS.

Configure TLS

Point an unproxied SMTP hostname to your server and open TCP 465 and 587. Provide fullchain.pem and privkey.pem in a restricted directory readable by container UID 1000. Restart after certificate renewal.

Start the profile

dotenv
SMTP_HOST=smtp.example.com
SMTP_CERT_DIR=/absolute/path/to/certificates
bash
docker compose --env-file .env.docker --profile smtp up -d --build smtp

Set SMTP_HOST in Convex too so Settings displays the correct host. Each team must enable SMTP.

Authenticate

Use username opensend and an os_ API key as the password. Port 465 is implicit TLS; port 587 requires STARTTLS. The gateway needs neither AWS credentials nor the deployment admin key. The internal HTTP target is port 3211.

Limits and retries

The MIME limit is 40 MiB; body/header, recipient, JSON, and proxy limits still apply. There are at most 16 clients per listener. AUTH and submission share the team’s 10 requests/second API budget. Opensend-Idempotency-Key maps to HTTP idempotency for 24 hours. No special SMTP tags header is interpreted.

Keep Opensend-Idempotency-Key stable when retrying a message. It must contain 1–256 printable non-space ASCII characters; duplicate or invalid headers return SMTP 554. The gateway removes it from the delivered message. A committed submission response survives crashes and logging failures; matching in-flight submissions receive a temporary conflict. See idempotency keys for replay and reservation timing.