Sending over SMTP
Anypost accepts mail over SMTP as well as over the HTTP API. If your application, or off-the-shelf software you run, already sends through an SMTP server, point it at Anypost and you get the same authentication, delivery, and event reporting without writing code.
When to use SMTP
The HTTP API is the richer interface and what most of these docs describe. Reach for SMTP when:
- An existing app already speaks SMTP and you would rather configure it than rewrite its mail layer.
- You run software whose mail transport you do not control.
- A library or framework you already use makes SMTP the path of least resistance.
Both transports send from the same verified domains, authenticate with the same API keys, and produce the same events. They do not sustain the same submission rate, though: see Throughput before you commit a high-volume stream to SMTP.
Connection settings
| Setting | Value |
|---|---|
| Host | smtp.anypost.com |
| Ports | 587, 2587, or 25 |
| Encryption | STARTTLS (required) |
| Username | anypost |
| Password | your API key secret (ap_...) |
All three ports behave identically: pick whichever your network allows. 587
is the standard submission port and the one to use by default. 2587 is an
alternative for networks that block 587. 25 is also accepted, but many
hosting providers and ISPs block outbound traffic on it, so treat it as a
last resort rather than a default.
STARTTLS is mandatory on every port. The connection opens in plaintext and must upgrade to TLS before authenticating. There is no implicit-TLS port and no unencrypted submission path: Anypost refuses to authenticate, and refuses mail, on a session that has not upgraded to TLS.
Authentication
The username is always the literal string anypost. The password is an API
key secret, the same ap_... value used as the bearer token on the HTTP API.
A single key authenticates both transports. See
Authentication for creating, scoping, and
rotating keys.
Use a send_only key for an application that only sends. SMTP submission
needs no other permission.
Authentication failures are reported in the SMTP exchange: a bad key is
rejected at the AUTH step, and a session that never authenticates is
refused at MAIL FROM. Repeated failures from one address are temporarily
blocked.
Sender addresses
An SMTP submission carries two sender addresses, and Anypost checks both:
- The envelope sender, set by the SMTP
MAIL FROMcommand. It is where delivery failures are returned and is not shown to the recipient. Most SMTP clients set it automatically to match theFromheader. - The
Fromheader, the address the recipient sees in their mail client.
The domain of each must be both verified for your team and permitted for the API key:
- The domain must be verified, exactly as on the HTTP API. See Domains & DNS setup.
- The key must be allowed to use it. A key with an
allowed_domainsrestriction can only send from the domains it lists; an unrestricted key may use any of the team's verified domains. See Authentication.
The envelope sender and the From header do not have to share a domain, but
each is checked on its own. A submission is rejected if either one is on a
domain that is unverified or not permitted for the key. Checking the From
header separately is what stops an authenticated sender from passing the
envelope check with one domain and then showing the recipient a From
address on another.
Message size
A submitted message may be up to 5 MB, the same ceiling the HTTP API enforces.
This is the size of the full MIME message, including encoded attachments.
Anypost advertises the limit over the SIZE extension, so a well-behaved
client can refuse an oversized message before sending it.
5 MB is ample for transactional and marketing email. For a send that would strain it, host large files elsewhere and link to them rather than attaching them.
A test submission
Any SMTP client works. This example uses swaks,
a command-line SMTP tester:
swaks \
--server smtp.anypost.com --port 587 --tls \
--auth-user anypost --auth-password "$ANYPOST_API_KEY" \
--from [email protected] \
--to [email protected] \
--header "Subject: Hello from Anypost" \
--body "Hello, inbox!"--tls performs the required STARTTLS upgrade. A 250 OK on the DATA
command means the message was accepted.
Anypost headers
Standard MIME covers most of a message: From, To, Cc, Bcc, Subject,
Reply-To, the text and HTML parts, attachments, and inline images are all
ordinary parts of the message you submit.
The fields that are neither MIME headers nor message content — Anypost's send-time correlation dimensions, and the IP pool to send from — have no MIME equivalent, so over SMTP you set them with headers. Anypost reads and then strips these headers, so recipients never see them:
| Header | Sets | Value |
|---|---|---|
X-Anypost-Tags | Tags | A JSON array of strings, for example ["welcome","onboarding"]. |
X-Anypost-Tag | One tag | A single tag value. Repeat the header for several. Cannot be combined with X-Anypost-Tags. |
X-Anypost-Topic | Topic | A single topic string. |
X-Campaign | Campaign | A single campaign string. |
X-Anypost-Ip-Pool | IP pool | The name of one of your named IP pools. Only for accounts with dedicated IPs. |
Each header may appear at most once per message (apart from repeated
X-Anypost-Tag). A malformed value is rejected in the SMTP exchange rather
than sent. See Tags, topics & campaigns
for what the first four dimensions do, and
ip_pool for pool selection.
The message ID
The 250 OK reply to the DATA command carries an ids= field: one
email_ ID per recipient, space-separated.
250 OK ids=email_018f4f3e-7b2c-7c80-8e21-1a3a4f5b6c7d
Each ID identifies one recipient's copy of the message, and every event for
that copy references it. Capture the ids= field from the DATA response if
you want to correlate events back to a submission.
Throughput
SMTP submission is validated one message at a time. Every message pays its own
sender authorization, suppression-list lookup, and quota accounting before
Anypost accepts it. The HTTP API does that work inside the request that already
carried the message, and
POST /v1/email/batch amortizes it across up to 100
messages at once.
This is invisible on transactional traffic and on campaigns in the low millions of messages a month. It becomes the limiting factor on a sustained stream well above that: at tens of millions a month, the per-message overhead, not the network or the delivery capacity, sets how fast you can hand mail off.
So:
- Under a few million a month: use whichever transport suits your stack. SMTP is fine.
- Tens of millions a month or more: submit over the HTTP API, and use the batch endpoint wherever the messages are independent of each other. Keep SMTP for the systems whose transport you genuinely cannot change.
Nothing about deliverability, IP assignment, or event reporting changes with the transport. This is about submission rate only.
What differs from the HTTP API
SMTP reaches the same delivery and reporting, with a few interface differences:
- Idempotency keys are an HTTP-only feature. SMTP has no equivalent; a resubmitted message is a new send.
- Batch sending is HTTP-only. Over SMTP, submit each message separately on the same connection.
- Templates are an HTTP-API feature. An SMTP submission is an already-rendered message: it cannot reference a stored template or carry per-recipient variables.
- The remaining correlation dimensions (
tags,topic,campaign) andip_poolare set through headers, as above, rather than as JSON fields. - Submission rate is lower per message, which matters only at very high volume. See Throughput.
For anything beyond a straightforward send, the HTTP API is the fuller interface. See Send a single email.
Where to go next
- Authentication: create and scope the key SMTP authenticates with.
- Domains & DNS setup: verify the domain you send from.
- Webhooks: receive delivery and engagement events.