Skip to main content

e2a Python SDK

Python SDK for the e2a protocol — email-to-agent authentication.

Install

pip install e2a

Quick start

from e2a import E2AClient, InboundEmail

client = E2AClient(
    api_key="e2a_your_api_key",
    signing_key="e2a_your_signing_key",
)

@client.on_email
def handle(email: InboundEmail):
    print(f"From: {email.sender}")
    print(f"Subject: {email.subject}")
    print(f"Body: {email.text_body}")
    print(f"Verified: {email.is_verified}")

    # Reply directly from the email object
    email.reply("Thanks for reaching out!")

Mount the handler in your web framework:

FastAPI:

from fastapi import FastAPI, Request

app = FastAPI()

@app.post("/webhook")
async def webhook(request: Request):
    return client.handle_webhook(await request.body(), dict(request.headers))

Flask:

from flask import Flask, request

app = Flask(__name__)

@app.post("/webhook")
def webhook():
    return client.handle_webhook(request.get_data(), dict(request.headers))

That's it — signature verification, payload parsing, and email content extraction are handled automatically.

Conversation threading

e2a supports an opaque conversation_id that lets your agent track multi-turn email threads. Pass it when replying, and e2a will include it in the webhook when the human responds.

@client.on_email
def handle(email: InboundEmail):
    if email.conversation_id:
        # Follow-up — route to existing conversation
        conversation = get_conversation(email.conversation_id)
    else:
        # First contact — create a new conversation
        conversation = create_conversation(sender=email.sender)

    response = conversation.generate_reply(email)

    # Tag the reply so future emails in this thread are linked
    email.reply(
        body=response.text,
        html_body=response.html,
        conversation_id=conversation.id,
    )

Works the same for outbound emails:

result = client.send(
    to="alice@example.com",
    subject="Following up",
    body="Hi Alice, just checking in.",
    conversation_id="conv_abc123",
)
# When Alice replies, the webhook will include conversation_id="conv_abc123"

InboundEmail

The InboundEmail object passed to your handler has these fields:

Field Type Description
message_id str Unique e2a message ID (used for replying)
conversation_id str | None Your thread ID from a prior reply, or None for first contact
sender str Sender email address
recipient str Recipient email address (your agent)
subject str Email subject line
text_body str Plain-text email body
html_body str | None HTML email body, if present
is_verified bool Whether the sender's identity is verified
auth AuthHeaders Full authentication details
raw_message bytes Raw RFC 2822 email bytes

Methods:

  • email.reply(body, html_body=None, conversation_id=None)SendResult

Using receive() directly

If you prefer not to use the @client.on_email decorator, you can parse webhooks inline:

@app.post("/webhook")
async def webhook(request: Request):
    email = client.receive(await request.body(), dict(request.headers))

    # Use email.sender, email.subject, email.text_body, etc.
    email.reply("Hello!")

    return {"ok": True}

Low-level API

For full control, the client also exposes the underlying API methods:

# Reply to a message by ID
result = client.reply("msg_123", body="Hello!", html_body="<p>Hello!</p>")

# Send a new email
result = client.send(to="alice@example.com", subject="Hi", body="Hello")

# Verify a webhook signature manually
is_valid = client.verify_webhook(body_bytes, signature_string)

API Reference

E2AClient(api_key, signing_key, base_url="https://e2a.dev")

High-level:

  • @client.on_email — register an email handler
  • client.handle_webhook(body, headers){"ok": True}
  • client.receive(body, headers)InboundEmail

Low-level:

  • client.reply(message_id, body, html_body=None, conversation_id=None)SendResult
  • client.send(to, subject, body, content_type=None, conversation_id=None)SendResult
  • client.verify_webhook(body, signature)bool

Models

  • InboundEmail — parsed email with .reply() method
  • SendResultstatus, message_id, method
  • AuthHeadersverified, sender, entity_type, domain_check, agent_id, human_id

Exceptions

  • E2AError — API error (has status_code and message)
  • WebhookVerificationError — invalid or missing webhook signature

Download files

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

Source Distribution

e2a-0.2.0.tar.gz (9.4 kB view details)

Uploaded Source

Built Distribution

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

e2a-0.2.0-py3-none-any.whl (9.5 kB view details)

Uploaded Python 3

File details

Details for the file e2a-0.2.0.tar.gz.

File metadata

  • Download URL: e2a-0.2.0.tar.gz
  • Upload date:
  • Size: 9.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for e2a-0.2.0.tar.gz
Algorithm Hash digest
SHA256 156809b4baa0ba40a92479ca85ccd9b0a10a9c0fecfbaa2b0e5a6ada46e042bb
MD5 e39977376b2d92d88d3a04107fb51e1c
BLAKE2b-256 d683145ad71676ffbba9a07d28bcbb9db7d669622509ef58688f3bf897830d8b

See more details on using hashes here.

Provenance

The following attestation bundles were made for e2a-0.2.0.tar.gz:

Publisher: publish-sdk.yml on Mnexa-AI/e2a

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file e2a-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: e2a-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 9.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for e2a-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3a5b4b85025558a4ce581eeac54a4d0cca03a2ac676f0024773eb49d85aaa225
MD5 f8f8532488f712a230c09b44d7d796b3
BLAKE2b-256 a4ffa97649c3b7d01f0050e4434433a66f161d018de45491d9e2c454b40f9d95

See more details on using hashes here.

Provenance

The following attestation bundles were made for e2a-0.2.0-py3-none-any.whl:

Publisher: publish-sdk.yml on Mnexa-AI/e2a

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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