Skip to content

Mail API Reference

Module functions

create_mailbox

create_mailbox(
    name: str | None = None,
    ttl: int | None = None,
    domain_id: str | None = None,
) -> Mailbox

Create a mailbox. Returns a Mailbox ready to send and receive.

Parameters:

Name Type Description Default
name str | None

Mailbox name (used in address prefix). Omit for random.

None
ttl int | None

Optional TTL in seconds (max 30 days).

None
domain_id str | None

Optional custom domain ID.

None
Example

from primitif import mail mb = mail.create_mailbox(name="agent") print(mb.address)

list_mailboxes

list_mailboxes(
    *, limit: int = 20, cursor: str | None = None
) -> PaginatedList[MailboxListItem]

List all mailboxes in the namespace.

Example

for mb in mail.list_mailboxes(): ... print(mb.address, mb.received_count)

delete_mailbox

delete_mailbox(mailbox_id: str) -> None

Delete a mailbox by ID.

Example

mail.delete_mailbox("mb_...")

account

account() -> AccountInfo

Get account info (plan, usage, limits).

Example

info = mail.account() print(info.plan, info.email_count)

add_protected_recipient

add_protected_recipient(pattern: str) -> ProtectedRecipient

Add a protected recipient pattern (email or @domain).

Example

mail.add_protected_recipient("ceo@bigcorp.com")

list_protected_recipients

list_protected_recipients() -> list[ProtectedRecipient]

List all protected recipient patterns.

Mailbox

Mailbox

Mailbox(
    token: str | None = None,
    *,
    base_url: str | None = None,
    max_retries: int = DEFAULT_MAX_RETRIES,
    timeout: float = 30.0,
    _client: Client | None = None,
)

A single ephemeral mailbox — send, receive, and manage email.

Typically created via p.mail.create_mailbox(), but can also be instantiated directly with a token for agent-scoped operations.

Usage::

with Mailbox() as mb:  # reads PRIMITIF_MAIL_TOKEN from env
    mb.send(to="user@example.com", subject="Hi", body_text="Hello")
    for msg in mb.inbox():
        detail = mb.read(msg.id)
    mb.delete()

Create a Mailbox client for agent-scoped email operations.

Parameters:

Name Type Description Default
token str | None

Mailbox token (mb_tok_...). Falls back to the PRIMITIF_MAIL_TOKEN environment variable if omitted.

None
base_url str | None

Mail API base URL. Defaults to PRIMITIF_MAIL_URL env var or https://api.mail.primitif.ai.

None
max_retries int

Number of automatic retries on transient errors. Defaults to 2.

DEFAULT_MAX_RETRIES
timeout float

HTTP request timeout in seconds. Defaults to 30.0.

30.0

Raises:

Type Description
MailError

If no token is provided and PRIMITIF_MAIL_TOKEN is not set.

Example

mb = Mailbox(token="mb_tok_abc123") print(mb.address) 'agent-7f3a@mail.primitif.ai'

address property

address: str

The mailbox email address (fetched and cached).

Calls info() on first access to populate the cache.

Returns:

Type Description
str

The full email address (e.g. "agent-7f3a@mail.primitif.ai").

Example

print(mb.address) 'agent-7f3a@mail.primitif.ai'

token property

token: str | None

The mailbox token, if available.

Present when created via p.mail.create_mailbox() or when token= was passed to the constructor. Useful for persisting tokens so a crashed agent can reconnect with Mailbox(token=...).

Returns:

Type Description
str | None

The token string (mb_tok_...) or None if not available.

Example

token = mb.token

persist token, then later:

mb = Mailbox(token=token)

send

send(
    to: str,
    subject: str,
    body_text: str,
    body_html: str | None = None,
    require_approval: bool = False,
) -> SendResult

Send an email from this mailbox.

Parameters:

Name Type Description Default
to str

Recipient email address.

required
subject str

Email subject line.

required
body_text str

Plain-text email body.

required
body_html str | None

Optional HTML email body.

None
require_approval bool

If True, the email is held for human approval before sending. Defaults to False.

False

Returns:

Type Description
SendResult

SendResult with thread_id, message_id, and status

SendResult

("sent", "held", or "pending_approval"). When

SendResult

approval is required, approval_url is set.

Raises:

Type Description
MailValidationError

If the payload is invalid (e.g. bad address).

MailAuthError

If the token is invalid.

Example

result = mb.send( ... to="user@example.com", ... subject="Invoice #42", ... body_text="Please find your invoice attached.", ... ) print(result.message_id)

reply

reply(
    message: str | InboxMessage,
    body_text: str,
    body_html: str | None = None,
    require_approval: bool = False,
) -> SendResult

