> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://developers.brevo.com/guides/python/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.brevo.com/_mcp/server. # Python SDK ## Overview The Brevo Python SDK (`brevo-python`) is a fully typed client library for the Brevo API. It provides: * A unified `Brevo` client with namespaced service clients * Native async support via `AsyncBrevo` * Pydantic-based typed models with full type annotations * Automatic retries with exponential backoff * Raw response access with headers and status codes * Custom `httpx` client support for proxies and mTLS [![PyPI](https://img.shields.io/pypi/dm/brevo-python)](https://pypi.org/project/brevo-python/) > **Warning** > > Version 5.0 introduces breaking changes versus v4.x. v4.x remains supported and continues to receive wire-compatibility fixes — see the [changelog](/docs/sdks-libraries/python-changelog) for the list of changes and the README for migration steps. ## Requirements * Python 3.8+ * `httpx` >= 0.21.2 * `pydantic` >= 1.9.2 * `typing_extensions` >= 4.0.0 ## Installation ```bash pip install brevo-python ``` ## Quick start Initialize the client and send your first email: **`quick_start.py`** ```python title="quick_start.py" from brevo import Brevo from brevo.transactional_emails import ( SendTransacEmailRequestSender, SendTransacEmailRequestToItem, ) client = Brevo(api_key="your-api-key") result = client.transactional_emails.send_transac_email( subject="Hello from Brevo!", html_content="

Hello,

This is my first transactional email.

", sender=SendTransacEmailRequestSender( name="Alex from Brevo", email="hello@brevo.com", ), to=[ SendTransacEmailRequestToItem( email="johndoe@example.com", name="John Doe", ) ], ) print("Email sent. Message ID:", result.message_id) ``` ## Configuration Pass keyword arguments to the constructor to configure the client: **`configuration.py`** ```python title="configuration.py" from brevo import Brevo client = Brevo( api_key="your-api-key", timeout=30.0, ) ``` ### Constructor parameters | Parameter | Type | Default | Description | | ------------------ | --------------------- | -------- | -------------------------------------------------- | | `api_key` | `str` | Required | Your Brevo API key | | `timeout` | `float` | `60.0` | Default request timeout in seconds | | `base_url` | `str` | `None` | Override the default API base URL | | `follow_redirects` | `bool` | `True` | Follow HTTP redirects | | `httpx_client` | `httpx.Client` | `None` | Custom httpx client instance | | `headers` | `dict` | `None` | Additional default headers sent with every request | | `logging` | `LogConfig \| Logger` | `None` | Logging configuration (see [Logging](#logging)) | ## Async client Use `AsyncBrevo` for non-blocking calls. Pass `httpx.AsyncClient` instead of `httpx.Client` when providing a custom HTTP client: **`async_client.py`** ```python title="async_client.py" import asyncio from brevo import AsyncBrevo from brevo.transactional_emails import ( SendTransacEmailRequestSender, SendTransacEmailRequestToItem, ) client = AsyncBrevo(api_key="your-api-key") async def main() -> None: result = await client.transactional_emails.send_transac_email( subject="Hello from Brevo!", html_content="

Hello!

