Skip to content
PostMTA Hosted
StatusSign inOpen panelRequest access
Open menu

Docs

Open in panel → /app · access

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):

  1. extractRecipientsFromMime walks the MIME for unique recipients.
  2. credits.hold(workspace, recipients, idempotencyKey, 'smtp') — same RPC contract as HTTP API.
  3. kumo.inject — same endpoint as POST /v1/send.
  4. credits.commit on 2xx, credits.void on 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).

Last verified: Sat Jul 11 2026 17:00:00 GMT-0700 (Pacific Daylight Time). Cross-link maintained byscripts/check-docs-drift.sh (M54).

← All docs