Skip to content

Repository files navigation

MailerSend Python SDK

MIT licensed

Table of Contents

Installation

pip install mailersend

Requirements

Authentication

The SDK supports multiple authentication methods:

Environment Variable (Recommended)

Option 1: System Environment Variable

Set your API key as a system environment variable:

export MAILERSEND_API_KEY="your-api-key"

Then initialize the client:

frommailersendimportMailerSendClient# Automatically uses MAILERSEND_API_KEY environment variablems=MailerSendClient()

Option 2: Using .env File

For development, you can use a .env file. First install python-dotenv:

pip install python-dotenv

Create a .env file in your project root:

# .env
MAILERSEND_API_KEY=your-api-key

Then load it in your Python code:

frommailersendimportMailerSendClientfromdotenvimportload_dotenv# Load environment variables from .env fileload_dotenv()
# Client automatically uses the loaded MAILERSEND_API_KEYms=MailerSendClient()

Direct API Key

frommailersendimportMailerSendClientms=MailerSendClient(api_key="your-api-key")

SDK Architecture

The MailerSend Python SDK v2 introduces a modern, clean architecture that follows industry best practices. Both a synchronous client (MailerSendClient) and an async client (AsyncMailerSendClient) are available — they share the same resources, builders, and models.

Builder Pattern

The SDK uses the builder pattern for constructing API requests. This provides a fluent, readable interface for setting parameters:

frommailersendimportMailerSendClientfrommailersendimportSmsRecipientsBuilderms=MailerSendClient()
# Build a request using the fluent builder patternrequest= (SmsRecipientsBuilder()
.sms_number_id("sms123")
.status("active")
.page(1)
.limit(25)
.build_list_request())
# Execute the requestresponse=ms.sms_recipients.list_sms_recipients(request)

Resource Classes

Each API endpoint group has its own resource class that provides clean method interfaces:

# Access different API resourcesms.sms_recipients# SMS Recipients operationsms.sms_webhooks# SMS Webhooks operationsms.sms_inbounds# SMS Inbound Routing operationsms.email# Email operationsms.domains# Domain operations# ... and more

Request and Response Models

All data is validated using Pydantic models ensuring type safety and data integrity:

# All responses are strongly typedresponse=ms.sms_recipients.get_sms_recipient(request)
print(response.id) # Validated stringprint(response.number) # Validated phone numberprint(response.created_at) # Validated datetime object

Async Support

The SDK ships an async client built on httpx for use in async applications (FastAPI, asyncio, etc.). It exposes the exact same resource namespaces and builder/model interfaces as the sync client.

frommailersendimportAsyncMailerSendClient# Recommended — use as an async context managerasyncwithAsyncMailerSendClient() asclient:
response=awaitclient.emails.send(email_request)
print(response["id"])

The async client accepts the same configuration parameters:

client=AsyncMailerSendClient(
api_key="your_api_key", # or set MAILERSEND_API_KEY env vartimeout=30,
max_retries=3,
debug=True,
)

Retries, rate-limit handling, and the error exception hierarchy (AuthenticationError, RateLimitExceeded, ServerError, etc.) behave identically to the sync client.

Response Data Access

The MailerSend SDK provides flexible ways to access and work with API response data. All API calls return a unified APIResponse object that supports multiple access patterns and data formats.

Multiple Access Patterns

Dict-like Access

Access response data using dictionary-style syntax:

frommailersendimportMailerSendClientfrommailersendimportSmsRecipientsBuilderms=MailerSendClient()
request=SmsRecipientsBuilder().sms_recipient_id("recipient-123").build_get_request()
response=ms.sms_recipients.get_sms_recipient(request)
# Dict-style accessrecipient_id=response["data"]["id"]
phone_number=response["data"]["number"]
status=response["data"]["status"]
# Nested accessif"sms"inresponse["data"]:
latest_sms=response["data"]["sms"][0]["text"]
# Check if key existsif"error"inresponse:
error_message=response['error']

Attribute Access

Access data using dot notation for cleaner code:

# Attribute-style access (most convenient)recipient_id=response.idphone_number=response.numberstatus=response.status# Nested attribute access for complex dataifhasattr(response, 'sms') andresponse.sms:
latest_sms=response.sms[0].text

Safe Access with Defaults

Use the get() method for safe access with fallback values:

# Safe access with defaultsrecipient_id=response.get("data", {}).get("id", "unknown")
error_message=response.get("error", "No error")
# Safe nested accessmeta_info=response.get("meta", {})
total_count=meta_info.get("total", 0)
current_page=meta_info.get("page", 1)

Handling Method Name Conflicts

When response data contains fields that conflict with built-in methods, use the data_ prefix:

# If response contains fields like 'items', 'keys', 'values', etc.response_data= {
"items": [{"id": 1, "name": "Item 1"}],
"keys": ["key1", "key2"],
"values": [100, 200]
}
# Use dict access (recommended for conflicts)items_list=response["items"]
key_list=response["keys"]
# Or use data_ prefix for attribute accessitems_list=response.data_itemskey_list=response.data_keysvalue_list=response.data_values

Data Format Conversion

Convert to Dictionary

Get the complete response as a dictionary:

# Convert entire response to dictresponse_dict=response.to_dict()
# Returns:# {# "data": {"id": "123", "number": "+1234567890", ...},# "headers": {"x-request-id": "req-456", ...},# "status_code": 200,# "request_id": "req-456",# "rate_limit_remaining": 1000,# "success": True# }# Or use dict() constructorresponse_dict=dict(response)
# Access specific partsdata_only=response_dict["data"]
headers_only=response_dict["headers"]

Convert to JSON

Get JSON string representation with various formatting options:

# Compact JSONjson_string=response.to_json()
# Pretty-printed JSON with indentationpretty_json=response.to_json(indent=2)
# Custom JSON optionsunicode_json=response.to_json(ensure_ascii=False, indent=4)
# Direct json.dumps() also worksimportjsonjson_string=json.dumps(response)

Extract Raw Data

Access just the API response data without metadata:

# Get raw response dataraw_data=response.data# For paginated responsesifisinstance(raw_data, dict) and"data"inraw_data:
items=raw_data["data"] # List of itemsmeta=raw_data.get("meta", {}) # Pagination infolinks=raw_data.get("links", {}) # Pagination linkselse:
# Single item responseitem_data=raw_data

Headers and Metadata

Access Response Headers