", sender=SendTransacEmailRequestSender( name="Alex from Brevo", email="hello@brevo.com", ), to=[ SendTransacEmailRequestToItem( email="johndoe@example.com", name="John Doe", ) ], ) print("Email sent. Message ID:", result.message_id) asyncio.run(main()) ``` ## Error handling The SDK raises `ApiError` (or a typed subclass) for non-2xx HTTP responses: **`error_handling.py`** ```python title="error_handling.py" from brevo import Brevo from brevo.core.api_error import ApiError client = Brevo(api_key="your-api-key") try: client.transactional_emails.send_transac_email(...) except ApiError as e: print(e.status_code) print(e.body) ``` ### Error classes | Status code | Class | | ----------- | --------------------------- | | `400` | `BadRequestError` | | `401` | `UnauthorizedError` | | `402` | `PaymentRequiredError` | | `403` | `ForbiddenError` | | `404` | `NotFoundError` | | `405` | `MethodNotAllowedError` | | `409` | `ConflictError` | | `412` | `PreconditionFailedError` | | `415` | `UnsupportedMediaTypeError` | | `422` | `UnprocessableEntityError` | | `424` | `FailedDependencyError` | | `429` | `TooManyRequestsError` | | `500` | `InternalServerError` | All `ApiError` instances expose: * `status_code` — HTTP status code * `body` — Parsed response body * `headers` — Response headers ## Retries Automatic retries with exponential backoff are enabled by default (2 retries). Configure at the client or request level: **`retries.py`** ```python title="retries.py" from brevo import Brevo # Client-level (not directly supported — use request_options per request) client = Brevo(api_key="your-api-key") # Request-level client.transactional_emails.send_transac_email( ..., request_options={"max_retries": 3}, ) ``` ### Retry behavior * **Retryable status codes**: `408`, `429`, `5xx` * **Backoff**: Exponential with jitter * **Disable**: Set `max_retries: 0` in `request_options` ## Timeouts Default timeout is 60 seconds. Configure at the client or request level: **`timeouts.py`** ```python title="timeouts.py" from brevo import Brevo # Client-level client = Brevo( api_key="your-api-key", timeout=30.0, ) # Request-level client.transactional_emails.send_transac_email( ..., request_options={"timeout_in_seconds": 10}, ) ``` ### Recommended timeout values | Use case | Timeout | | ----------------------- | ------------------ | | Standard API calls | `30–60s` (default) | | Quick operations | `10–15s` | | Bulk operations | `120–300s` | | Real-time / low-latency | `5–10s` | ## Request options All service methods accept a `request_options` dict as the final keyword argument: | Option | Type | Description | | ----------------------------- | ------ | ----------------------------------------- | | `timeout_in_seconds` | `int` | Override timeout for this request | | `max_retries` | `int` | Override max retries for this request | | `additional_headers` | `dict` | Merge additional headers into the request | | `additional_query_parameters` | `dict` | Add query parameters to the request | | `additional_body_parameters` | `dict` | Add body parameters to the request | **`request_options.py`** ```python title="request_options.py" client.transactional_emails.send_transac_email( ..., request_options={ "timeout_in_seconds": 10, "max_retries": 1, "additional_headers": {"X-Custom-Header": "custom-value"}, }, ) ``` ## Raw response access Access response headers and status code via `.with_raw_response`: **`raw_response.py`** ```python title="raw_response.py" from brevo import Brevo client = Brevo(api_key="your-api-key") response = client.transactional_emails.with_raw_response.send_transac_email(...) print(response.status_code) print(response.headers) print(response.data) ``` ## Logging The SDK has a built-in, opt-in logger you can plug your own implementation into. Pass a `LogConfig` dict (or a pre-built `Logger`) via the `logging` constructor option. > **Warning** > > By default the SDK is **silent**: nothing is logged unless you set `silent=False`. This keeps integration changes from accidentally producing log volume in production. **`logging_basic.py`** ```python title="logging_basic.py" from brevo import Brevo from brevo.core.logging import ConsoleLogger client = Brevo( api_key="your-api-key", logging={ "level": "debug", # "debug" | "info" | "warn" | "error" "logger": ConsoleLogger(), # built-in; writes to stdlib `logging` under the "fern" logger "silent": False, # required to actually emit logs }, ) ``` ### `LogConfig` fields | Field | Type | Default | Description | | -------- | ---------------------------------------- | ----------------- | ----------------------------------------------------------------------- | | `level` | `"debug" \| "info" \| "warn" \| "error"` | `"info"` | Minimum level that gets forwarded to the logger | | `logger` | `ILogger` | `ConsoleLogger()` | Logger implementation — any object conforming to the `ILogger` protocol | | `silent` | `bool` | `True` | When `True`, all logging is suppressed regardless of `level` | ### Custom logger Implement the `ILogger` protocol (a `typing.Protocol` with `debug`, `info`, `warn`, `error` methods) to forward to any logging library — Python's stdlib `logging`, `structlog`, `loguru`, or your own sink. **`custom_logger.py`** ```python title="custom_logger.py" import logging from brevo import Brevo from brevo.core.logging import ILogger logging.basicConfig(level=logging.DEBUG) class StdlibLogger(ILogger): def __init__(self, name: str = "brevo") -> None: self._log = logging.getLogger(name) def debug(self, message: str, **kwargs) -> None: self._log.debug(message, extra=kwargs) def info(self, message: str, **kwargs) -> None: self._log.info(message, extra=kwargs) def warn(self, message: str, **kwargs) -> None: self._log.warning(message, extra=kwargs) def error(self, message: str, **kwargs) -> None: self._log.error(message, extra=kwargs) client = Brevo( api_key="your-api-key", logging={"level": "debug", "logger": StdlibLogger(), "silent": False}, ) ``` ### Integrations #### structlog ```python import structlog from brevo import Brevo from brevo.core.logging import ILogger class StructlogLogger(ILogger): def __init__(self) -> None: self._log = structlog.get_logger("brevo") def debug(self, message, **kwargs): self._log.debug(message, **kwargs) def info(self, message, **kwargs): self._log.info(message, **kwargs) def warn(self, message, **kwargs): self._log.warning(message, **kwargs) def error(self, message, **kwargs): self._log.error(message, **kwargs) client = Brevo( api_key="your-api-key", logging={"level": "info", "logger": StructlogLogger(), "silent": False}, ) ``` #### loguru ```python from loguru import logger from brevo import Brevo from brevo.core.logging import ILogger class LoguruLogger(ILogger): def debug(self, message, **kwargs): logger.bind(**kwargs).debug(message) def info(self, message, **kwargs): logger.bind(**kwargs).info(message) def warn(self, message, **kwargs): logger.bind(**kwargs).warning(message) def error(self, message, **kwargs): logger.bind(**kwargs).error(message) client = Brevo( api_key="your-api-key", logging={"level": "debug", "logger": LoguruLogger(), "silent": False}, ) ``` #### Reusing a pre-built Logger Build a `Logger` once and reuse it across `Brevo` and `AsyncBrevo` instances: ```python from brevo import Brevo, AsyncBrevo from brevo.core.logging import Logger, ConsoleLogger shared = Logger(level="info", logger=ConsoleLogger(), silent=False) sync_client = Brevo(api_key="your-api-key", logging=shared) async_client = AsyncBrevo(api_key="your-api-key", logging=shared) ``` > **Note** > > The default `ConsoleLogger` uses Python's stdlib `logging` module under the logger name `"fern"`. If you only need to filter or reformat output, configuring that logger via `logging.getLogger("fern")` may be enough — you don't always need a custom `ILogger`. ## Custom HTTP client Override the default `httpx` client for proxies, custom transports, or mTLS: **`custom_http_client.py`** ```python title="custom_http_client.py" import httpx from brevo import Brevo client = Brevo( api_key="your-api-key", httpx_client=httpx.Client( proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0"), ), ) ``` ### Common integrations #### Async with custom client ```python import httpx from brevo import AsyncBrevo client = AsyncBrevo( api_key="your-api-key", httpx_client=httpx.AsyncClient( proxy="http://my.test.proxy.example.com", ), ) ``` #### Custom timeout and transport ```python import httpx from brevo import Brevo client = Brevo( api_key="your-api-key", httpx_client=httpx.Client( timeout=httpx.Timeout(120.0, connect=10.0), transport=httpx.HTTPTransport(retries=3), ), ) ``` #### With event hooks ```python import httpx from brevo import Brevo def log_request(request: httpx.Request) -> None: print(f"→ {request.method} {request.url}") def log_response(response: httpx.Response) -> None: print(f"← {response.status_code}") client = Brevo( api_key="your-api-key", httpx_client=httpx.Client( event_hooks={"request": [log_request], "response": [log_response]}, ), ) ``` ## Available services The `Brevo` and `AsyncBrevo` clients expose the following service namespaces: | Property | Description | | ------------------------- | ----------------------------------------------------------- | | `transactional_emails` | Send emails, manage templates, blocked contacts and domains | | `transactional_sms` | Send SMS messages and view delivery statistics | | `transactional_whats_app` | Send WhatsApp messages and view event reports | | `sms_templates` | Manage SMS templates | | `contacts` | Manage contacts, lists, folders, attributes and segments | | `email_campaigns` | Create and manage email marketing campaigns | | `sms_campaigns` | Create and manage SMS marketing campaigns | | `whats_app_campaigns` | Create and manage WhatsApp campaigns and templates | | `companies` | Manage CRM companies | | `deals` | Manage CRM deals and pipelines | | `tasks` | Manage CRM tasks | | `notes` | Manage CRM notes | | `files` | Upload and manage CRM files | | `conversations` | Manage conversation messages and automated messages | | `ecommerce` | Manage products, categories, orders and attribution | | `coupons` | Manage coupon collections and coupons | | `payments` | Create and manage payment requests | | `event` | Track custom events | | `webhooks` | Manage webhooks | | `senders` | Manage senders and IPs | | `domains` | Manage and authenticate domains | | `account` | Retrieve account information and activity logs | | `inbound_parsing` | Retrieve inbound email events and attachments | | `custom_objects` | Manage custom object records | | `external_feeds` | Manage external RSS feeds | | `master_account` | Manage sub-accounts and groups (enterprise) | | `user` | Manage users and permissions | | `process` | Retrieve background process status | | `program` | Manage loyalty programs | | `balance` | Manage loyalty balances and transactions | | `reward` | Manage loyalty rewards and vouchers | | `tier` | Manage loyalty tiers and tier groups | ## Migration from v1.x ### Key changes | Area | v1.x (`brevo_python`) | v4.x (`brevo`) | | -------- | ---------------------------------------- | --------------------------------------- | | Module | `import brevo_python` | `from brevo import Brevo` | | Client | `AccountApi(ApiClient(config))` | `Brevo(api_key="...")` | | Config | `Configuration()` + `api_key['api-key']` | Constructor parameter `api_key` | | Errors | `ApiException` | `ApiError` with `.status_code`, `.body` | | HTTP | `urllib3` | `httpx` | | Async | Not available | `AsyncBrevo` | | Retries | Not built-in | Automatic with exponential backoff | | Timeouts | Manual | 60s default, configurable | | Python | 2.7, 3.4+ | 3.8+ | ### Migration example **`v1_example.py`** ```python title="v1_example.py" # v1.x import brevo_python from brevo_python.rest import ApiException configuration = brevo_python.Configuration() configuration.api_key['api-key'] = 'YOUR_API_KEY' api_instance = brevo_python.AccountApi( brevo_python.ApiClient(configuration) ) account = api_instance.get_account() ``` **`v4_example.py`** ```python title="v4_example.py" # v4.x from brevo import Brevo client = Brevo(api_key="YOUR_API_KEY") account = client.account.get_account() ``` ## Resources * [GitHub Repository](https://github.com/getbrevo/brevo-python/tree/main) * [PyPI Package](https://pypi.org/project/brevo-python/) * [API Reference](https://developers.brevo.com/reference) * [Support](mailto:support@brevo.com) > Learn how to integrate the Brevo API into your Python applications. ## Docs - [Python SDK Changelog](https://developers.brevo.com/guides/python/changelog.md): Release history for the brevo-python SDK.