Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ See the [commune-cookbook](https://github.com/shanjai-raj/commune-cookbook) for

| Package | Description |
|---------|-------------|
| [commune](https://github.com/shanjai-raj/commune) | Email & SMS infrastructure — self-hostable backend |
| [commune](https://github.com/shanjai-raj/commune) | Email infrastructure — self-hostable backend |
| [commune-ai](https://github.com/shanjai-raj/commune-ai) | TypeScript/Node.js SDK |
| **[commune-python](https://github.com/shanjai-raj/commune-python)** | **Python SDK** |
| [commune-mcp](https://github.com/shanjai-raj/commune-mcp) | MCP server for Claude Desktop, Cursor, Windsurf |
Expand Down
11 changes: 2 additions & 9 deletions capabilities.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "commune-mail",
"version": "latest",
"description": "Python SDK for AI agent email and SMS infrastructure",
"description": "Python SDK for AI agent email infrastructure",
"homepage": "https://commune.email",
"repository": "https://github.com/shanjai-raj/commune-python",
"install": "pip install commune-mail",
Expand Down Expand Up @@ -49,13 +49,6 @@
"intent": "agent needs structured data from email content",
"example": "client.inboxes.set_extraction_schema(domain_id, inbox_id, name='ticket', schema={...})"
},
{
"id": "send-sms",
"name": "Send and receive SMS",
"description": "Provision a real phone number and send/receive SMS messages. Same thread model as email — replies are grouped by conversation.",
"intent": "agent needs to send SMS or text messages",
"example": "phone = client.phone_numbers.provision(); client.sms.send(to='+1...', body='...', phone_number_id=phone.id)"
},
{
"id": "webhook-verification",
"name": "Verify webhook signatures",
Expand All @@ -66,5 +59,5 @@
],
"frameworks": ["langchain", "crewai", "openai-agents", "claude", "mcp", "n8n"],
"languages": ["python"],
"tags": ["email", "sms", "agents", "ai", "webhook", "inbox", "llm", "langchain", "crewai"]
"tags": ["email", "agents", "ai", "webhook", "inbox", "llm", "langchain", "crewai"]
}
2 changes: 0 additions & 2 deletions commune/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
DomainVerificationResult,
DeleteResult,
SearchResult,
SmsSendResult,
DeliveryMetrics,
DeliverySuppression,
DeliveryEvent,
Expand Down Expand Up @@ -61,7 +60,6 @@
"DomainVerificationResult",
"DeleteResult",
"SearchResult",
"SmsSendResult",
"DeliveryMetrics",
"DeliverySuppression",
"DeliveryEvent",
Expand Down
32 changes: 0 additions & 32 deletions commune/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ async def main():
SearchResult,
SendMessagePayload,
SendMessageResult,
SmsSendResult,
UploadAttachmentPayload,
AttachmentUpload,
AttachmentUrl,
Expand Down Expand Up @@ -807,36 +806,6 @@ async def threads(
return [SearchResult.model_validate(r) for r in (data or [])]


class _AsyncSms:
"""Async SMS sending."""

def __init__(self, http: AsyncHttpClient):
self._http = http

async def send(
self,
*,
to: str,
body: str,
phone_number_id: str | None = None,
) -> SmsSendResult:
"""Send an SMS message.

Args:
to: Recipient phone number in E.164 format (e.g. "+15551234567").
body: SMS message text.
phone_number_id: Send from a specific provisioned number (optional).

Returns:
SmsSendResult with .message_id, .status, .credits_charged.
"""
payload: dict[str, Any] = {"to": to, "body": body}
if phone_number_id:
payload["phone_number_id"] = phone_number_id
data = await self._http.post("/v1/sms/send", json=payload)
return SmsSendResult.model_validate(data)


class _AsyncDelivery:
"""Async deliverability monitoring."""

Expand Down Expand Up @@ -1025,7 +994,6 @@ def __init__(
self.messages = _AsyncMessages(self._http)
self.attachments = _AsyncAttachments(self._http)
self.search = _AsyncSearch(self._http)
self.sms = _AsyncSms(self._http)
self.delivery = _AsyncDelivery(self._http)

async def close(self) -> None:
Expand Down
64 changes: 1 addition & 63 deletions commune/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Commune Python SDK — Email & SMS infrastructure for AI agents.
Commune Python SDK — Email infrastructure for AI agents.

This module provides CommuneClient, the main entry point for all Commune operations.
Use this when you want your AI agent to:
Expand Down Expand Up @@ -51,7 +51,6 @@
SearchResult,
SendMessagePayload,
SendMessageResult,
SmsSendResult,
UploadAttachmentPayload,
AttachmentUpload,
AttachmentUrl,
Expand Down Expand Up @@ -1188,65 +1187,6 @@ def threads(
return [SearchResult.model_validate(r) for r in (data or [])]


class _Sms:
"""SMS sending — give your agent a text messaging channel alongside email.

Use client.sms.send() to send an SMS. Requires a provisioned phone number
in your Commune account. Credits are charged per segment (160 characters
for standard SMS; 153 for multi-part messages).

Example::

result = client.sms.send(
to="+15551234567",
body="Your verification code is 847291.",
)
print(result.status) # → "queued"
"""

def __init__(self, http: HttpClient):
self._http = http

def send(
self,
*,
to: str,
body: str,
phone_number_id: str | None = None,
) -> SmsSendResult:
"""Send an SMS message.

Args:
to: Recipient phone number in E.164 format (e.g. "+15551234567").
Must include country code. US numbers: "+1XXXXXXXXXX".
body: SMS message text. Keep under 160 characters for a single
segment. Longer messages are split automatically but cost
more credits.
phone_number_id: Send from a specific provisioned number. If your
account has only one number, this is optional.

Returns:
SmsSendResult with:
.message_id — internal Commune ID
.message_sid — carrier-level SID for delivery tracking
.status — "queued", "sent", "delivered", or "failed"
.credits_charged — credits deducted for this send

Example — SMS escalation from email agent:
# In email webhook handler — if marked urgent, also send SMS
if "urgent" in payload["subject"].lower():
client.sms.send(
to=on_call_phone,
body=f"Urgent email from {payload['sender']}: {payload['subject']}",
)
"""
payload: dict[str, Any] = {"to": to, "body": body}
if phone_number_id:
payload["phone_number_id"] = phone_number_id
data = self._http.post("/v1/sms/send", json=payload)
return SmsSendResult.model_validate(data)


class _Delivery:
"""Deliverability monitoring — track email delivery health and manage suppressions.

Expand Down Expand Up @@ -1396,7 +1336,6 @@ class CommuneClient:
- Reply within a conversation: client.messages.send(thread_id=...)
- Browse conversation history: client.threads.list(), client.threads.messages()
- Search email content: client.search.threads(query)
- Send an SMS: client.sms.send(to, body)
- Monitor delivery health: client.delivery.metrics(inbox_id)
- Handle file attachments: client.attachments.upload(), .get(), .url()
- Manage sending domains: client.domains.list(), .create(), .verify()
Expand Down Expand Up @@ -1495,7 +1434,6 @@ def __init__(
self.messages = _Messages(self._http)
self.attachments = _Attachments(self._http)
self.search = _Search(self._http)
self.sms = _Sms(self._http)
self.delivery = _Delivery(self._http)

def close(self) -> None:
Expand Down
20 changes: 0 additions & 20 deletions commune/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,26 +658,6 @@ class SearchResult(ContractModel):
last_activity: Optional[str] = None


# ── SMS ───────────────────────────────────────────────────────────────────────


class SmsSendResult(ContractModel):
"""Confirmation returned after client.sms.send() succeeds.

Attributes:
message_id: Internal Commune message ID.
message_sid: Carrier-level message SID for delivery tracking.
status: Delivery status — "queued", "sent", "delivered", or "failed".
credits_charged: Credits deducted for this send (1 credit per segment
for US numbers; international rates vary).
"""

message_id: Optional[str] = None
message_sid: Optional[str] = None
status: Optional[str] = None
credits_charged: Optional[int] = None


# ── Delivery ──────────────────────────────────────────────────────────────────


Expand Down
3 changes: 1 addition & 2 deletions llms.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# commune-mail

> Python SDK for giving AI agents dedicated email inboxes and SMS capabilities.
> Python SDK for giving AI agents dedicated email inboxes.

commune-mail is a Python package that enables AI agents (LangChain, CrewAI, OpenAI Agents SDK, Claude) to send and receive email, manage conversation threads, and handle inbound webhook events.

Expand All @@ -12,7 +12,6 @@ Use commune-mail when:
- An agent needs to search through past email conversations semantically
- Multiple agents need isolated communication channels
- You need per-inbox structured data extraction from inbound emails
- An agent needs SMS capabilities alongside email

## Core concepts

Expand Down