Headers can be accessed in multiple ways with automatic case handling:

# Dictionary-style access (case-sensitive)request_id=response.headers["x-request-id"]
content_type=response.headers["content-type"]
# Attribute-style access (dashes become underscores)request_id=response.headers.x_request_idcontent_type=response.headers.content_typerate_limit=response.headers.x_rate_limit_remaining# Nested dictionary accessrequest_id=response["headers"]["x-request-id"]
# Safe access with defaultsretry_after=response.headers.get("retry-after", "0")

Response Metadata

Access useful metadata about the API response:

# HTTP status informationstatus_code=response.status_codeis_successful=response.success# True for 2xx status codes# Rate limiting informationremaining_requests=response.rate_limit_remainingretry_delay=response.retry_after# Seconds to wait before retry# Request trackingrequest_id=response.request_id# Pagination (for list responses)if"meta"inresponse.data:
total_items=response.data["meta"]["total"]
current_page=response.data["meta"]["current_page"]
per_page=response.data["meta"]["per_page"]

Error Handling with Responses

Check Response Status

Always check if the response was successful:

frommailersendimportMailerSendClient, EmailBuilderms=MailerSendClient()
try:
email=EmailBuilder().from_email("sender@domain.com").build()
response=ms.emails.send(email)
ifresponse.success:
email_id=response.idremaining_quota=response.rate_limit_remainingelse:
status_code=response.status_codeerror_details=response.data# Handle rate limitingifresponse.status_code==429andresponse.retry_after:
retry_seconds=response.retry_afterexceptExceptionase:
# Handle exception

Access Error Information

When requests fail, error details are available in the response:

ifnotresponse.success:
error_data=response.data# API error response structureerror_message=error_data.get("message", "Unknown error")
error_code=error_data.get("code")
# Validation errors (422 responses)if"errors"inerror_data:
forfield, messagesinerror_data["errors"].items():
validation_errors= {field: messages}

Working with Different Response Types

# Single item responses (get operations)user_response=ms.users.get_user(request)
ifuser_response.success:
user_name=user_response.nameuser_email=user_response.email# List responses (paginated)users_response=ms.users.list_users(request)
ifusers_response.success:
users=users_response.data["data"] # Array of userstotal_count=users_response.data["meta"]["total"]
foruserinusers:
user_name=user['name']
user_email=user['email']
# Empty responses (delete operations)delete_response=ms.users.delete_user(request)
ifdelete_response.success:
# delete_response.data is typically empty or contains confirmationdeletion_confirmed=True

Logging

The SDK includes comprehensive logging to help with debugging and monitoring:

Enable Debug Logging

importloggingfrommailersendimportMailerSendClient# Enable debug logginglogging.basicConfig(level=logging.DEBUG)
ms=MailerSendClient()
# All API calls will now be logged with detailed information

Custom Logging Configuration

importloggingfrommailersendimportMailerSendClient# Configure logging with custom formatlogging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('mailersend.log'),
logging.StreamHandler()
]
)
ms=MailerSendClient()
# Logs will include:# - API request details# - Response status codes# - Parameter information# - Error details

Usage

Email

Send an email

frommailersendimportMailerSendClient, EmailBuilderms=MailerSendClient()
email= (EmailBuilder()
.from_email("sender@domain.com", "Your Name")
.to_many([{"email": "recipient@domain.com", "name": "Recipient"}])
.subject("Hello from MailerSend!")
.html("<h1>Hello World!</h1>")
.text("Hello World!")
.build())
response=ms.emails.send(email)

Add CC, BCC recipients

frommailersendimportMailerSendClient, EmailBuilderms=MailerSendClient()
email= (EmailBuilder()
.from_email("sender@domain.com", "Your Name")
.to_many([{"email": "recipient@domain.com", "name": "Recipient"}])
.cc([
{"email": "cc1@example.com", "name": "CC User 1"},
{"email": "cc2@example.com", "name": "CC User 2"}
])
.bcc([
{"email": "bcc1@example.com", "name": "BCC User 1"},
{"email": "bcc2@example.com"}
])
.subject("Hello with CC/BCC!")
.html("<h1>Hello World!</h1>")
.build())
response=ms.emails.send(email)

Send a template-based email

frommailersendimportMailerSendClient, EmailBuilderms=MailerSendClient()
email= (EmailBuilder()
.from_email("sender@domain.com", "Your Name")
.to_many([{"email": "recipient@domain.com", "name": "Recipient"}])
.template("template-id")
.personalize_many([{
"email": "recipient@domain.com",
"data": {
"name": "John",
"company": "MailerSend"
}
}])
.build())
response=ms.emails.send(email)

You can also set a language code for a template-based email. It is only meaningful with a template and is ignored for raw html/text sends. Supported codes: de, en, es, fr, it, lt, nl, pl, pt-BR.

email= (EmailBuilder()
.from_email("sender@domain.com", "Your Name")
.to_many([{"email": "recipient@domain.com", "name": "Recipient"}])
.template("template-id")
.language("de")
.build())
response=ms.emails.send(email)

Personalization

frommailersendimportMailerSendClient, EmailBuilderms=MailerSendClient()
email= (EmailBuilder()
.from_email("sender@domain.com", "Your Name")
.to_many([{"email": "recipient@domain.com", "name": "Recipient"}])
.subject("Hello {$name}!")
.html("<h1>Hello {$name} from {$company}!</h1>")
.personalize_many([{
"email": "recipient@domain.com",
"data": {
"name": "John",
"company": "MailerSend",
"items": ["item1", "item2"],
"total": 99.99
}
}])
.build())
response=ms.emails.send(email)

Send email with attachment

frommailersendimportMailerSendClient, EmailBuilderms=MailerSendClient()
email= (EmailBuilder()
.from_email("sender@domain.com", "Your Name")
.to_many([{"email": "recipient@domain.com", "name": "Recipient"}])
.subject("Email with attachment")
.html("<h1>Please find attached document</h1>")
.attach_file("document.pdf")
.build())
response=ms.emails.send(email)

Send bulk email

