Skip to main content

mailsai

Email API for AI agents — Python SDK.

Per-agent email addresses on your domain, per-agent reputation, and prompt-injection scanning on every inbound. Your agent reads the reply and decides what to say — intent + entity extraction is opt-in.

pip install mailsai

Quick start

No agent to create, no domain to verify, no DNS. from names the sender and the agent is created on first use.

from mailsai import Client

# Reads MAILS_API_KEY from env (or pass api_key=... explicitly)
client = Client()

# mails.ai is transactional-only: mail the recipient asked for. Cold outreach and bulk
# marketing are refused with 422 cold_email_prohibited — that is deliberate, and it is
# what keeps the sending reputation clean for everyone on the platform.
sent = client.send(**{
    "from": "sarah",
    "to": "you@example.com",
    "subject": "Your verification code is 481902",
    "body": "Your verification code is 481902. It expires in 15 minutes.",
})

print(sent["from"])   # sarah@<your-workspace>.mails.ai — which identity actually sent

A test key (mk_test_…) runs that entire path — validation, the firewall, threading, events, webhooks — and delivers nothing, so you can integrate before you decide anything. On a test key, check sent.get("classifier_warning"): it is how a sandbox send tells you the same message would be refused on a live key.

Already have an agent, or want to name it explicitly? Both of these still work:

client.create_agent("sarah")            # explicit creation, when you want it
client.send("sarah", to="…", subject="…", body="…")

Note the free plan allows one agent. If from names a second one and there is no room, the send is refused with 402 plan_limit_exceeded naming the agent you do have — it is never quietly sent under a different identity.

from mailsai import agent

sarah = agent("sarah")

@sarah.on_reply
def handle(reply):
    # Always present — the delivery + security + identity layer:
    # reply["injection_score"]   -> 0.02   # six-category prompt-injection scan
    # reply["sender_reputation"] -> 0.91   # per-agent reputation
    #
    # Present only when classification is enabled (opt-in, +$0.003/inbound):
    # reply["intent"]            -> "schedule_demo" | "ask_question" | …
    # reply["entities"]          -> {"date": "...", "time": "..."}
    # reply["urgency"]           -> 0.8
    #
    # Your agent reads the reply and decides what to send next.
    print(reply["injection_score"], reply["sender_reputation"])

sarah.start_listening()  # blocks; opens SSE stream and dispatches replies

For non-blocking, pass blocking=False to start_listening() — it returns a daemon thread.

Lower-level client

from mailsai import create_client

c = create_client()  # reads MAILS_API_KEY

# Send via any agent
c.send("sarah", to="lead@example.com", subject="Demo", body_text="…")

# Resources
threads = c.list_threads(agent_id="agent_abc123")
usage = c.usage()
rep = c.get_reputation(agent_id="agent_abc123")

# Drafts
draft = c.create_draft(agent="sarah", to="lead@example.com", subject="Demo", body_text="…")
c.send_draft(draft["id"])

Webhook verification

from mailsai import verify_webhook

# In your webhook handler:
event = verify_webhook(
    body=request.body.decode(),
    signature=request.headers["X-Mails-Signature"],
    secret=os.environ["MAILS_WEBHOOK_SECRET"],
)
if event is None:
    return Response(status=400)
# event is the verified inbound event dict

Errors

from mailsai import MailsError

try:
    sarah.send(to="blocked@example.com", subject="…", body="…")
except MailsError as e:
    print(e.type, e.code, e.message, e.status, e.request_id)

Configuration

Param / env var Default
api_key / MAILS_API_KEY (required)
base_url / MAILS_BASE_URL https://api.mails.ai

Documentation

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mailsai-0.2.2.tar.gz (12.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mailsai-0.2.2-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file mailsai-0.2.2.tar.gz.

File metadata

  • Download URL: mailsai-0.2.2.tar.gz
  • Upload date:
  • Size: 12.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.5

File hashes

Hashes for mailsai-0.2.2.tar.gz
Algorithm Hash digest
SHA256 6a0c431a976dec17828b6f4cd19cfc7c32ab17b814cbdd62ef85f0155d7f7397
MD5 78d88ec1ed922801d1d16221261c8ec7
BLAKE2b-256 fe821a93e1a6f75473e2993637abb2ae9c26a6c38bd2481218a5975f7964222d

See more details on using hashes here.

File details

Details for the file mailsai-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: mailsai-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.5

File hashes

Hashes for mailsai-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 397fd2bcbcd4ea504e535cb4b3902f59c46bcc6314d7912d28e23cb45c9eaf8a
MD5 b617faaede082b12f2324e6458779152
BLAKE2b-256 4f327d205c6fab9386271e29fddad96ffd90d630d72a1f95abdb8cc6fe199334

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page