Sync vs Async Execution Flow
Relevant source files
The following files were used as context for generating this wiki page:
The Resend Python SDK supports both synchronous and asynchronous execution flows for interacting with the Resend API. The library provides dual implementations for all major resource modules (Emails, Automations, Domains, etc.), allowing you to choose between standard blocking calls or non-blocking coroutines depending on your application's requirements.
Sources: resend/init.py:216-240, setup.py:27-29
Execution Architecture
The SDK differentiates between execution styles through distinct request handler classes and client implementations. Synchronous operations use the RequestsClient by default, while asynchronous operations utilize an AsyncHTTPClient interface, typically implemented by HTTPXClient when the httpx library is available.
Client Detection and Configuration
The resend package initializes default clients during import. It sets a default_http_client for synchronous requests and attempts to auto-detect an asynchronous client if httpx is installed.
| Component | Sync Implementation | Async Implementation | Requirement |
|---|---|---|---|
| HTTP Client | RequestsClient | HTTPXClient | httpx (for async) |
| Request Handler | Request | AsyncRequest | None |
| Execution Method | perform() | await perform() | Python 3.7+ |
Sources: resend/init.py:220-238, setup.py:27-29, tests/request_test.py:34-40
Synchronous Execution Flow
Synchronous flow follows a blocking pattern where the execution thread waits for the API response. This is the default behavior for methods like resend.Emails.send() or resend.Automations.create().
Synchronous Sequence
The following diagram illustrates the internal flow when a user calls a synchronous resource method.
The Request.perform() method handles the actual dispatch through the default_http_client and manages error decoding for the synchronous flow.
Sources: resend/request.py, tests/request_test.py:53-70, examples/automations.py:12-25
Asynchronous Execution Flow
Asynchronous flow uses Python's asyncio framework. Resource methods are suffixed with _async (e.g., create_async, list_async) and must be awaited within an asynchronous context.
Asynchronous Sequence
The asynchronous flow mirrors the synchronous one but uses non-blocking calls and an AsyncHTTPClient.
Error Handling and Response Decoding
Both execution flows share logic for processing API responses and raising exceptions, though their implementations are contained within Request and AsyncRequest respectively.
Handling Non-JSON Responses
When the API returns non-JSON content (e.g., HTML error pages or empty bodies), both handlers preserve the HTTP status code and headers while wrapping the message in a ResendError.
- Sync:
Request.perform()catches decoding errors and raisesApplicationErrororResendError. - Async:
AsyncRequest.perform()performs identical validation within anawaitblock.
# Synchronous Error Handling Example
try:
resend.Templates.create(params)
except resend.exceptions.ResendError as e:
print(f"Error {e.code}: {e.message}")
# Asynchronous Error Handling Example
try:
await resend.Templates.create_async(params)
except resend.exceptions.ResendError as e:
print(f"Error {e.code}: {e.message}")
Sources: tests/request_test.py:22-50, tests/request_test.py:100-115, resend/async_request.py
Usage Comparison
The following table summarizes the implementation differences between the two flows.
| Feature | Synchronous | Asynchronous |
|---|---|---|
| Method Naming | resource.method() | await resource.method_async() |
| Client Type | resend.default_http_client | resend.default_async_http_client |
| Dependency | requests | httpx (optional/extra) |
| Best For | Scripts, CLI tools, simple apps | Web frameworks (FastAPI, Django), high-concurrency |
Sources: resend/init.py:220-240, examples/automations.py:12-25, examples/async/automations_async.py:13-30, setup.py:27-29
Summary
The Resend Python SDK provides a flexible execution model. The synchronous flow relies on the requests library for straightforward blocking operations. The asynchronous flow uses httpx and asyncio to enable non-blocking I/O, which is critical for performance in modern asynchronous Python applications. Both flows utilize centralized request handler classes (Request and AsyncRequest) to ensure consistent header management, idempotency handling, and error processing across the SDK.