frommailersendimportMailerSendClient, EmailBuilderms=MailerSendClient()
# Create individual EmailRequest objectsemails= [
EmailBuilder()
.from_email("sender@domain.com", "Sender")
.to_many([{"email": "recipient1@domain.com", "name": "Recipient 1"}])
.subject("Bulk email 1")
.html("<h1>Hello from bulk email 1</h1>")
.text("Hello from bulk email 1")
.build(),
EmailBuilder()
.from_email("sender@domain.com", "Sender")
.to_many([{"email": "recipient2@domain.com", "name": "Recipient 2"}])
.subject("Bulk email 2")
.html("<h1>Hello from bulk email 2</h1>")
.text("Hello from bulk email 2")
.build()
]
response=ms.emails.send_bulk(emails)

Get bulk email status

frommailersendimportMailerSendClientms=MailerSendClient()
response=ms.emails.get_bulk_status("bulk-email-id")

Activity

Get a list of activities

frommailersendimportMailerSendClient, ActivityBuilderfromdatetimeimportdatetime, timedeltams=MailerSendClient()
# Get activities from last 7 days (maximum allowed timeframe)date_from=int((datetime.now() -timedelta(days=7)).timestamp())
date_to=int(datetime.now().timestamp())
request= (ActivityBuilder()
.domain_id("domain-id")
.date_from(date_from)
.date_to(date_to)
.page(1)
.limit(25)
.build_list_request())
response=ms.activities.get(request)

Get activity with filters

frommailersendimportMailerSendClient, ActivityBuilderfromdatetimeimportdatetime, timedeltams=MailerSendClient()
# Get activities from last 7 daysdate_from=int((datetime.now() -timedelta(days=7)).timestamp())
date_to=int(datetime.now().timestamp())
request= (ActivityBuilder()
.domain_id("domain-id")
.date_from(date_from)
.date_to(date_to)
.events(["sent", "delivered", "opened"])
.page(1)
.limit(50)
.build_list_request())
response=ms.activities.get(request)

Get a single activity

frommailersendimportMailerSendClient, SingleActivityBuilderms=MailerSendClient()
request= (SingleActivityBuilder()
.activity_id("activity-id")
.build_get_request())
response=ms.activities.get_single(request)

Analytics

Activity data by date

frommailersendimportMailerSendClient, AnalyticsBuilderfromdatetimeimportdatetime, timedeltams=MailerSendClient()
date_from=int((datetime.now() -timedelta(days=30)).timestamp())
date_to=int(datetime.now().timestamp())
request= (AnalyticsBuilder()
.date_from(date_from)
.date_to(date_to)
.events("sent", "delivered", "opened")
.domain_id("domain-id")
.group_by("days")
.build())
response=ms.analytics.get_activity_by_date(request)

Opens by country

frommailersendimportMailerSendClient, AnalyticsBuilderms=MailerSendClient()
request= (AnalyticsBuilder()
.date_from(date_from)
.date_to(date_to)
.domain_id("domain-id")
.build())
response=ms.analytics.get_opens_by_country(request)

Opens by user-agent name

frommailersendimportMailerSendClient, AnalyticsBuilderms=MailerSendClient()
request= (AnalyticsBuilder()
.date_from(date_from)
.date_to(date_to)
.domain_id("domain-id")
.build())
response=ms.analytics.get_opens_by_user_agent(request)

Opens by reading environment

frommailersendimportMailerSendClient, AnalyticsBuilderms=MailerSendClient()
request= (AnalyticsBuilder()
.date_from(date_from)
.date_to(date_to)
.domain_id("domain-id")
.build())
response=ms.analytics.get_opens_by_reading_environment(request)

Domains

Get a list of domains

frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.page(1)
.limit(25)
.build_list_request())
response=ms.domains.list_domains(request)

Get a single domain

frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.build_get_request())
response=ms.domains.get_domain(request)

Add a domain

frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_name("mydomain.com")
.return_path_subdomain("rp")
.custom_tracking_subdomain("ct")
.inbound_routing_subdomain("ir")
.build_create_request())
response=ms.domains.create_domain(request)

Delete a domain

frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.build_delete_request())
response=ms.domains.delete_domain(request)

Get a list of recipients per domain

frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.page(1)
.limit(25)
.build_recipients_request())
response=ms.domains.get_domain_recipients(request)

Update domain settings

frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.send_paused(False)
.track_clicks(True)
.track_opens(True)
.track_unsubscribe(True)
.track_content(True)
.custom_tracking_enabled(True)
.custom_tracking_subdomain("email")
.precedence_bulk(False)
.build_update_settings_request())
response=ms.domains.update_domain_settings(request)

Get DNS Records

frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.build_dns_records_request())
response=ms.domains.get_domain_dns_records(request)

Verify a domain

frommailersendimportMailerSendClientfrommailersendimportDomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.build_verification_request())
response=ms.domains.get_domain_verification_status(request)

Sender Identities

Get a list of sender identities

frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.domain_id("domain-id")
.build_list_request())
response=ms.identities.list_identities(request)

Get a sender identity

frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.identity_id("identity-id")
.build_get_request())
response=ms.identities.get_identity(request)

Create a sender identity

frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.domain_id("domain-id")
.name("John Doe")
.email("john@yourdomain.com")
.reply_to_email("support@yourdomain.com")
.reply_to_name("Support Team")
.add_note(True)
.build_create_request())
response=ms.identities.create_identity(request)

Update a sender identity

frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.identity_id("identity-id")
.name("Jane Doe")
.reply_to_email("support@yourdomain.com")
.reply_to_name("Support Team")
.add_note(True)
.build_update_request())
response=ms.identities.update_identity(request)

Update a sender identity by email

frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.email("support@yourdomain.com")
.name("Doe Jane")
.reply_to_email("support@yourdomain.com")
.reply_to_name("Support Team")
.add_note(True)
.build_update_by_email_request())
response=ms.identities.update_identity(request)

Delete a sender identity

frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.identity_id("identity-id")
.build_delete_request())
response=ms.identities.delete_identity(request)

Delete a sender identity by email

frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.email("support@yourdomain.com")
.build_delete_by_email_request())
response=ms.identities.delete_identity_by_email(request)

Inbound Routes

Get a list of inbound routes

frommailersendimportMailerSendClient, InboundBuilderms=MailerSendClient()
request= (InboundBuilder()
.domain_id("domain-id")
.build_list_request())
response=ms.inbound.list(request)

Get a single inbound route

frommailersendimportMailerSendClient, InboundBuilderms=MailerSendClient()
request= (InboundBuilder()
.inbound_id("inbound-id")
.build_get_request())
response=ms.inbound.get(request)

Add an inbound route

