MailerSend Python SDK
- Table of Contents
- Installation
- SDK Architecture
- Response Data Access
- Logging
- Usage
- Activity
- Analytics
- Domains
- Sender Identities
- Inbound Routes
- Messages
- Scheduled messages
- Recipients
- Get a list of recipients
- Get a single recipient
- Delete a recipient
- Get recipients from a blocklist
- Get recipients from hard bounces
- Get recipients from spam complaints
- Get recipients from unsubscribes
- Add recipients to blocklist
- Add hard bounced recipients
- Add spam complaints
- Add recipients to unsubscribe list
- Delete recipients from blocklist
- Delete hard bounced recipients
- Delete spam complaints
- Delete recipients from unsubscribe list
- Templates
- Webhooks
- Email Verification
- SMS
- SMS Activity
- SMS Phone Numbers
- SMS Recipients
- SMS Messages
- SMS Webhooks
- SMS Inbound Routing
- Tokens
- SMTP Users
- Users
- DMARC Monitoring
- Other Endpoints
- Async Usage
- Error Handling
- Testing
- Available endpoints
- Support and Feedback
- License
pip install mailersend- Python 3.10+
- An API Key from mailersend.com
The SDK supports multiple authentication methods:
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()For development, you can use a .env file. First install python-dotenv:
pip install python-dotenvCreate a .env file in your project root:
# .env
MAILERSEND_API_KEY=your-api-keyThen load it in your Python code:
frommailersendimportMailerSendClientfromdotenvimportload_dotenv# Load environment variables from .env fileload_dotenv()
# Client automatically uses the loaded MAILERSEND_API_KEYms=MailerSendClient()frommailersendimportMailerSendClientms=MailerSendClient(api_key="your-api-key")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.
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)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 moreAll 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 objectThe 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.
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.
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']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].textUse 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)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_valuesGet 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"]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)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_dataHeaders 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")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"]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 exceptionWhen 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}# 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=TrueThe SDK includes comprehensive logging to help with debugging and monitoring:
importloggingfrommailersendimportMailerSendClient# Enable debug logginglogging.basicConfig(level=logging.DEBUG)
ms=MailerSendClient()
# All API calls will now be logged with detailed informationimportloggingfrommailersendimportMailerSendClient# 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 detailsfrommailersendimportMailerSendClient, 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)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)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)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)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)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)frommailersendimportMailerSendClientms=MailerSendClient()
response=ms.emails.get_bulk_status("bulk-email-id")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)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)frommailersendimportMailerSendClient, SingleActivityBuilderms=MailerSendClient()
request= (SingleActivityBuilder()
.activity_id("activity-id")
.build_get_request())
response=ms.activities.get_single(request)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)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)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)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)frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.page(1)
.limit(25)
.build_list_request())
response=ms.domains.list_domains(request)frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.build_get_request())
response=ms.domains.get_domain(request)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)frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.build_delete_request())
response=ms.domains.delete_domain(request)frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.page(1)
.limit(25)
.build_recipients_request())
response=ms.domains.get_domain_recipients(request)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)frommailersendimportMailerSendClient, DomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.build_dns_records_request())
response=ms.domains.get_domain_dns_records(request)frommailersendimportMailerSendClientfrommailersendimportDomainsBuilderms=MailerSendClient()
request= (DomainsBuilder()
.domain_id("domain-id")
.build_verification_request())
response=ms.domains.get_domain_verification_status(request)frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.domain_id("domain-id")
.build_list_request())
response=ms.identities.list_identities(request)frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.identity_id("identity-id")
.build_get_request())
response=ms.identities.get_identity(request)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)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)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)frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.identity_id("identity-id")
.build_delete_request())
response=ms.identities.delete_identity(request)frommailersendimportMailerSendClient, IdentityBuilderms=MailerSendClient()
request= (IdentityBuilder()
.email("support@yourdomain.com")
.build_delete_by_email_request())
response=ms.identities.delete_identity_by_email(request)frommailersendimportMailerSendClient, InboundBuilderms=MailerSendClient()
request= (InboundBuilder()
.domain_id("domain-id")
.build_list_request())
response=ms.inbound.list(request)frommailersendimportMailerSendClient, InboundBuilderms=MailerSendClient()
request= (InboundBuilder()
.inbound_id("inbound-id")
.build_get_request())
response=ms.inbound.get(request)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)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)frommailersendimportMailerSendClient, InboundBuilderms=MailerSendClient()
request= (InboundBuilder()
.inbound_id("inbound-id")
.build_delete_request())
response=ms.inbound.delete_inbound_route(request)frommailersendimportMailerSendClient, MessagesBuilderms=MailerSendClient()
request= (MessagesBuilder()
.build_list_request())
response=ms.messages.list_messages(request)frommailersendimportMailerSendClient, MessagesBuilderms=MailerSendClient()
request= (MessagesBuilder()
.message_id("message-id")
.build_get_request())
response=ms.messages.get_message(request)frommailersendimportMailerSendClient, SchedulesBuilderms=MailerSendClient()
request= (SchedulesBuilder()
.domain_id("domain-id")
.build_list_request())
response=ms.schedules.list_schedules(request)frommailersendimportMailerSendClient, SchedulesBuilderms=MailerSendClient()
request= (SchedulesBuilder()
.message_id("scheduled-id")
.build_get_request())
response=ms.schedules.get_schedule(request)frommailersendimportMailerSendClient, SchedulesBuilderms=MailerSendClient()
request= (SchedulesBuilder()
.message_id("scheduled-id")
.build_delete_request())
response=ms.schedules.delete_schedule(request)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_recipients_list_request())
response=ms.recipients.list_recipients(request)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.recipient_id("recipient-id")
.build_recipient_get_request())
response=ms.recipients.get_recipient(request)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.recipient_id("recipient-id")
.build_recipient_delete_request())
response=ms.recipients.delete_recipient(request)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_suppression_list_request())
response=ms.recipients.list_blocklist(request)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_suppression_list_request())
response=ms.recipients.list_hard_bounces(request)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_suppression_list_request())
response=ms.recipients.list_spam_complaints(request)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.build_suppression_list_request())
response=ms.recipients.list_unsubscribes(request)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)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.recipients(["bounced@example.com"])
.build_suppression_add_request())
response=ms.recipients.add_hard_bounces(request)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.recipients(["complainer@example.com"])
.build_suppression_add_request())
response=ms.recipients.add_spam_complaints(request)frommailersendimportMailerSendClient, RecipientsBuilderms=MailerSendClient()
request= (RecipientsBuilder()
.domain_id("domain-id")
.recipients(["unsubscribed@example.com"])
.build_suppression_add_request())
response=ms.recipients.add_unsubscribes(request)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)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)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)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)frommailersendimportMailerSendClient, TemplatesBuilderms=MailerSendClient()
request= (TemplatesBuilder()
.domain_id("domain-id")
.page(1)
.limit(25)
.build_templates_list_request())
response=ms.templates.list_templates(request)frommailersendimportMailerSendClient, TemplatesBuilderms=MailerSendClient()
request= (TemplatesBuilder()
.template("template-id")
.build_template_get_request())
response=ms.templates.get_template(request)frommailersendimportMailerSendClient, TemplatesBuilderms=MailerSendClient()
request= (TemplatesBuilder()
.template("template-id")
.build_delete_request())
response=ms.templates.delete_template(request)frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
request= (WebhooksBuilder()
.domain_id("domain-id")
.build_webhooks_list_request())
response=ms.webhooks.list_webhooks(request)frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
request= (WebhooksBuilder()
.webhook_id("webhook-id")
.build_webhook_get_request())
response=ms.webhooks.get_webhook(request)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)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)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)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)frommailersendimportMailerSendClient, WebhooksBuilderms=MailerSendClient()
request= (WebhooksBuilder()
.webhook_id("webhook-id")
.build_webhook_delete_request())
response=ms.webhooks.delete_webhook(request)frommailersendimportMailerSendClient, EmailVerificationBuilderms=MailerSendClient()
request=EmailVerificationBuilder().build_lists()
response=ms.email_verification.list_verifications(request)frommailersendimportMailerSendClient, EmailVerificationBuilderms=MailerSendClient()
request= (EmailVerificationBuilder()
.email_verification_id("list-id")
.build_get())
response=ms.email_verification.get_verification(request)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)frommailersendimportMailerSendClient, EmailVerificationBuilderms=MailerSendClient()
request= (EmailVerificationBuilder()
.email_verification_id("list-id")
.build_verify_list())
response=ms.email_verification.verify_list(request)frommailersendimportMailerSendClient, EmailVerificationBuilderms=MailerSendClient()
request= (EmailVerificationBuilder()
.email_verification_id("list-id")
.build_results())
response=ms.email_verification.get_results(request)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)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)frommailersendimportMailerSendClient, SmsActivityBuilderms=MailerSendClient()
request= (SmsActivityBuilder()
.sms_message_id("sms-message-id")
.build_get_request())
response=ms.sms_activity.get(request)frommailersendimportMailerSendClient, SmsNumbersBuilderms=MailerSendClient()
request= (SmsNumbersBuilder()
.paused(False)
.page(1)
.limit(25)
.build_list_request())
response=ms.sms_numbers.list(request)frommailersendimportMailerSendClient, SmsNumbersBuilderms=MailerSendClient()
request= (SmsNumbersBuilder()
.sms_number_id("sms-number-id")
.build_get_request())
response=ms.sms_numbers.get(request)frommailersendimportMailerSendClient, SmsNumbersBuilderms=MailerSendClient()
request= (SmsNumbersBuilder()
.sms_number_id("sms-number-id")
.paused(True)
.build_update_request())
response=ms.sms_numbers.update(request)frommailersendimportMailerSendClient, SmsNumbersBuilderms=MailerSendClient()
request= (SmsNumbersBuilder()
.sms_number_id("sms-number-id")
.build_delete_request())
response=ms.sms_numbers.delete(request)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)frommailersendimportMailerSendClient, SmsRecipientsBuilderms=MailerSendClient()
request= (SmsRecipientsBuilder()
.sms_recipient_id("recipient-id")
.build_get_request())
response=ms.sms_recipients.get_sms_recipient(request)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)frommailersendimportMailerSendClient, SmsMessagesBuilderms=MailerSendClient()
request= (SmsMessagesBuilder()
.page(1)
.limit(25)
.build_sms_messages_list())
response=ms.sms_messages.list_sms_messages(request)frommailersendimportMailerSendClient, SmsMessagesBuilderms=MailerSendClient()
request= (SmsMessagesBuilder()
.sms_message_id("message-id")
.build_sms_message_get())
response=ms.sms_messages.get_sms_message(request)frommailersendimportMailerSendClient, SmsWebhooksBuilderms=MailerSendClient()
request= (SmsWebhooksBuilder()
.sms_number_id("sms-number-id")
.build_list_request())
response=ms.sms_webhooks.list_sms_webhooks(request)frommailersendimportMailerSendClient, SmsWebhooksBuilderms=MailerSendClient()
request= (SmsWebhooksBuilder()
.sms_webhook_id("webhook-id")
.build_get_request())
response=ms.sms_webhooks.get_sms_webhook(request)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)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)frommailersendimportMailerSendClient, SmsWebhooksBuilderms=MailerSendClient()
request= (SmsWebhooksBuilder()
.sms_webhook_id("webhook-id")
.build_delete_request())
response=ms.sms_webhooks.delete_sms_webhook(request)frommailersendimportMailerSendClient, SmsInboundsBuilderms=MailerSendClient()
request= (SmsInboundsBuilder()
.sms_number_id("sms-number-id")
.enabled(True)
.build_list_request())
response=ms.sms_inbounds.list_sms_inbounds(request)frommailersendimportMailerSendClient, SmsInboundsBuilderms=MailerSendClient()
request= (SmsInboundsBuilder()
.sms_inbound_id("inbound-id")
.build_get_request())
response=ms.sms_inbounds.get_sms_inbound(request)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)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)frommailersendimportMailerSendClient, SmsInboundsBuilderms=MailerSendClient()
request= (SmsInboundsBuilder()
.sms_inbound_id("inbound-id")
.build_delete_request())
response=ms.sms_inbounds.delete_sms_inbound(request)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)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)frommailersendimportMailerSendClient, TokensBuilderms=MailerSendClient()
request= (TokensBuilder()
.token_id("token-id")
.build_token_delete())
response=ms.tokens.delete_token(request)frommailersendimportMailerSendClient, SmtpUsersBuilderms=MailerSendClient()
request= (SmtpUsersBuilder()
.domain_id("domain-id")
.build_smtp_users_list())
response=ms.smtp_users.list_smtp_users(request)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)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)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)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)frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.page(1)
.limit(25)
.build_users_list())
response=ms.users.list_users(request)frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.user_id("user-id")
.build_user_get())
response=ms.users.get_user(request)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)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)frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.user_id("user-id")
.build_user_delete())
response=ms.users.delete_user(request)frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.page(1)
.limit(25)
.build_invites_list())
response=ms.users.list_invites(request)frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.invite_id("invite-id")
.build_invite_get())
response=ms.users.get_invite(request)frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.invite_id("invite-id")
.build_invite_resend())
response=ms.users.resend_invite(request)frommailersendimportMailerSendClient, UsersBuilderms=MailerSendClient()
request= (UsersBuilder()
.invite_id("invite-id")
.build_invite_cancel())
response=ms.users.cancel_invite(request)frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.page(1)
.limit(25)
.build_list_request())
response=ms.dmarc_monitoring.list_monitors(request)frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.domain_id("your-domain-id")
.build_create_request())
response=ms.dmarc_monitoring.create_monitor(request)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)frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.build_delete_request())
response=ms.dmarc_monitoring.delete_monitor(request)frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.page(1)
.limit(25)
.build_report_request())
response=ms.dmarc_monitoring.get_aggregated_report(request)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)frommailersendimportMailerSendClient, DmarcMonitoringBuilderms=MailerSendClient()
request= (DmarcMonitoringBuilder()
.monitor_id("monitor-id")
.build_report_sources_request())
response=ms.dmarc_monitoring.get_report_sources(request)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)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)frommailersendimportMailerSendClientms=MailerSendClient()
response=ms.api_quota.get_quota()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.
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 operationsThe 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())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.
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())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
# 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=htmlThe 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| Feature group | Endpoint | Available |
|---|---|---|
| Activity | GET activity | ✅ |
| Analytics | GET analytics | ✅ |
| Domains | {GET, POST, PUT, DELETE} domains | ✅ |
POST send | ✅ | |
| Email Verification | {GET, POST, PUT} email-verification | ✅ |
| Bulk Email | POST bulk-email | ✅ |
| Inbound Routes | {GET, POST, PUT, DELETE} inbound | ✅ |
| Messages | GET 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 Sending | POST sms | ✅ |
| SMS Activity | GET sms-activity | ✅ |
| SMS Phone Numbers | {GET, PUT, DELETE} sms-numbers | ✅ |
| SMS Recipients | {GET, PUT} sms-recipients | ✅ |
| SMS Messages | GET 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 Quota | GET 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.
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