Open Source · MIT or Apache-2.0

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.

TierCostWhat runs
ConnectionSub-millisecondIP bans, connection and AUTH rate limits, DNSBL lookups, greylisting, reputation scoring, reverse DNS
ContentTens of millisecondsrspamd or the built-in engine: Bayesian classification, fuzzy hashes, URL reputation, header heuristics
LLM tiebreakBorderline onlyA 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:

GroupOperationsWhat it covers
Messages9Submit single, batch, raw or multipart mail; read status, events and raw source
Domains7Register sending and receiving domains, fetch the DNS records to publish, verify them
Mailboxes5Per-address inboxes on a domain, with forwarding and auto-reply
Inbound Routes4Match inbound mail (exact, domain, regex, catch-all) to a webhook
Webhooks7Subscribe to delivery and engagement events, HMAC-signed with retries
Tenants and keys13Tenants, tiers, scoped API keys, SMTP credentials and OAuth clients
DKIM Keys5Generate, rotate and retire signing keys; export the DNS record
Suppressions5Bounce, complaint and unsubscribe lists; check an address before sending
IP Pools12Dedicated and shared pools, tenant assignment and warmup schedules
Reports7Ingest 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.

CrateResponsibility
sentio-coreShared types, error model, configuration, repository traits
sentio-storePostgreSQL repositories and the Redis KV pool
sentio-smtp-serverInbound SMTP state machine, TLS, SASL AUTH
sentio-smtp-clientOutbound delivery, MX resolution, connection pooling
sentio-authDKIM, SPF, DMARC, ARC, MTA-STS, DANE, BIMI
sentio-queueNATS/JetStream producers and consumers
sentio-storageS3-compatible blob storage, ClamAV scanning
sentio-spamrspamd integration and the built-in scoring engine
sentio-abuseRate limiting, IP bans, greylisting, reputation
sentio-llmLLM classification, with a choice of provider
sentio-webhooksHMAC-signed event dispatch with retries
sentio-observeStructured logging, Prometheus metrics, OpenTelemetry
sentio-apiAxum 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.