frommailersendimportMailerSendClient, InboundBuilderms=MailerSendClient()
request= (InboundBuilder()
.domain_id("domain-id")
.name("My Inbound Route")
.domain_enabled(False)
.inbound_priority(1)
.catch_type("all")
.match_type("all")
.add_forward("email", "support@mycompany.com")
.catch_recipient([{"comparer": "equal", "value": "support"}])
.add_match_filter("match_sender", [{"comparer": "equal", "value": "support"}])
.add_webhook_forward("https://mycompany.com/webhook")
.build_create_request())
response=ms.inbound.create_inbound_route(request)

Update an inbound route

frommailersendimportMailerSendClient, InboundBuilderms=MailerSendClient()
request= (InboundBuilder()
.inbound_id("inbound-id")
.name("Updated Route Name")
.enabled(False)
.build_update_request())
response=ms.inbound.update_inbound_route(request)

Delete an inbound route

frommailersendimportMailerSendClient, InboundBuilderms=MailerSendClient()
request= (InboundBuilder()
.inbound_id("inbound-id")
.build_delete_request())
response=ms.inbound.delete_inbound_route(request)

Messages

Get a list of messages

frommailersendimportMailerSendClient, MessagesBuilderms=MailerSendClient()
request= (MessagesBuilder()
.build_list_request())
response=ms.messages.list_messages(request)

Get a single message

frommailersendimportMailerSendClient, MessagesBuilderms=MailerSendClient()
request= (MessagesBuilder()
.message_id("message-id")
.build_get_request())
response=ms.messages.get_message(request)

Scheduled messages

Get a list of scheduled messages

frommailersendimportMailerSendClient, SchedulesBuilderms=MailerSendClient()
request= (SchedulesBuilder()
.domain_id("domain-id")
.build_list_request())
response=ms.schedules.list_schedules(request)

Get a single scheduled message

frommailersendimportMailerSendClient, SchedulesBuilderms=MailerSendClient()
request= (SchedulesBuilder()
.message_id("scheduled-id")
.build_get_request())
response=ms.schedules.get_schedule(request)

Delete a scheduled message

frommailersendimportMailerSendClient, SchedulesBuilderms=MailerSendClient()
request= (SchedulesBuilder()
.message_id("scheduled-id")
.build_delete_request())
response=ms.schedules.delete_schedule(request)

Recipients

Get a list of recipients

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_recipients_list_request())
response=ms.recipients.list_recipients(request)

Get a single recipient

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.recipient_id("recipient-id")
.build_recipient_get_request())
response=ms.recipients.get_recipient(request)

Delete a recipient

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.recipient_id("recipient-id")
.build_recipient_delete_request())
response=ms.recipients.delete_recipient(request)

Get recipients from a blocklist

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_suppression_list_request())
response=ms.recipients.list_blocklist(request)

Get recipients from hard bounces

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_suppression_list_request())
response=ms.recipients.list_hard_bounces(request)

Get recipients from spam complaints

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_suppression_list_request())
response=ms.recipients.list_spam_complaints(request)

Get recipients from unsubscribes

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_suppression_list_request())
response=ms.recipients.list_unsubscribes(request)

Add recipients to blocklist

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
# Using specific emailsrequest= (RecipientsBuilder()
.domain_id("domain-id")
.recipients(["blocked@example.com", "spam@example.com"])
.build_suppression_add_request())
response=ms.recipients.add_to_blocklist(request)
# Using patternsrequest= (RecipientsBuilder()
.domain_id("domain-id")
.patterns(["*@spammer.com", "*@blocked-domain.com"])
.build_suppression_add_request())
response=ms.recipients.add_to_blocklist(request)

Add hard bounced recipients

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.recipients(["bounced@example.com"])
.build_suppression_add_request())
response=ms.recipients.add_hard_bounces(request)

Add spam complaints

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.recipients(["complainer@example.com"])
.build_suppression_add_request())
response=ms.recipients.add_spam_complaints(request)

Add recipients to unsubscribe list

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.recipients(["unsubscribed@example.com"])
.build_suppression_add_request())
response=ms.recipients.add_unsubscribes(request)

Delete recipients from blocklist

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
# Delete specific entries by IDsrequest= (RecipientsBuilder()
.domain_id("domain-id")
.ids(["recipient-id-1", "recipient-id-2"])
.build_suppression_delete_request())
response=ms.recipients.delete_from_blocklist(request)
# Or delete all entriesrequest= (RecipientsBuilder()
.domain_id("domain-id")
.all(True)
.build_suppression_delete_request())
response=ms.recipients.delete_from_blocklist(request)

Delete hard bounced recipients

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
# Delete specific entries by IDsrequest= (RecipientsBuilder()
.domain_id("domain-id")
.ids(["recipient-id"])
.build_suppression_delete_request())
response=ms.recipients.delete_hard_bounces(request)
# Or delete all entriesrequest= (RecipientsBuilder()
.domain_id("domain-id")
.all(True)
.build_suppression_delete_request())
response=ms.recipients.delete_hard_bounces(request)

Delete spam complaints

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
# Delete specific entries by IDsrequest= (RecipientsBuilder()
.domain_id("domain-id")
.ids(["recipient-id"])
.build_suppression_delete_request())
response=ms.recipients.delete_spam_complaints(request)
# Or delete all entriesrequest= (RecipientsBuilder()
.domain_id("domain-id")
.all(True)
.build_suppression_delete_request())
response=ms.recipients.delete_spam_complaints(request)

Delete recipients from unsubscribe list

frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
# Delete specific entries by IDsrequest= (RecipientsBuilder()
.domain_id("domain-id")
.ids(["recipient-id"])
.build_suppression_delete_request())
response=ms.recipients.delete_unsubscribes(request)
# Or delete all entriesrequest= (RecipientsBuilder()
.domain_id("domain-id")
.all(True)
.build_suppression_delete_request())
response=ms.recipients.delete_unsubscribes(request)

Templates

Get a list of templates

frommailersendimportMailerSendClient, TemplatesBuilderms=MailerSendClient()
request= (TemplatesBuilder()
.domain_id("domain-id")
.page(1)
.limit(25)
.build_templates_list_request())
response=ms.templates.list_templates(request)

Get a single template

frommailersendimportMailerSendClient, TemplatesBuilderms=MailerSendClient()
request= (TemplatesBuilder()
.template("template-id")
.build_template_get_request())
response=ms.templates.get_template(request)

Delete template

