API Reference
API Reference
GitHub
SMTP and Domains

SMTP Servers

Configure SMTP servers for email delivery

An SMTP server is a route out. A project can hold several, arranged into groups that decide which one a given message tries and what it falls back to.

Adding one

POST /api/v1/smtp-servers

name is required and is how you refer to the server everywhere else. host and port are required for an ordinary SMTP relay — a provider reached over an API has neither.

curl -X POST http://localhost:3000/api/v1/smtp-servers \
  -H "Authorization: Bearer myk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "primary-relay",
    "host": "smtp.relay.example.net",
    "port": 587,
    "username": "acme-industrial",
    "password": "'"$SMTP_PASSWORD"'",
    "encryption": "starttls",
    "allowed_emails": ["noreply@yourdomain.com", "alerts@yourdomain.com"]
  }'

username and password are both optional — a relay authenticated by IP address, or an internal one that requires nothing, is a legitimate configuration. The password is sealed at rest and never returned by any read.

Encryption Options

ValuePortDescription
none25No encryption (not recommended)
starttls587Upgrade to TLS after connecting
ssl465TLS from the start

Testing Connections

Verify SMTP credentials and connectivity before sending via POST /api/v1/smtp-servers/{id}/test. This validates the hostname, port, credentials, and encryption.

Private network targets are refused

A project’s server cannot point at loopback, RFC 1918 or other reserved address space, and neither can a provider’s endpoint override. The host is a project member’s choice and the connection test reports what the peer answered, so without that guard the button is a scanner of the network Mailyard runs in. The check happens when the row is written and again at every dial, after the name has resolved.

sending.allow_private_smtp_targets lifts it, for a relay that genuinely is on the same network. The shared pool and relay nodes are never subject to it - an operator placed those.

Sender Restrictions

Use allowed_emails to restrict which sender addresses can use a specific SMTP server. This is useful when different servers are configured for different brands or departments.

Note

Passwords are never returned in API responses.

Common SMTP Providers

ProviderHostPortEncryption
Gmailsmtp.gmail.com587starttls
Outlooksmtp.office365.com587starttls
Amazon SESemail-smtp.us-east-1.amazonaws.com587starttls
Mailgunsmtp.mailgun.org587starttls
Postfix (local)localhost25none

Grouping and order

Servers belong to groups , which is how a send picks one and how failover decides what to try next. A project that never creates a group has exactly one, the default, holding every server - which is the behaviour that existed before groups.

If a project has no server

A project that has configured no SMTP server delivers through the platform’s shared pool , if an administrator has set one up. Adding a server here takes delivery over completely: from that point the pool is not consulted, even if the server you added is disabled or refuses the sender.

Providers

A server row says how it is reached, not only where. Two providers today:

ProviderHowFields it asks for
smtpA dialhost, port, encryption, optional username and password
sesThe Amazon SES APIregion, optional configuration set, optional access key

Everything else about a row is the same whichever it is: it sits in a group , takes a priority, honours its allowed senders, and takes part in failover. A group can hold both, and failover walks it in the same order - which is what lets an SES row be the primary and a plain relay the fallback.

provider is set when the server is created and cannot be patched afterwards. The credentials mean something different to each one - an SMTP login on one, an access key on the other - so switching in place would leave the wrong ones in the fields a PATCH does not touch. Delete and recreate instead.

A row reached over an API shows no host and no encryption, and the console says so rather than leaving the cells blank: “none” under encryption would read as cleartext when the call is HTTPS.