Sentio SMTP
An email inbox API for AI agents. Give every agent its own real address, receive mail as structured webhooks, and reply in-thread over REST - on a complete mail server you run yourself.
Who Sentio is for
Developers and integrators who need an agent to be an email participant: receive a customer thread, act on it, and reply as itself.
Normally that means wiring an IMAP poller to a parser to an SMTP relay, and inheriting a legacy mail server's operating surface along the way. Sentio is that whole path as one service.
It is also built for platforms. Every domain, mailbox, API key, rate limit, suppression list and spam profile belongs to a tenant, so one deployment can carry many customers without them sharing a sending reputation.
What Sentio does
An Address Per Agent
A mailbox is a real address on your domain. Give one to each agent, put your own agent id in its metadata, and run thousands side by side.
Verified Before You See It
Inbound mail is SPF, DKIM and DMARC checked, virus-scanned and spam-scored before your webhook fires, and the verdicts arrive with the payload. An agent never has to work out whether a sender was forged.
A Real Mail Server
Not a wrapper around someone else's API. Sentio speaks the protocol in both directions, signs with DKIM, and handles MTA-STS, DANE and three tiers of anti-spam itself.
Give an agent an inbox
Three calls: a domain, a mailbox, and a route that points at your application.
# 1. A receiving domain for this tenant
curl -X POST "$API/v1/domains" -H "Authorization: Bearer $KEY" \
-d '{"domain_name":"acme.example.com","use_for_receiving":true}'
# 2. One mailbox per agent. metadata is yours - put the agent id in it.
curl -X POST "$API/v1/domains/$DOMAIN_ID/mailboxes" -H "Authorization: Bearer $KEY" \
-d '{"address":"support-agent","metadata":{"agent_id":"agt_01H8..."}}'
# 3. Route the domain to your application
curl -X POST "$API/v1/tenants/$TENANT/inbound-routes" -H "Authorization: Bearer $KEY" \
-d '{"match_type":"domain","pattern":"acme.example.com",
"webhook_url":"https://your-platform.example.com/hooks/inbound"}'support-agent@acme.example.com is now live, and mail to it arrives at your webhook already parsed.
Replying in thread
Pass the inbound Message-ID back and the reply threads correctly in the recipient's client. Outbound is DKIM-signed with the tenant's own key, so it authenticates as your customer's domain rather than yours.
curl -X POST "$API/v1/messages/send" -H "Authorization: Bearer $KEY" \
-d '{
"from": "support-agent@acme.example.com",
"to": ["customer@example.net"],
"subject": "Re: Order #1234",
"text": "Refund processed - you should see it in 3-5 days.",
"in_reply_to": "<abc123@example.net>",
"references": ["<abc123@example.net>"]
}'Once mail is flowing
Forwarding That Survives DMARC
Most servers relay a forwarded message unchanged, so the original From: no longer aligns and the receiver rejects it. Sentio rewrites the envelope and re-signs with the mailbox domain's key, keeping the original sender in Reply-To: so hitting reply still answers the person who wrote in.
Event Webhooks
Subscribe to delivered, bounced, deferred, opened, clicked, unsubscribed and more. Signed with HMAC-SHA256, with retries, per-endpoint concurrency caps, delivery logs and a test-dispatch endpoint.
Suppressions and Unsubscribe
Hard bounces and ISP complaint reports suppress addresses automatically, one-click unsubscribe is honoured, and you can check an address before spending a send on it.
IP Pools and Warmup
Assign tenants to dedicated or shared pools and ramp a new address on a schedule with per-ISP overrides, rather than sending an untrusted IP straight to full volume.
Engagement Tracking
Open pixels and click rewriting with bot detection, so a mail scanner's open is not counted as a human one. Serve it from your own branded CNAME instead of a shared host.
Reports You Can Read
DMARC aggregate, FBL/ARF and TLS-RPT reports are ingested and queryable, so authentication failures and TLS problems surface as data rather than as unexplained delivery loss.
Anti-spam in three tiers
Expensive checks only see traffic the cheap ones could not decide.
| Tier | Cost | What runs |
|---|---|---|
| Connection | Sub-millisecond | IP bans, connection and AUTH rate limits, DNSBL lookups, greylisting, reputation scoring, reverse DNS |
| Content | Tens of milliseconds | rspamd or the built-in engine: Bayesian classification, fuzzy hashes, URL reputation, header heuristics |
| LLM tiebreak | Borderline only | A model, and only inside a configurable review band. Clear ham and clear spam never reach one. |
Quick start
The compose stack brings up Sentio plus everything it needs: PostgreSQL, Redis, NATS/JetStream, MinIO, ClamAV and rspamd. It pulls a prebuilt image, so there is nothing to compile. Docker Engine 24+ with the Compose plugin, around 4 GB of RAM and 8 GB of disk.
git clone https://github.com/truespar/sentio.git
cd sentio
docker compose up -d
curl localhost:8080/health/ready
# {"status":"ok","database":"ok","kv":"ok"}The server documents itself: /docs is an interactive reference with a request client that calls your running server, and /openapi.json is the OpenAPI 3.1 document. Ports are 25 for inbound, 587 for submission, 465 for implicit TLS, and 8080 for the API.
The API
116 operations across 85 paths, all bearer-authenticated. A selection of the groups:
| Group | Operations | What it covers |
|---|---|---|
| Messages | 9 | Submit single, batch, raw or multipart mail; read status, events and raw source |
| Domains | 7 | Register sending and receiving domains, fetch the DNS records to publish, verify them |
| Mailboxes | 5 | Per-address inboxes on a domain, with forwarding and auto-reply |
| Inbound Routes | 4 | Match inbound mail (exact, domain, regex, catch-all) to a webhook |
| Webhooks | 7 | Subscribe to delivery and engagement events, HMAC-signed with retries |
| Tenants and keys | 13 | Tenants, tiers, scoped API keys, SMTP credentials and OAuth clients |
| DKIM Keys | 5 | Generate, rotate and retire signing keys; export the DNS record |
| Suppressions | 5 | Bounce, complaint and unsubscribe lists; check an address before sending |
| IP Pools | 12 | Dedicated and shared pools, tenant assignment and warmup schedules |
| Reports | 7 | Ingest and read DMARC aggregate, FBL/ARF and TLS-RPT reports |
Because it is a standard OpenAPI document, the usual generators produce a client directly from it.
How it is built
A Rust workspace of thirteen crates. PostgreSQL for state, Redis for the KV layer, NATS/JetStream for queues, S3-compatible storage for message bodies.
| Crate | Responsibility |
|---|---|
sentio-core | Shared types, error model, configuration, repository traits |
sentio-store | PostgreSQL repositories and the Redis KV pool |
sentio-smtp-server | Inbound SMTP state machine, TLS, SASL AUTH |
sentio-smtp-client | Outbound delivery, MX resolution, connection pooling |
sentio-auth | DKIM, SPF, DMARC, ARC, MTA-STS, DANE, BIMI |
sentio-queue | NATS/JetStream producers and consumers |
sentio-storage | S3-compatible blob storage, ClamAV scanning |
sentio-spam | rspamd integration and the built-in scoring engine |
sentio-abuse | Rate limiting, IP bans, greylisting, reputation |
sentio-llm | LLM classification, with a choice of provider |
sentio-webhooks | HMAC-signed event dispatch with retries |
sentio-observe | Structured logging, Prometheus metrics, OpenTelemetry |
sentio-api | Axum REST API with generated OpenAPI |
Running it for real
Software is the easy half. Deliverability lives in DNS and IP reputation, and skipping that is the usual reason self-hosted mail lands in spam.
Sentio generates your DNS
SPF, DKIM and DMARC records come from the API for each domain, and a verify call checks what has actually propagated. You still need an MX, and a PTR that only your hosting provider can set.
Port 25 is often blocked
Most residential ISPs and several cloud providers restrict outbound port 25 by default, AWS, GCP, Azure, Oracle and Hetzner among them. You may need a limit lift, or relay through a smart host.
Forward and reverse DNS must agree
Many receivers reject mail from a host whose PTR does not resolve back to its address. This catches people out more than any software problem does.
MIT or Apache-2.0, and open to contributions
Sentio is dual-licensed: take it under MIT or under Apache-2.0, whichever suits you, and you do not have to satisfy both. MIT is the shorter of the two and is compatible with GPLv2; Apache-2.0 additionally grants an explicit patent licence, which some adopters require. Issues and pull requests are welcome, and the repository carries the full documentation.