frommailersendimportMailerSendClient, TemplatesBuilderms=MailerSendClient()
request= (TemplatesBuilder()
.template("template-id")
.build_delete_request())
response=ms.templates.delete_template(request)

Webhooks

Get a list of webhooks

frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
request= (WebhooksBuilder()
.domain_id("domain-id")
.build_webhooks_list_request())
response=ms.webhooks.list_webhooks(request)

Get a single webhook

frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
request= (WebhooksBuilder()
.webhook_id("webhook-id")
.build_webhook_get_request())
response=ms.webhooks.get_webhook(request)

Create a Webhook

frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
request= (WebhooksBuilder()
.domain_id("domain-id")
.url("https://yourdomain.com/webhook")
.name("My webhook")
.events(["activity.sent", "activity.delivered"])
.enabled(True)
.build_webhook_create_request())
response=ms.webhooks.create_webhook(request)

Create a disabled webhook

frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
request= (WebhooksBuilder()
.domain_id("domain-id")
.url("https://yourdomain.com/webhook")
.name("My disabled webhook")
.events(["activity.sent", "activity.delivered"])
.enabled(False)
.build_webhook_create_request())
response=ms.webhooks.create_webhook(request)

Update a Webhook

frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
request= (WebhooksBuilder()
.webhook_id("webhook-id")
.url("https://yourdomain.com/webhook-updated")
.name("My updated webhook")
.events(["activity.sent"])
.enabled(True)
.build_webhook_update_request())
response=ms.webhooks.update_webhook(request)

Disable/Enable a Webhook

frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
# Disable webhookrequest= (WebhooksBuilder()
.webhook_id("webhook-id")
.enabled(False)
.build_webhook_update_request())
response=ms.webhooks.update_webhook(request)
# Enable webhookrequest= (WebhooksBuilder()
.webhook_id("webhook-id")
.enabled(True)
.build_webhook_update_request())
response=ms.webhooks.update_webhook(request)

Delete a Webhook

frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
request= (WebhooksBuilder()
.webhook_id("webhook-id")
.build_webhook_delete_request())
response=ms.webhooks.delete_webhook(request)

Email Verification

Get all email verification lists

frommailersendimportMailerSendClient, EmailVerificationBuilderms=MailerSendClient()
request=EmailVerificationBuilder().build_lists()
response=ms.email_verification.list_verifications(request)

Get a single email verification list

frommailersendimportMailerSendClient, EmailVerificationBuilderms=MailerSendClient()
request= (EmailVerificationBuilder()
.email_verification_id("list-id")
.build_get())
response=ms.email_verification.get_verification(request)

Create an email verification list

frommailersendimportMailerSendClient, EmailVerificationBuilderms=MailerSendClient()
request= (EmailVerificationBuilder()
.name("My Verification List")
.emails(["test1@example.com", "test2@example.com"])
.build_create())
response=ms.email_verification.create_verification(request)

Verify a list

frommailersendimportMailerSendClient, EmailVerificationBuilderms=MailerSendClient()
request= (EmailVerificationBuilder()
.email_verification_id("list-id")
.build_verify_list())
response=ms.email_verification.verify_list(request)

Get list results

frommailersendimportMailerSendClient, EmailVerificationBuilderms=MailerSendClient()
request= (EmailVerificationBuilder()
.email_verification_id("list-id")
.build_results())
response=ms.email_verification.get_results(request)

SMS

Sending SMS messages

frommailersendimportMailerSendClient, SmsSendingBuilderms=MailerSendClient()
# Simple SMSrequest= (SmsSendingBuilder()
.from_number("sms-number")
.to(["+1234567890", "+1234567891"])
.text("Hello from MailerSend SMS!")
.build())
response=ms.sms_sending.send(request)
# SMS with personalizationrequest= (SmsSendingBuilder()
.from_number("sms-number")
.to(["+1234567890", "+1234567891"])
.text("Hello {{name}}, your order {{order_id}} is ready!")
.personalization([
{
"phone_number": "+1234567890",
"data": {"name": "John", "order_id": "12345"}
},
{
"phone_number": "+1234567891",
"data": {"name": "Jane", "order_id": "12346"}
}
])
.build())
response=ms.sms_sending.send(request)

SMS Activity

Get a list of SMS activities

frommailersendimportMailerSendClient, SmsActivityBuilderfromdatetimeimportdatetime, timedeltams=MailerSendClient()
# Get activities from last 7 daysdate_from=int((datetime.now() -timedelta(days=7)).timestamp())
date_to=int(datetime.now().timestamp())
request= (SmsActivityBuilder()
.sms_number_id("sms-number-id")
.date_from(date_from)
.date_to(date_to)
.status(["sent", "delivered", "failed"])
.page(1)
.limit(25)
.build_list_request())
response=ms.sms_activity.list(request)

Get activity of a single SMS message

frommailersendimportMailerSendClient, SmsActivityBuilderms=MailerSendClient()
request= (SmsActivityBuilder()
.sms_message_id("sms-message-id")
.build_get_request())
response=ms.sms_activity.get(request)

SMS Phone Numbers

Get a list of SMS phone numbers

frommailersendimportMailerSendClient, SmsNumbersBuilderms=MailerSendClient()
request= (SmsNumbersBuilder()
.paused(False)
.page(1)
.limit(25)
.build_list_request())
response=ms.sms_numbers.list(request)

Get an SMS phone number

frommailersendimportMailerSendClient, SmsNumbersBuilderms=MailerSendClient()
request= (SmsNumbersBuilder()
.sms_number_id("sms-number-id")
.build_get_request())
response=ms.sms_numbers.get(request)

Update a single SMS phone number

frommailersendimportMailerSendClient, SmsNumbersBuilderms=MailerSendClient()
request= (SmsNumbersBuilder()
.sms_number_id("sms-number-id")
.paused(True)
.build_update_request())
response=ms.sms_numbers.update(request)

Delete an SMS phone number

frommailersendimportMailerSendClient, SmsNumbersBuilderms=MailerSendClient()
request= (SmsNumbersBuilder()
.sms_number_id("sms-number-id")
.build_delete_request())
response=ms.sms_numbers.delete(request)

SMS Recipients

Get a list of SMS recipients

