Email Functions as Native Python with Magentic

Use Magentic's decorator pattern to make LLM-powered email composition feel like regular Python functions, backed by MultiMail's delivery infrastructure and oversight.


Magentic is a Python library that makes LLM calls look like regular function calls using decorators. Seamlessly integrating LLM capabilities into existing Python code with minimal boilerplate, it turns prompts into typed functions. MultiMail provides the email delivery infrastructure that sends what Magentic composes.

By combining Magentic with MultiMail, you can create email-composing functions that feel native to your Python codebase. Decorate a function with @prompt to describe the email task, and Magentic handles the LLM call. Then send the result through MultiMail's API with human oversight via gated_send mode.

Integration requires no special SDK — define Magentic-decorated functions for email composition and classification, then call the MultiMail REST API for delivery. The decorator pattern keeps your email logic clean and maintainable.

Built for Magentic developers

Native Python Feel

Magentic's decorator pattern makes email composition functions look and feel like regular Python code. Call compose_reply(email) and get a typed response. MultiMail sends it. No framework complexity in between.

Typed Email Composition

Return Pydantic models from Magentic functions for structured email data. Validate recipients, subjects, and body content at the type level, then send validated data to MultiMail.

Minimal Boilerplate

A Magentic email function is a decorator and a type hint. Compare that to agent frameworks that require tool registries, executors, and configuration objects. Less code means fewer bugs.

Composable Email Pipeline

Chain Magentic functions together: classify_email() | compose_reply() | send_via_multimail(). Each step is a simple function, making the pipeline easy to test, debug, and modify.

Async Support

Magentic supports async functions natively. Combined with async HTTP calls to MultiMail's API, you can process multiple emails concurrently without blocking.


Get started in minutes

Email Composition with Decorators
python
import requests
from magentic import prompt
from pydantic import BaseModel

MULTIMAIL_API = "https://api.multimail.dev/v1"
HEADERS = {"Authorization": "Bearer mm_live_your_api_key"}

class EmailDraft(BaseModel):
    subject: str
    body: str

@prompt(
    "Compose a professional email reply to the following message. "
    "Be concise and helpful.\n\n{email_content}"
)
def compose_reply(email_content: str) -> EmailDraft: ...

@prompt(
    "Classify this email as one of: support, sales, billing, spam.\n\n{content}"
)
def classify_email(content: str) -> str: ...

@prompt(
    "Summarize this email in one sentence.\n\n{content}"
)
def summarize_email(content: str) -> str: ...

"cm"># Use like regular Python functions
draft = compose_reply("Hi, what are your pricing options for the Pro plan?")
print(f"Subject: {draft.subject}\nBody: {draft.body}")

Use Magentic's @prompt decorator to create email-composing functions.

Compose and Send Pipeline
python
def process_and_reply(email: dict, mailbox_id: str) -> dict:
    """Process an inbound email and send a reply through MultiMail."""
    content = f"From: {email[&"cm">#039;from']}\nSubject: {email['subject']}\n\n{email['body']}"

    # Classify using Magentic
    category = classify_email(content)

    # Skip spam
    if category == "spam":
        return {"action": "skipped", "reason": "spam"}

    # Compose reply using Magentic
    draft = compose_reply(content)

    # Send via MultiMail (gated_send queues for approval)
    resp = requests.post(f"{MULTIMAIL_API}/reply", headers=HEADERS, json={
        "message_id": email["message_id"],
        "body": draft.body
    })

    return {
        "action": "replied",
        "category": category,
        "subject": draft.subject,
        "result": resp.json()
    }

# Process inbox
resp = requests.get(
    f"{MULTIMAIL_API}/mailboxes/your_mailbox_id/inbox",
    headers=HEADERS, params={"limit": 10}
)
for email in resp.json().get("emails", []):
    result = process_and_reply(email, "your_mailbox_id")
    print(f"{email[&"cm">#039;subject']}: {result['action']}")

Chain Magentic composition with MultiMail delivery in a clean pipeline.

Chat-Based Email Composition
python
from magentic import chatprompt, SystemMessage, UserMessage

@chatprompt(
    SystemMessage(
        "You are a professional email assistant. Compose emails that are "
        "concise, clear, and appropriate. The mailbox uses gated_send "
        "mode, so all emails will be reviewed before delivery."
    ),
    UserMessage(
        "Compose an email to {to} about {topic}. "
        "Context: {context}"
    )
)
def compose_email(to: str, topic: str, context: str) -> EmailDraft: ...

"cm"># Compose with context
draft = compose_email(
    to="[email protected]",
    topic="partnership renewal",
    context="They&"cm">#039;ve been a partner for 2 years. Contract expires next month. We want to renew with a 10% volume discount."
)

# Send through MultiMail
result = requests.post(f"{MULTIMAIL_API}/send", headers=HEADERS, json={
    "mailbox_id": "your_mailbox_id",
    "to": "[email protected]",
    "subject": draft.subject,
    "body": draft.body
})
print(result.json())

Use Magentic's @chatprompt for multi-turn email composition with context.


Step by step

1

Create a MultiMail Account and API Key

Sign up at multimail.dev, create a mailbox, and generate an API key. Your key will start with mm_live_.

2

Install Dependencies

Install Magentic and requests for calling the MultiMail API.

bash
pip install magentic requests
3

Define Email Functions

Create @prompt-decorated functions for email composition, classification, and summarization. Return Pydantic models for structured output.

bash
@prompt("Compose a reply to: {email_content}")
def compose_reply(email_content: str) -> EmailDraft: ...
4

Build Your Pipeline

Chain Magentic functions with MultiMail API calls: fetch inbox, classify emails, compose replies, and send through MultiMail.

5

Review Pending Emails

Approve or reject pending emails in the MultiMail dashboard when using gated_send mode.


Common questions

How does Magentic's decorator pattern work for email composition?
Decorate a function with @prompt and provide a prompt template with placeholders for parameters. Magentic calls the LLM with the filled template and returns a typed result. For email composition, the return type can be a Pydantic model with subject and body fields, giving you structured email data ready to send through MultiMail.
Can I use Magentic with models other than OpenAI?
Yes. Magentic supports multiple LLM backends including OpenAI, Anthropic, and LiteLLM for broader provider access. The decorator pattern works the same regardless of backend. MultiMail's REST API is completely provider-agnostic.
How does Magentic compare to full agent frameworks for email?
Magentic provides decorated functions, not agent loops. This is simpler for email composition and classification tasks where you don't need autonomous tool selection. For complex multi-step email workflows with branching logic, consider combining Magentic functions with an orchestrator like ControlFlow or LangGraph.
Can I use async Magentic functions with MultiMail?
Yes. Magentic supports async decorated functions. Combine with async HTTP calls using httpx to process multiple emails concurrently. This is useful for batch operations like classifying and replying to a full inbox.
How do I handle streaming for long email drafts?
Magentic supports streaming output from decorated functions. Use Annotated types with streaming support to get partial results as the LLM generates them. The final complete draft is then sent to MultiMail as a single API call, since email delivery requires the full message.

Explore more

The only agent email with a verifiable sender

Email infrastructure built for AI agents. Verifiable identity, graduated oversight, and a 38-tool MCP server. Formally verified in Lean 4.