---
title: "Install and Configure the Python SDK"
canonical: "https://test.abhinandan.one/python-sdk-quickstart"
markdown_url: "https://test.abhinandan.one/python-sdk-quickstart.md"
publisher: "Primitive SDKs"
kind: "quickstart"
content_type: "reference"
category: "Python SDK"
description: "Install the primitivedotdev package, set PRIMITIVE_API_KEY, and send your first outbound email with client.send in under five minutes."
keywords: ["pip install primitivedotdev", "primitive.client", "PrimitiveClient", "PRIMITIVE_API_KEY", "api_base_url_1 api_base_url_2", "with_options timeout"]
last_modified: "2026-08-11T18:54:59.307934+00:00"
published_at: "2026-08-11T18:54:59.021182+00:00"
source_files:
  - "sdk-python/README.md"
sections:
  - {anchor: "step-install-the-package", title: "Install the package"}
  - {anchor: "step-set-your-api-key", title: "Set your API key"}
  - {anchor: "step-send-your-first-email", title: "Send your first email"}
  - {anchor: "step-verify-the-result", title: "Verify the result"}
  - {anchor: "configuring-the-client", title: "Configuring the client"}
  - {anchor: "per-call-and-default-timeouts", title: "Per-call and default timeouts"}
  - {anchor: "next-call-receive-and-reply", title: "Next call: receive and reply"}
  - {anchor: "next-steps", title: "Next steps"}
---

> Documentation index: https://test.abhinandan.one/llms.txt

# 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`.

> **Note:** This page covers the Python SDK. For the Node.js SDK, see [Node.js SDK Quickstart](https://test.abhinandan.one/node-sdk-quickstart.md); for Go, see [Go SDK Quickstart](https://test.abhinandan.one/go-sdk-quickstart.md). All three implement the same [inbound/outbound email model](https://test.abhinandan.one/email-model.md), so pick by language, not by capability.

### 1. Install the package

```bash
pip install primitivedotdev
```

The import name is `primitive` (distinct from the PyPI package name `primitivedotdev`).

### 2. Set your API key

Get a key from your [dashboard](https://primitive.dev) and export it:

```bash
export PRIMITIVE_API_KEY=prim_test
```

Read it from the environment when constructing the client, rather than hardcoding it:

```python
import os
import primitive

client = primitive.client(api_key=os.environ["PRIMITIVE_API_KEY"])
```

### 3. Send your first email

```python
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 `SendResult` dataclass. By default `send` returns as soon as Primitive accepts the message for delivery, so `result.delivery_status` is `None` at this point. The printed line looks like this (ids will differ):

```text
<send-id> submitted_to_agent <queue-id> None
```

To confirm the actual SMTP outcome (`delivered`, `bounced`, `deferred`, or `wait_timeout`) instead of just acceptance, pass `wait=True`; see [Sending Email](https://test.abhinandan.one/python-send-email.md) 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. |

```python
import primitive

client = primitive.client(
    api_key="prim_test",
    timeout=60.0,  # seconds; raise this when you plan to pass wait=True
)
```

> **Note:** 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.

> **Warning:** `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:

```python
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](https://test.abhinandan.one/python-client-options.md).

## Next call: receive and reply

Sending is half the story. `primitive.receive(...)` turns an inbound webhook into a normalized `ReceivedEmail`:

```python
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](https://test.abhinandan.one/email-model.md). For the Python-specific mechanics of receiving and parsing, see [Receiving and Parsing Inbound Email](https://test.abhinandan.one/python-receive-email.md); for sending in depth, see [Sending Email](https://test.abhinandan.one/python-send-email.md).

> **Tip:** If an AI coding agent is doing the integration, point it at the [Agent Guide](https://test.abhinandan.one/agent-guide.md) instead: install commands, canonical API shapes, and repo conventions on one page.