frommailersendimportMailerSendClient, SmsRecipientsBuilderfrommailersend.models.sms_recipientsimportSmsRecipientStatusms=MailerSendClient()
request= (SmsRecipientsBuilder()
.sms_number_id("sms-number-id")
.status(SmsRecipientStatus.ACTIVE)
.page(1)
.limit(25)
.build_list_request())
response=ms.sms_recipients.list_sms_recipients(request)

Get an SMS recipient

frommailersendimportMailerSendClient, SmsRecipientsBuilderms=MailerSendClient()
request= (SmsRecipientsBuilder()
.sms_recipient_id("recipient-id")
.build_get_request())
response=ms.sms_recipients.get_sms_recipient(request)

Update a single SMS recipient

frommailersendimportMailerSendClient, SmsRecipientsBuilderfrommailersend.models.sms_recipientsimportSmsRecipientStatusms=MailerSendClient()
request= (SmsRecipientsBuilder()
.sms_recipient_id("recipient-id")
.build_update_request(SmsRecipientStatus.OPT_OUT))
response=ms.sms_recipients.update_sms_recipient(request)

SMS Messages

Get a list of SMS messages

frommailersendimportMailerSendClient, SmsMessagesBuilderms=MailerSendClient()
request= (SmsMessagesBuilder()
.page(1)
.limit(25)
.build_sms_messages_list())
response=ms.sms_messages.list_sms_messages(request)

Get an SMS message

frommailersendimportMailerSendClient, SmsMessagesBuilderms=MailerSendClient()
request= (SmsMessagesBuilder()
.sms_message_id("message-id")
.build_sms_message_get())
response=ms.sms_messages.get_sms_message(request)

SMS Webhooks

Get a list of SMS webhooks

frommailersendimportMailerSendClient, SmsWebhooksBuilderms=MailerSendClient()
request= (SmsWebhooksBuilder()
.sms_number_id("sms-number-id")
.build_list_request())
response=ms.sms_webhooks.list_sms_webhooks(request)

Get a single SMS webhook

frommailersendimportMailerSendClient, SmsWebhooksBuilderms=MailerSendClient()
request= (SmsWebhooksBuilder()
.sms_webhook_id("webhook-id")
.build_get_request())
response=ms.sms_webhooks.get_sms_webhook(request)

Create an SMS webhook

frommailersendimportMailerSendClient, SmsWebhooksBuilderfrommailersend.models.sms_webhooksimportSmsWebhookEventms=MailerSendClient()
request= (SmsWebhooksBuilder()
.from_number("sms-number-id")
.url("https://webhook.example.com/sms")
.name("SMS Webhook")
.add_event(SmsWebhookEvent.SMS_SENT)
.add_event(SmsWebhookEvent.SMS_DELIVERED)
.add_event(SmsWebhookEvent.SMS_FAILED)
.enabled(True)
.build_create_request())
response=ms.sms_webhooks.create_sms_webhook(request)

Update a single SMS webhook

frommailersendimportMailerSendClient, SmsWebhooksBuilderfrommailersend.models.sms_webhooksimportSmsWebhookEventms=MailerSendClient()
request= (SmsWebhooksBuilder()
.sms_webhook_id("webhook-id")
.name("Updated SMS Webhook")
.url("https://new-webhook.example.com/sms")
.events([SmsWebhookEvent.SMS_DELIVERED, SmsWebhookEvent.SMS_FAILED])
.enabled(False)
.build_update_request())
response=ms.sms_webhooks.update_sms_webhook(request)

Delete an SMS webhook

frommailersendimportMailerSendClient, SmsWebhooksBuilderms=MailerSendClient()
request= (SmsWebhooksBuilder()
.sms_webhook_id("webhook-id")
.build_delete_request())
response=ms.sms_webhooks.delete_sms_webhook(request)

SMS Inbound Routing

Get a list of SMS inbound routes

frommailersendimportMailerSendClient, SmsInboundsBuilderms=MailerSendClient()
request= (SmsInboundsBuilder()
.sms_number_id("sms-number-id")
.enabled(True)
.build_list_request())
response=ms.sms_inbounds.list_sms_inbounds(request)

Get a single SMS inbound route

frommailersendimportMailerSendClient, SmsInboundsBuilderms=MailerSendClient()
request= (SmsInboundsBuilder()
.sms_inbound_id("inbound-id")
.build_get_request())
response=ms.sms_inbounds.get_sms_inbound(request)

Create an SMS inbound route

frommailersendimportMailerSendClient, SmsInboundsBuilderfrommailersend.models.sms_inboundsimportFilterComparerms=MailerSendClient()
request= (SmsInboundsBuilder()
.sms_number_id("sms-number-id")
.name("Support Route")
.forward_url("https://api.example.com/sms/support")
.filter(FilterComparer.STARTS_WITH, "SUPPORT")
.enabled(True)
.build_create_request())
response=ms.sms_inbounds.create_sms_inbound(request)

Update an SMS inbound route

frommailersendimportMailerSendClient, SmsInboundsBuilderfrommailersend.models.sms_inboundsimportFilterComparerms=MailerSendClient()
request= (SmsInboundsBuilder()
.sms_number_id("inbound-id")
.name("Updated Support Route")
.forward_url("https://api.example.com/sms/new-support")
.filter(FilterComparer.CONTAINS, "HELP")
.enabled(False)
.build_update_request())
response=ms.sms_inbounds.update_sms_inbound(request)

Delete an SMS inbound route

frommailersendimportMailerSendClient, SmsInboundsBuilderms=MailerSendClient()
request= (SmsInboundsBuilder()
.sms_inbound_id("inbound-id")
.build_delete_request())
response=ms.sms_inbounds.delete_sms_inbound(request)

Tokens

Create a token

frommailersendimportMailerSendClient, TokensBuilderms=MailerSendClient()
request= (TokensBuilder()
.name("My API Token")
.scopes(["email_full", "analytics_read"])
.domain_id("domain-id")
.build_token_create())
response=ms.tokens.create_token(request)

Pause / Unpause Token

frommailersendimportMailerSendClient, TokensBuilderms=MailerSendClient()
# Pause tokenrequest= (TokensBuilder()
.token_id("token-id")
.status("pause")
.build_token_update())
response=ms.tokens.update_token(request)
# Unpause tokenrequest= (TokensBuilder()
.token_id("token-id")
.status("unpause")
.build_token_update())
response=ms.tokens.update_token(request)

Delete a Token

frommailersendimportMailerSendClient, TokensBuilderms=MailerSendClient()
request= (TokensBuilder()
.token_id("token-id")
.build_token_delete())
response=ms.tokens.delete_token(request)