Reply to a message.

Sends a reply in the same thread as the original message.

Parameters:

Name Type Description Default
message str | InboxMessage

Message ID string or an InboxMessage object.

required
body_text str

Plain-text reply body.

required
body_html str | None

Optional HTML reply body.

None
require_approval bool

If True, the reply is held for human approval. Defaults to False.

False

Returns:

Type Description
SendResult

SendResult with thread_id, message_id, and status.

Raises:

Type Description
MailNotFoundError

If the original message does not exist.

MailValidationError

If the payload is invalid.

MailAuthError

If the token is invalid.

Example

for msg in mb.inbox(unread_only=True): ... mb.reply(msg, "Got it, thanks!")

inbox

inbox(
    *,
    unread_only: bool = False,
    limit: int = 20,
    cursor: str | None = None,
) -> PaginatedList[InboxMessage]

List inbox messages.

Parameters:

Name Type Description Default
unread_only bool

If True, return only unread messages. Defaults to False.

False
limit int

Maximum number of messages per page. Defaults to 20.

20
cursor str | None

Pagination cursor from a previous response.

None

Returns:

Type Description
PaginatedList[InboxMessage]

PaginatedList[InboxMessage] supporting iteration and

PaginatedList[InboxMessage]

.auto_paging_iter() for automatic pagination.

Raises:

Type Description
MailAuthError

If the token is invalid.

MailNetworkError

On connection failure.

Example

for msg in mb.inbox(unread_only=True): ... print(msg.from_address, msg.subject)

Auto-paginate through all messages:

for msg in mb.inbox().auto_paging_iter(): ... print(msg.id)

read

read(message: str | InboxMessage) -> MessageDetail

Read a full message.

Marks the message as read on the server.

Parameters:

Name Type Description Default
message str | InboxMessage

Message ID string or an InboxMessage object.

required

Returns:

Type Description
MessageDetail

MessageDetail with full body, headers, and auth results

MessageDetail

(spf, dkim, dmarc).

Raises:

Type Description
MailNotFoundError

If the message does not exist.

MailAuthError

If the token is invalid.

Example

for msg in mb.inbox(): ... detail = mb.read(msg) ... print(detail.body_text)

threads

threads(
    *, limit: int = 20, cursor: str | None = None
) -> PaginatedList[ThreadSummary]

List email threads.

Parameters:

Name Type Description Default
limit int

Maximum number of threads per page. Defaults to 20.

20
cursor str | None

Pagination cursor from a previous response.

None

Returns:

Type Description
PaginatedList[ThreadSummary]

PaginatedList[ThreadSummary] supporting iteration and

PaginatedList[ThreadSummary]

.auto_paging_iter().

Raises:

Type Description
MailAuthError

If the token is invalid.

MailNetworkError

On connection failure.

Example

for t in mb.threads(): ... print(t.subject, t.message_count)

thread

thread(thread: str | ThreadSummary) -> ThreadDetail

Get a full thread with all messages.

Parameters:

Name Type Description Default
thread str | ThreadSummary

Thread ID string or a ThreadSummary object.

required

Returns:

Type Description
ThreadDetail

ThreadDetail containing the thread metadata and a messages

ThreadDetail

list of MessageDetail objects.

Raises:

Type Description
MailNotFoundError

If the thread does not exist.

MailAuthError

If the token is invalid.

Example

for t in mb.threads(): ... detail = mb.thread(t) ... for msg in detail.messages: ... print(msg.from_address, msg.body_text)

list_attachments

list_attachments(
    message: str | InboxMessage,
) -> list[AttachmentInfo]

List attachments on a message.

Parameters:

Name Type Description Default
message str | InboxMessage

Message ID string or an InboxMessage object.

required

Returns:

Type Description
list[AttachmentInfo]

List of AttachmentInfo with id, filename,

list[AttachmentInfo]

content_type, and size_bytes.

Raises:

Type Description
MailNotFoundError

If the message does not exist.

MailAuthError

If the token is invalid.

Example

for att in mb.list_attachments(msg): ... print(att.filename, att.size_bytes)

download

download(attachment: AttachmentInfo) -> bytes

Download an attachment.

Parameters:

Name Type Description Default
attachment AttachmentInfo

An AttachmentInfo object from list_attachments().

required

Returns:

Type Description
bytes

Raw file bytes.

Example

for att in mb.list_attachments(msg): ... data = mb.download(att) ... with open(att.filename, "wb") as f: ... f.write(data)

download_attachment

download_attachment(
    message: str | InboxMessage, attachment_id: str
) -> bytes

Download a raw attachment.

Parameters:

Name Type Description Default
message str | InboxMessage

Message ID string or an InboxMessage object.

required
attachment_id str

The attachment ID (from AttachmentInfo.id).

required

Returns:

Type Description
bytes

Raw file bytes.

Raises:

Type Description
MailNotFoundError

If the message or attachment does not exist.

MailAuthError

If the token is invalid.

MailNetworkError

On connection failure after retries.

Example

data = mb.download_attachment("msg_abc123", "att_def456") with open("invoice.pdf", "wb") as f: ... f.write(data)

get_allowlist

get_allowlist() -> list[AllowlistEntry]

List allowed senders.

Returns:

Type Description
list[AllowlistEntry]

List of AllowlistEntry with id, sender_address, and

list[AllowlistEntry]

created_at.

Raises:

Type Description
MailAuthError

If the token is invalid.

Example

for entry in mb.get_allowlist(): ... print(entry.sender_address)

add_allowlist

add_allowlist(sender_address: str) -> AllowlistEntry

Add an allowed sender.

Only emails from allowlisted senders will be delivered to this mailbox (when the allowlist is non-empty).

Parameters:

Name Type Description Default
sender_address str

Email address to allow (e.g. "noreply@github.com").

required

Returns:

Type Description
AllowlistEntry

The created AllowlistEntry.

Raises:

Type Description
MailConflictError

If the address is already allowlisted.

MailValidationError

If the address is invalid.

MailAuthError

If the token is invalid.

Example

entry = mb.add_allowlist("noreply@github.com") print(entry.id)

remove_allowlist

remove_allowlist(entry_id: str) -> None

Remove an allowed sender.

Parameters:

Name Type Description Default
entry_id str

The allowlist entry ID (from AllowlistEntry.id).

required

Raises:

Type Description
MailNotFoundError

If the entry does not exist.

MailAuthError

If the token is invalid.

Example

mb.remove_allowlist("ale_abc123")

set_webhook

set_webhook(
    url: str, events: list[str] | None = None
) -> WebhookCreated

Register a webhook. Returns WebhookCreated with signing secret (shown once).

Replaces any existing webhook on this mailbox.

Parameters:

Name Type Description Default
url str

The HTTPS URL to receive webhook POST requests.

required
events list[str] | None

List of event types to subscribe to (e.g. ["message.received"]). Omit to subscribe to all events.

None

Returns:

Type Description
WebhookCreated

WebhookCreated with id, url, secret (one-time),

WebhookCreated

and events.

Raises:

Type Description
MailValidationError

If the URL is invalid.

MailAuthError

If the token is invalid.

Example

wh = mb.set_webhook("https://example.com/hook") print(wh.secret) # save this -- shown only once

webhook

webhook() -> WebhookInfo

Get current webhook config.

Returns:

Type Description
WebhookInfo

WebhookInfo with id, url, events, and created_at.

Raises:

Type Description
MailNotFoundError

If no webhook is configured.

MailAuthError

If the token is invalid.

Example

wh = mb.webhook() print(wh.url, wh.events)

delete_webhook

delete_webhook() -> None

Remove the webhook.

Raises:

Type Description
MailNotFoundError

If no webhook is configured.

MailAuthError

If the token is invalid.

Example

mb.delete_webhook()

info

info() -> MailboxInfo

Get mailbox details.

Returns:

Type Description
MailboxInfo

MailboxInfo with id, address, name, expires_at,

MailboxInfo

and created_at fields.

Raises:

Type Description
MailAuthError

If the token is invalid or expired.

MailNetworkError

On connection failure.

Example

info = mb.info() print(info.address, info.expires_at)

delete

delete() -> None

Delete this mailbox from the server and close the HTTP client.

This permanently destroys the mailbox and all its messages. The Mailbox instance cannot be used after this call.

Raises:

Type Description
MailAuthError

If the token is invalid.

MailNetworkError

On connection failure.

Example

mb.delete() # mailbox is gone

close

close() -> None

Close the HTTP client.

The mailbox remains active on the server. Use delete() to destroy it entirely. Called automatically when used as a context manager.

Example

mb.close()

Models

InboxMessage

Bases: BaseModel

MessageDetail

Bases: BaseModel

SendResult

Bases: BaseModel

ThreadSummary

Bases: BaseModel

ThreadDetail

Bases: BaseModel

AttachmentInfo

Bases: BaseModel

MailboxInfo

Bases: BaseModel

MailboxListItem

Bases: BaseModel

AllowlistEntry

Bases: BaseModel

WebhookCreated

Bases: BaseModel

WebhookInfo

Bases: BaseModel

ProtectedRecipient

Bases: BaseModel

AccountInfo

Bases: BaseModel