Python SDK

Learn how to integrate the Brevo API into your Python applications.

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

Version 5.0 introduces breaking changes versus v4.x. v4.x remains supported and continues to receive wire-compatibility fixes — see the 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

$pip install brevo-python

Quick start

Initialize the client and send your first email:

quick_start.py
1from brevo import Brevo
2from brevo.transactional_emails import (
3 SendTransacEmailRequestSender,
4 SendTransacEmailRequestToItem,
5)
6
7client = Brevo(api_key="your-api-key")
8
9result = client.transactional_emails.send_transac_email(
10 subject="Hello from Brevo!",
11 html_content="<html><body><p>Hello,</p><p>This is my first transactional email.</p></body></html>",
12 sender=SendTransacEmailRequestSender(
13 name="Alex from Brevo",
14 email="hello@brevo.com",
15 ),
16 to=[
17 SendTransacEmailRequestToItem(
18 email="johndoe@example.com",
19 name="John Doe",
20 )
21 ],
22)
23
24print("Email sent. Message ID:", result.message_id)

Configuration

Pass keyword arguments to the constructor to configure the client:

configuration.py
1from brevo import Brevo
2
3client = Brevo(
4 api_key="your-api-key",
5 timeout=30.0,
6)

Constructor parameters

ParameterTypeDefaultDescription
api_keystrRequiredYour Brevo API key
timeoutfloat60.0Default request timeout in seconds
base_urlstrNoneOverride the default API base URL
follow_redirectsboolTrueFollow HTTP redirects
httpx_clienthttpx.ClientNoneCustom httpx client instance
headersdictNoneAdditional default headers sent with every request
loggingLogConfig | LoggerNoneLogging configuration (see 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
1import asyncio
2from brevo import AsyncBrevo
3from brevo.transactional_emails import (
4 SendTransacEmailRequestSender,
5 SendTransacEmailRequestToItem,
6)
7
8client = AsyncBrevo(api_key="your-api-key")
9
10async def main() -> None:
11 result = await client.transactional_emails.send_transac_email(
12 subject="Hello from Brevo!",
13 html_content="<html><body><p>Hello!</p></body></html>",
14 sender=SendTransacEmailRequestSender(
15 name="Alex from Brevo",
16 email="hello@brevo.com",
17 ),
18 to=[
19 SendTransacEmailRequestToItem(
20 email="johndoe@example.com",
21 name="John Doe",
22 )
23 ],
24 )
25 print("Email sent. Message ID:", result.message_id)
26
27asyncio.run(main())

Error handling

The SDK raises ApiError (or a typed subclass) for non-2xx HTTP responses:

error_handling.py
1from brevo import Brevo
2from brevo.core.api_error import ApiError
3
4client = Brevo(api_key="your-api-key")
5
6try:
7 client.transactional_emails.send_transac_email(...)
8except ApiError as e:
9 print(e.status_code)
10 print(e.body)

Error classes

Status codeClass
400BadRequestError
401UnauthorizedError
402PaymentRequiredError
403ForbiddenError
404NotFoundError
405MethodNotAllowedError
409ConflictError
412PreconditionFailedError
415UnsupportedMediaTypeError
422UnprocessableEntityError
424FailedDependencyError
429TooManyRequestsError
500InternalServerError

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
1from brevo import Brevo
2
3# Client-level (not directly supported — use request_options per request)
4client = Brevo(api_key="your-api-key")
5
6# Request-level
7client.transactional_emails.send_transac_email(
8 ...,
9 request_options={"max_retries": 3},
10)

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
1from brevo import Brevo
2
3# Client-level
4client = Brevo(
5 api_key="your-api-key",
6 timeout=30.0,
7)
8
9# Request-level
10client.transactional_emails.send_transac_email(
11 ...,
12 request_options={"timeout_in_seconds": 10},
13)
Use caseTimeout
Standard API calls30–60s (default)
Quick operations10–15s
Bulk operations120–300s
Real-time / low-latency5–10s

Request options

All service methods accept a request_options dict as the final keyword argument:

OptionTypeDescription
timeout_in_secondsintOverride timeout for this request
max_retriesintOverride max retries for this request
additional_headersdictMerge additional headers into the request
additional_query_parametersdictAdd query parameters to the request
additional_body_parametersdictAdd body parameters to the request
request_options.py
1client.transactional_emails.send_transac_email(
2 ...,
3 request_options={
4 "timeout_in_seconds": 10,
5 "max_retries": 1,
6 "additional_headers": {"X-Custom-Header": "custom-value"},
7 },
8)

Raw response access

Access response headers and status code via .with_raw_response:

raw_response.py
1from brevo import Brevo
2
3client = Brevo(api_key="your-api-key")
4
5response = client.transactional_emails.with_raw_response.send_transac_email(...)
6
7print(response.status_code)
8print(response.headers)
9print(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.

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
1from brevo import Brevo
2from brevo.core.logging import ConsoleLogger
3
4client = Brevo(
5 api_key="your-api-key",
6 logging={
7 "level": "debug", # "debug" | "info" | "warn" | "error"
8 "logger": ConsoleLogger(), # built-in; writes to stdlib `logging` under the "fern" logger
9 "silent": False, # required to actually emit logs
10 },
11)

LogConfig fields

FieldTypeDefaultDescription
level"debug" | "info" | "warn" | "error""info"Minimum level that gets forwarded to the logger
loggerILoggerConsoleLogger()Logger implementation — any object conforming to the ILogger protocol
silentboolTrueWhen 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
1import logging
2from brevo import Brevo
3from brevo.core.logging import ILogger
4
5logging.basicConfig(level=logging.DEBUG)
6
7class StdlibLogger(ILogger):
8 def __init__(self, name: str = "brevo") -> None:
9 self._log = logging.getLogger(name)
10
11 def debug(self, message: str, **kwargs) -> None: self._log.debug(message, extra=kwargs)
12 def info(self, message: str, **kwargs) -> None: self._log.info(message, extra=kwargs)
13 def warn(self, message: str, **kwargs) -> None: self._log.warning(message, extra=kwargs)
14 def error(self, message: str, **kwargs) -> None: self._log.error(message, extra=kwargs)
15
16client = Brevo(
17 api_key="your-api-key",
18 logging={"level": "debug", "logger": StdlibLogger(), "silent": False},
19)

Integrations

1import structlog
2from brevo import Brevo
3from brevo.core.logging import ILogger
4
5class StructlogLogger(ILogger):
6 def __init__(self) -> None:
7 self._log = structlog.get_logger("brevo")
8
9 def debug(self, message, **kwargs): self._log.debug(message, **kwargs)
10 def info(self, message, **kwargs): self._log.info(message, **kwargs)
11 def warn(self, message, **kwargs): self._log.warning(message, **kwargs)
12 def error(self, message, **kwargs): self._log.error(message, **kwargs)
13
14client = Brevo(
15 api_key="your-api-key",
16 logging={"level": "info", "logger": StructlogLogger(), "silent": False},
17)
1from loguru import logger
2from brevo import Brevo
3from brevo.core.logging import ILogger
4
5class LoguruLogger(ILogger):
6 def debug(self, message, **kwargs): logger.bind(**kwargs).debug(message)
7 def info(self, message, **kwargs): logger.bind(**kwargs).info(message)
8 def warn(self, message, **kwargs): logger.bind(**kwargs).warning(message)
9 def error(self, message, **kwargs): logger.bind(**kwargs).error(message)
10
11client = Brevo(
12 api_key="your-api-key",
13 logging={"level": "debug", "logger": LoguruLogger(), "silent": False},
14)

Build a Logger once and reuse it across Brevo and AsyncBrevo instances:

1from brevo import Brevo, AsyncBrevo
2from brevo.core.logging import Logger, ConsoleLogger
3
4shared = Logger(level="info", logger=ConsoleLogger(), silent=False)
5
6sync_client = Brevo(api_key="your-api-key", logging=shared)
7async_client = AsyncBrevo(api_key="your-api-key", logging=shared)

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
1import httpx
2from brevo import Brevo
3
4client = Brevo(
5 api_key="your-api-key",
6 httpx_client=httpx.Client(
7 proxy="http://my.test.proxy.example.com",
8 transport=httpx.HTTPTransport(local_address="0.0.0.0"),
9 ),
10)

Common integrations

1import httpx
2from brevo import AsyncBrevo
3
4client = AsyncBrevo(
5 api_key="your-api-key",
6 httpx_client=httpx.AsyncClient(
7 proxy="http://my.test.proxy.example.com",
8 ),
9)
1import httpx
2from brevo import Brevo
3
4client = Brevo(
5 api_key="your-api-key",
6 httpx_client=httpx.Client(
7 timeout=httpx.Timeout(120.0, connect=10.0),
8 transport=httpx.HTTPTransport(retries=3),
9 ),
10)
1import httpx
2from brevo import Brevo
3
4def log_request(request: httpx.Request) -> None:
5 print(f"→ {request.method} {request.url}")
6
7def log_response(response: httpx.Response) -> None:
8 print(f"← {response.status_code}")
9
10client = Brevo(
11 api_key="your-api-key",
12 httpx_client=httpx.Client(
13 event_hooks={"request": [log_request], "response": [log_response]},
14 ),
15)

Available services

The Brevo and AsyncBrevo clients expose the following service namespaces:

PropertyDescription
transactional_emailsSend emails, manage templates, blocked contacts and domains
transactional_smsSend SMS messages and view delivery statistics
transactional_whats_appSend WhatsApp messages and view event reports
sms_templatesManage SMS templates
contactsManage contacts, lists, folders, attributes and segments
email_campaignsCreate and manage email marketing campaigns
sms_campaignsCreate and manage SMS marketing campaigns
whats_app_campaignsCreate and manage WhatsApp campaigns and templates
companiesManage CRM companies
dealsManage CRM deals and pipelines
tasksManage CRM tasks
notesManage CRM notes
filesUpload and manage CRM files
conversationsManage conversation messages and automated messages
ecommerceManage products, categories, orders and attribution
couponsManage coupon collections and coupons
paymentsCreate and manage payment requests
eventTrack custom events
webhooksManage webhooks
sendersManage senders and IPs
domainsManage and authenticate domains
accountRetrieve account information and activity logs
inbound_parsingRetrieve inbound email events and attachments
custom_objectsManage custom object records
external_feedsManage external RSS feeds
master_accountManage sub-accounts and groups (enterprise)
userManage users and permissions
processRetrieve background process status
programManage loyalty programs
balanceManage loyalty balances and transactions
rewardManage loyalty rewards and vouchers
tierManage loyalty tiers and tier groups

Migration from v1.x

Key changes

Areav1.x (brevo_python)v4.x (brevo)
Moduleimport brevo_pythonfrom brevo import Brevo
ClientAccountApi(ApiClient(config))Brevo(api_key="...")
ConfigConfiguration() + api_key['api-key']Constructor parameter api_key
ErrorsApiExceptionApiError with .status_code, .body
HTTPurllib3httpx
AsyncNot availableAsyncBrevo
RetriesNot built-inAutomatic with exponential backoff
TimeoutsManual60s default, configurable
Python2.7, 3.4+3.8+

Migration example

1# v1.x
2import brevo_python
3from brevo_python.rest import ApiException
4
5configuration = brevo_python.Configuration()
6configuration.api_key['api-key'] = 'YOUR_API_KEY'
7
8api_instance = brevo_python.AccountApi(
9 brevo_python.ApiClient(configuration)
10)
11account = api_instance.get_account()

Resources