SMTP Users

Get a list of SMTP users

frommailersendimportMailerSendClient, SmtpUsersBuilderms=MailerSendClient()
request= (SmtpUsersBuilder()
.domain_id("domain-id")
.build_smtp_users_list())
response=ms.smtp_users.list_smtp_users(request)

Get a single SMTP user

frommailersendimportMailerSendClient, SmtpUsersBuilderms=MailerSendClient()
request= (SmtpUsersBuilder()
.domain_id("domain-id")
.smtp_user_id("smtp-user-id")
.build_smtp_user_get())
response=ms.smtp_users.get_smtp_user(request)

Create an SMTP user

frommailersendimportMailerSendClient, SmtpUsersBuilderms=MailerSendClient()
request= (SmtpUsersBuilder()
.domain_id("domain-id")
.name("SMTP User Name")
.enabled(True)
.build_smtp_user_create())
response=ms.smtp_users.create_smtp_user(request)

Update an SMTP user

frommailersendimportMailerSendClient, SmtpUsersBuilderms=MailerSendClient()
request= (SmtpUsersBuilder()
.domain_id("domain-id")
.smtp_user_id("smtp-user-id")
.name("Updated SMTP User Name")
.enabled(False)
.build_smtp_user_update())
response=ms.smtp_users.update_smtp_user(request)

Delete an SMTP user

frommailersendimportMailerSendClient, SmtpUsersBuilderms=MailerSendClient()
request= (SmtpUsersBuilder()
.domain_id("domain-id")
.smtp_user_id("smtp-user-id")
.build_smtp_user_delete())
response=ms.smtp_users.delete_smtp_user(request)

Users

Get a list of account users

frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.page(1)
.limit(25)
.build_users_list())
response=ms.users.list_users(request)

Get a single account user

frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.user_id("user-id")
.build_user_get())
response=ms.users.get_user(request)

Invite a user to account

frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
# Basic invite with admin rolerequest= (UsersBuilder()
.email("newuser@example.com")
.admin_role()
.build_user_invite())
response=ms.users.invite_user(request)
# Custom invite with specific permissions and accessrequest= (UsersBuilder()
.email("designer@example.com")
.designer_role()
.add_permission("read-all-templates")
.add_permission("manage-template")
.add_template("template-id")
.add_domain("domain-id")
.requires_periodic_password_change(True)
.build_user_invite())
response=ms.users.invite_user(request)

Update an account user

frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.user_id("user-id")
.manager_role()
.add_permission("read-analytics")
.add_permission("read-activity")
.add_domain("domain-id")
.build_user_update())
response=ms.users.update_user(request)

Delete a user from account

frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.user_id("user-id")
.build_user_delete())
response=ms.users.delete_user(request)

Get a list of invites

frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.page(1)
.limit(25)
.build_invites_list())
response=ms.users.list_invites(request)

Get a single invite

frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.invite_id("invite-id")
.build_invite_get())
response=ms.users.get_invite(request)

Resend an invite

frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.invite_id("invite-id")
.build_invite_resend())
response=ms.users.resend_invite(request)

Cancel an invite

frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.invite_id("invite-id")
.build_invite_cancel())
response=ms.users.cancel_invite(request)

DMARC Monitoring

Get a list of monitors

frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.page(1)
.limit(25)
.build_list_request())
response=ms.dmarc_monitoring.list_monitors(request)

Create a monitor

frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.domain_id("your-domain-id")
.build_create_request())
response=ms.dmarc_monitoring.create_monitor(request)

Update a monitor

frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.wanted_dmarc_record("v=DMARC1; p=reject; rua=mailto:dmarc@example.com")
.build_update_request())
response=ms.dmarc_monitoring.update_monitor(request)

Delete a monitor

frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.build_delete_request())
response=ms.dmarc_monitoring.delete_monitor(request)

Get aggregated reports

frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.page(1)
.limit(25)
.build_report_request())
response=ms.dmarc_monitoring.get_aggregated_report(request)

Get IP-specific reports

frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.ip("192.168.1.1")
.page(1)
.limit(25)
.build_ip_report_request())
response=ms.dmarc_monitoring.get_ip_report(request)

Get report sources

frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.build_report_sources_request())
response=ms.dmarc_monitoring.get_report_sources(request)

Mark IP as favorite

frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.ip("192.168.1.1")
.build_mark_favorite_request())
response=ms.dmarc_monitoring.mark_ip_favorite(request)

Remove IP from favorites

frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.ip("192.168.1.1")
.build_remove_favorite_request())
response=ms.dmarc_monitoring.remove_ip_favorite(request)

Other Endpoints

Get API Quota

frommailersendimportMailerSendClientms=MailerSendClient()
response=ms.api_quota.get_quota()

Async Usage

The AsyncMailerSendClient exposes the same resources and methods as the synchronous MailerSendClient — prefixed with async/await — so you can use it anywhere asyncio is available.

Basic Async Usage

Use AsyncMailerSendClient as an async context manager (recommended) to ensure the underlying HTTP connection is properly closed:

importasynciofrommailersendimportAsyncMailerSendClient, EmailBuilderasyncdefmain():
asyncwithAsyncMailerSendClient() asclient:
email= (EmailBuilder()
.from_email("sender@domain.com", "Your Name")
.to_many([{"email": "recipient@domain.com", "name": "Recipient"}])
.subject("Hello from MailerSend!")
.html("<h1>Hello World!</h1>")
.text("Hello World!")
.build())
response=awaitclient.emails.send(email)
print(response.status_code)
asyncio.run(main())

If you prefer to manage the lifecycle manually, call await client.close() when finished:

frommailersendimportAsyncMailerSendClientclient=AsyncMailerSendClient(api_key="your-api-key")
try:
response=awaitclient.api_quota.get_quota()
finally:
awaitclient.close()

All resources available on MailerSendClient are also available on AsyncMailerSendClient:

