Docs
SMTP submission
PostMTA Hosted runs apps/smtp as an authenticated injection proxy. Lab
default :2525 plaintext; production typically :587 behind a Caddy or
direct TLS endpoint.
Auth transcript
AUTH PLAIN with a smtp_credentials row:
C: EHLO mta.example.com
S: 250-postmta-hosted Hello
S: 250 AUTH PLAIN LOGIN
C: AUTH PLAIN AGFkbWluQGRldgBhZG1pbi1wYXNz (base64(`admin@dev` + \0 + password))
S: 235 2.7.0 Authentication successful
C: MAIL FROM:<ops@verified.example.com>
S: 250 OK
C: RCPT TO:<alice@example.com>
S: 250 OK
C: DATA
S: 354 Send message, end with CRLF.CRLF
... <message body, headers included>
C: .
S: 250 OK queued
C: QUIT
S: 221 Bye
AUTH LOGIN is also accepted (fallback for legacy clients).
What the proxy does
After DATA the proxy (apps/smtp/src/server.ts):
extractRecipientsFromMimewalks the MIME for unique recipients.credits.hold(workspace, recipients, idempotencyKey, 'smtp')— same RPC contract as HTTP API.kumo.inject— same endpoint asPOST /v1/send.credits.commiton2xx,credits.voidon failure.
Ports
| Env | Listen |
|---|---|
SMTP_PORT |
default 2525 |
SMTP_TLS_CERT / SMTP_TLS_KEY |
required in production for STARTTLS |
Production should run :587 behind Caddy (or via apps/smtp directly when
the appliance is on private net only). assertProductionProfile() rejects
SMTP_ALLOW_INSECURE=1 when NODE_ENV=production.
TLS
apps/smtp/src/tls.ts resolves STARTTLS via SMTP_TLS_CERT + SMTP_TLS_KEY.
Lab convenience: bash scripts/gen-smtp-lab-certs.sh writes self-signed
PEMs under .local/smtp-certs/ (matrix M06b/M26).
Bulk / queue via SMTP
Each SMTP session handles one envelope at a time. For high-volume mailing
many operators prefer the HTTP API (better idempotency, batch recipients)
or direct Kumo inject (POST /api/inject/v1 from the panel).
Related
- docs/access.md — SMTP credential create + rotate.
- docs/http-api.md — HTTP-equivalent path.
- docs/sending.md —
runSendflow. - docs/domains.md — verified From gate.
- docs/queues.md — bounce/suspend UI.
Last verified: Sat Jul 11 2026 17:00:00 GMT-0700 (Pacific Daylight Time). Cross-link maintained byscripts/check-docs-drift.sh (M54).