Install and Configure the Python SDK
Install primitivedotdev, create a PrimitiveClient with your API key, and send your first email in a few lines of Python.
Install primitivedotdev, create a client with your API key, and send your first outbound email. Requires Python >=3.10.
This page covers the Python SDK. For the Node.js SDK, see Node.js SDK Quickstart; for Go, see Go SDK Quickstart. All three implement the same inbound/outbound email model, so pick by language, not by capability.
- 1
Install the package#
pip install primitivedotdevThe import name is
primitive(distinct from the PyPI package nameprimitivedotdev). - 2
- 3
Send your first email#
import os import primitive client = primitive.client(api_key=os.environ["PRIMITIVE_API_KEY"]) result = client.send( from_email="Support <support@example.com>", to="alice@example.com", subject="Hello", body_text="Hi there", ) print(result.id, result.status, result.queue_id, result.delivery_status) - 4
Verify the result#
A successful call returns a
SendResultdataclass. By defaultsendreturns as soon as Primitive accepts the message for delivery, soresult.delivery_statusisNoneat this point. The printed line looks like this (ids will differ):<send-id> submitted_to_agent <queue-id> NoneTo confirm the actual SMTP outcome (
delivered,bounced,deferred, orwait_timeout) instead of just acceptance, passwait=True; see Sending Email for the full wait-mode contract and delivery-status meanings.
Configuring the client#
primitive.client(...) returns a PrimitiveClient. The constructor accepts:
| Parameter | Purpose |
|---|---|
api_key | Required. Your Primitive API key. |
api_base_url_1 | Primary API host. Defaults to DEFAULT_API_BASE_URL_1. |
api_base_url_2 | Attachment-capable host used for send/reply. Defaults to DEFAULT_API_BASE_URL_2. |
**client_kwargs | Forwarded to the underlying AuthenticatedClient, including timeout in seconds. |
import primitive
client = primitive.client(
api_key="prim_test",
timeout=60.0, # seconds; raise this when you plan to pass wait=True
)
Internally the SDK is a dual-host client: most operations hit api_base_url_1, while send and reply route to api_base_url_2, which accepts larger request bodies for attachments. The split is transparent; you never choose the host yourself, and both defaults point at production.
PrimitiveClient no longer accepts a bare base_url keyword. Passing it raises a TypeError explaining the rename to api_base_url_1 / api_base_url_2.
Per-call and default timeouts#
Every send, reply, and forward call (and their a* async variants) accepts per-call timeout, extra_headers, and idempotency_key keyword arguments. Use client.with_options(...) to change the client-wide defaults without repeating them on every call:
fast = client.with_options(timeout=5.0)
fast.send(
from_email="support@example.com",
to="alice@example.com",
subject="Hello",
body_text="Hi there",
)
Per-call kwargs still win over with_options defaults, and with_options accepts only timeout and extra_headers; idempotency_key is rejected as a client default. Full details live on Client and Request Options.
Next call: receive and reply#
Sending is half the story. primitive.receive(...) turns an inbound webhook into a normalized ReceivedEmail:
import primitive
client = primitive.client(api_key="prim_test")
def webhook_handler(body: bytes, headers: dict[str, str]) -> dict[str, object]:
email = primitive.receive(
body=body,
headers=headers,
secret="whsec_...",
)
client.reply(email, "Thank you for your email.")
return {"ok": True}
The normalized email object and the receive/send/reply/forward flow are explained once, for every SDK, on Inbound and Outbound Email Model. For the Python-specific mechanics of receiving and parsing, see Receiving and Parsing Inbound Email; for sending in depth, see Sending Email.
If an AI coding agent is doing the integration, point it at the Agent Guide instead: install commands, canonical API shapes, and repo conventions on one page.
Next steps#
Configure timeouts, dual-host base URLs, and per-call overrides with with_options.
Sending EmailControl idempotency and wait-for-delivery semantics, and interpret delivery status.
Receiving and Parsing Inbound EmailTurn a raw inbound webhook into a normalized ReceivedEmail object.
Inbound and Outbound Email ModelThe normalized email object and wait-mode delivery statuses shared across every SDK.
Was this page helpful?