asyncwithAsyncMailerSendClient() asclient:
client.emails# Email operationsclient.activities# Activity operationsclient.analytics# Analytics operationsclient.domains# Domain operationsclient.identities# Sender identity operationsclient.inbound# Inbound route operationsclient.templates# Template operationsclient.tokens# Token operationsclient.webhooks# Webhook operationsclient.email_verification# Email verification operationsclient.users# User operationsclient.messages# Message operationsclient.recipients# Recipient & suppression operationsclient.schedules# Scheduled message operationsclient.smtp_users# SMTP user operationsclient.sms_sending# SMS sending operationsclient.sms_numbers# SMS phone number operationsclient.sms_activity# SMS activity operationsclient.sms_inbounds# SMS inbound routing operationsclient.sms_recipients# SMS recipient operationsclient.sms_webhooks# SMS webhook operationsclient.sms_messages# SMS message operationsclient.api_quota# API quota operationsclient.dmarc_monitoring# DMARC monitoring operations

Concurrent Requests

The main benefit of AsyncMailerSendClient is the ability to run multiple API calls concurrently with asyncio.gather:

importasynciofrommailersendimportAsyncMailerSendClient, DomainsBuilder, TemplatesBuilderasyncdefmain():
asyncwithAsyncMailerSendClient() asclient:
domains_request=DomainsBuilder().build_list_request()
templates_request=TemplatesBuilder().build_templates_list_request()
# Both requests run concurrentlydomains_response, templates_response=awaitasyncio.gather(
client.domains.list_domains(domains_request),
client.templates.list_templates(templates_request),
)
print(f"Domains: {domains_response.data}")
print(f"Templates: {templates_response.data}")
asyncio.run(main())

Async Error Handling

AsyncMailerSendClient raises the same exception types as the synchronous client:

importasynciofrommailersendimportAsyncMailerSendClientfrommailersend.exceptionsimport (
AuthenticationError,
RateLimitExceeded,
ResourceNotFoundError,
BadRequestError,
ServerError,
MailerSendError,
)
asyncdefmain():
asyncwithAsyncMailerSendClient() asclient:
try:
response=awaitclient.api_quota.get_quota()
exceptAuthenticationError:
print("Invalid API key")
exceptRateLimitExceededase:
print(f"Rate limit hit: {e}")
exceptResourceNotFoundError:
print("Resource not found")
exceptBadRequestErrorase:
print(f"Bad request: {e}")
exceptServerErrorase:
print(f"Server error: {e}")
exceptMailerSendErrorase:
print(f"Unexpected error: {e}")
asyncio.run(main())

The client automatically retries transient errors (429, 500, 502, 503, 504) with exponential backoff. For 429 responses the Retry-After header is respected if present.

Async Debug Logging

Debug logging works the same way as the synchronous client:

importasynciofrommailersendimportAsyncMailerSendClientasyncdefmain():
# Enable debug at construction timeasyncwithAsyncMailerSendClient(debug=True) asclient:
response=awaitclient.api_quota.get_quota()
# Or toggle at runtimeasyncwithAsyncMailerSendClient() asclient:
client.enable_debug()
response=awaitclient.api_quota.get_quota()
client.disable_debug()
asyncio.run(main())

Error Handling

The SDK provides comprehensive error handling with detailed error information:

frommailersendimportMailerSendClientfrommailersend.exceptionsimportMailerSendErrorfrommailersendimportEmailBuilderms=MailerSendClient()
try:
email= (EmailBuilder()
.from_email("invalid-email", "Sender") # Invalid email
.to_many([{"email": "recipient@domain.com", "name": "Recipient"}])
.subject("Test")
.html("<h1>Test</h1>")
.build())
response=ms.emails.send(email)
exceptMailerSendErrorase:
print(f"MailerSend API Error: {e}")
print(f"Status Code: {e.status_code}")
print(f"Error Details: {e.details}")
exceptExceptionase:
print(f"Unexpected error: {e}")

Common error types:

  • ValidationError: Invalid data in request models (handled by Pydantic)
  • AuthenticationError: Invalid or missing API key (401)
  • RateLimitExceeded: API rate limit exceeded (429)
  • BadRequestError: Malformed or invalid request (400)
  • ResourceNotFoundError: Requested resource not found (404)
  • ServerError: Server-side error (5xx)
  • MailerSendError: Base exception; also raised for network connectivity failures

Testing

Running Unit Tests

# Install development dependencies
pip install -e ".[dev]"# Run all tests
pytest
# Run specific test module
pytest tests/unit/test_sms_recipients_*.py
# Run with coverage
pytest --cov=mailersend --cov-report=html

Testing with VCR

The SDK uses VCR.py for integration tests to record and replay API responses:

importpytestfrommailersendimportMailerSendClientfrommailersendimportSmsRecipientsBuilder@pytest.mark.vcrdeftest_list_sms_recipients():
ms=MailerSendClient()
request=SmsRecipientsBuilder().build_list_request()
response=ms.sms_recipients.list_sms_recipients(request)
assertresponse.dataisnotNone

Available endpoints

Feature groupEndpointAvailable
ActivityGET activity
AnalyticsGET analytics
Domains{GET, POST, PUT, DELETE} domains
EmailPOST send
Email Verification{GET, POST, PUT} email-verification
Bulk EmailPOST bulk-email
Inbound Routes{GET, POST, PUT, DELETE} inbound
MessagesGET messages
Scheduled Messages{GET, DELETE} scheduled-messages
Recipients{GET, POST, DELETE} recipients
Templates{GET, DELETE} templates
Tokens{POST, PUT, DELETE} tokens
SMTP Users{GET, POST, PUT, DELETE} smtp-users
Users{GET, POST, PUT, DELETE} users
User Invites{GET, POST, DELETE} invites
Webhooks{GET, POST, PUT, DELETE} webhooks
SMS SendingPOST sms
SMS ActivityGET sms-activity
SMS Phone Numbers{GET, PUT, DELETE} sms-numbers
SMS Recipients{GET, PUT} sms-recipients
SMS MessagesGET sms-messages
SMS Webhooks{GET, POST, PUT, DELETE} sms-webhooks
SMS Inbound Routing{GET, POST, PUT, DELETE} sms-inbounds
Sender Identities{GET, POST, PUT, DELETE} identities
API QuotaGET api-quota
DMARC Monitoring{GET, POST, PUT, DELETE} dmarc-monitoring

All endpoints are available and fully tested. Refer to official API docs for the most up-to-date API specifications.

Support and Feedback

In case you find any bugs, submit an issue directly here in GitHub.

If you have any troubles using our API or SDK free to contact our support by email info@mailersend.com

The official documentation is at https://developers.mailersend.com

License

The MIT License (MIT)

About

The official MailerSend Python SDK

Topics

Resources

Stars

71 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages