SMTP relay
Orbit’s SMTP relay is an ingress endpoint: your SMTP client connects, authenticates with an API key, and submits a standard RFC 5322 message. The submission enters the same email pillar thatPOST /api/v1/messages/email uses — the same suppression checks, consent gates, billing, delivery tracking, and verified-sender enforcement apply either way.
This is not a deliverability relay in the SES sense. Orbit does not accept arbitrary email for relay to third-party providers; it accepts your email and hands it to the same outbound pipeline the rest of the platform uses.
The SMTP relay is in early access and rolls out per account. If the dashboard
surface at Developer → SMTP shows the early-access notice, request access
before pointing production traffic at the endpoint.
When to use it
Use the relay when the sending system already speaks SMTP and switching it to HTTP is not practical — a CRM with built-in SMTP notifications, a point-of-sale system, monitoring software, or an ERP that can only emit email. If you are writing new code, prefer the HTTP endpoint on Channels → Email: it returns structured errors, supports attachments andcc/bcc, and is the better integration surface. The relay exists so legacy systems join the same pipeline without a rewrite.
Credential model
The relay authenticates with your existing API keys — there is no separate SMTP credential to issue. The same key gates both the HTTP send endpoint and the SMTP submission, and every relayed message is scoped and billed to the key that authenticated it. Revoke or rotate a key under Settings → API Keys and both ingress paths follow immediately. Mint or manage keys from Developer → API Keys (the relay page links straight there).Connection profile
TLS is required on every port. Use port
587 unless your network blocks it — 2525 exists for that case — and 465 only if your client cannot do STARTTLS.
The username is a fixed sentinel. Your client must send the literal string apikey as the SMTP AUTH username and the full API key as the password. Authentication failure returns a single 535 reply regardless of which check failed, so a wrong username and a revoked key look identical on the wire.
Message mapping
The relay converts the SMTP session into the same payload shape the HTTP endpoint produces:- Envelope recipients win. The recipient list comes from the envelope
RCPT TOcommands (which is what you actually addressed, including Bcc). HeaderTo/Ccare only a fallback when the client presents no envelope recipients. - Sender. The
From:header is preferred (it is what recipients see and what verified-sender enforcement checks); the envelopeMAIL FROMis the fallback. The sender domain must be verified exactly as it would be for an HTTP send — an unverified domain is rejected either way. - Body. The HTML part is preferred over the plain-text part, matching the HTTP endpoint’s selection so the two ingress paths cannot drift. A message with no parseable body content returns
554. - Headers. Standard headers (
Subject, date, message-id) map to the message record. CustomX-headers your system adds do not become contact fields — use the HTTP endpoint’smetadatafor programmatic fields.
Recipients and suppression
Suppression and consent behave identically on both ingress paths because the relay dispatches into the same send pipeline. A recipient on your email suppression list (hard bounce, complaint, unsubscribe, or a manual entry) is refused at the pre-send gate, exactly asRECIPIENT_OPTED_OUT behaves on the HTTP path, and you are not charged for it. See Bounce and Complaint Handling for the suppression lifecycle, and Opt-out lists for consent configuration.
After DATA, the relay returns one transaction-level reply: 250 if at least one recipient was accepted (the count is included in the reply text), or 554 if every recipient was rejected by the pipeline.
Throughput limits
Relayed sends consume the same per-tenant rate pool as HTTP sends — 200 messages per minute per tenant on the email channel by default. A burst that exceeds the pool is throttled rather than queued indefinitely; when the relay’s submission envelope exceeds one recipient, the per-recipient fanout draws from that same pool. Check the current pool and any per-tenant overrides in Rate limits. Connection-level flood protection closes abusive sessions; keep reconnecting clients on a bounded retry loop.Example session
Probe the endpoint with swaks or verify TLS withopenssl s_client:
587 begins with STARTTLS before EHLO. A 535 after AUTH means the key failed; a 554 after DATA means the message or every recipient was rejected — check sender verification and suppression before retrying.
To see the per-recipient fanout, address two RCPT TO recipients in one probe — one live address and one suppressed address. The relay accepts the message when at least one recipient survives, and the 250 reply names the accepted count:
DATA — not billed, not delivered — while the accepted one delivers. Only when every recipient is rejected does the relay answer 554.
Connection troubleshooting
Work through these in the order your client hits them: a335 stops the session before authentication, a 535 is authentication itself, and a 554 after DATA is the pipeline refusing the message.
335 StartTLS expected before Authenticate
The server requires the session to be encrypted before it accepts credentials, but your client tried to authenticate on the plaintext connection. Library-specific — Nodemailer’s secure: false is the classic case.
Fix: upgrade with STARTTLS before AUTH. In Nodemailer use secure: false plus requireTLS: true; most other clients enable STARTTLS when the port maps to 587/2525. If the client cannot do STARTTLS, move it to port 465 (implicit TLS) instead.
535 Authentication failed
The relay answers a single 535 for every credential failure, so a wrong username and a dead key look identical on the wire. Check in this order:
- The username must be the literal string
apikey— not your account id, tenant id, or an email address. - The password must be an active tenant API key, full value, no prefix trimming.
- If the key was rotated or revoked under Developer → API Keys, point the client at the replacement key — an environment variable or secrets-injection step is the usual stale-credential source.
535 after all three checks usually means the client base64-encodes its AUTH payload with a trailing newline — strip whitespace at the client boundary.
554 after DATA — message rejected
The pre-send pipeline refused the message as a whole: either the sender failed verification, or every envelope RCPT TO recipient was turned away by suppression or consent. Two root causes, fixed in different places:
- Sender unverified. The domain in the
From:header must be a verified sender under the Email channel. Complete the DNS records in Email → Senders exactly as you would for an HTTP send — see Domain Setup on the Email channel. - All recipients suppressed. Every recipient on the envelope was on your suppression list (hard bounce, complaint, unsubscribe, or manual entry) or blocked by consent. The relay reports
554only when not a single recipient survived — a mixed list returns250with the accepted count. Check Opt-out lists for the consent gate and Bounce and Complaint Handling for the suppression lifecycle.
Client libraries
Every snippet authenticates with the literal usernameapikey and the API key as the password — the pattern works in any SMTP library that allows a custom AUTH username.
Nodemailer (Node.js)
Python smtplib
Ruby Net::SMTP
PHP (Symfony Mailer)
Go (gomail/v2)
Java (Jakarta Mail)
535 after AUTH in any of these clients means the credential check failed — work through the 535 checks above before retrying. Note that PHP and Java read the key with getenv/System.getenv, so a key exported in a different shell or service context than the one the process runs in shows up as a 535, not a connection error.
All six snippets submit into the same pipeline as the HTTP endpoint, so sender verification, suppression, and rate limits behave identically to POST /api/v1/messages/email.
Worked HTTP equivalent — request, response, errors, SDKs
The relay maps every accepted submission onto the same payloadPOST /api/v1/messages/email produces. Model or verify the full loop over HTTP first — the sequences below are the exact request/response/error trio the SMTP session compresses into reply codes. The longer guide with per-SDK catch blocks is at SMTP relay recipes.
Request (HTTP equivalent of an SMTP submission with an attachment)
Response — the 202-accepted envelope
250 after DATA with the accepted-recipient count.
Error branches worth coding against
The full catalog (including
VALIDATION_ERROR, QUOTA_EXCEEDED, and MESSAGE_SEND_FAILED) lives on the Email channel page.
SDK calls (the same send in four languages)
Node.js —@devotel-orbit/node:
orbit_sdk:
devotel/orbit:
devotel/orbit:
code values — INVALID_RECIPIENT, CHANNEL_NOT_CONFIGURED, RATE_LIMITED — see SMTP relay recipes for the catch blocks.
Where to go next
Email channel
HTTP send endpoint, templates, domain setup, and the full error catalog.
API integration
End-to-end REST integration patterns including idempotent sends.
Opt-out lists
Configure the suppression and consent checks the relay inherits.
Rate limits
Per-tenant pools the SMTP and HTTP ingress share.