Docs
Python SDK

Python SDK

Official Python SDK for the WeSend email API.

Overview

The WeSend Python SDK provides a simple, reliable way to integrate with the WeSend email API from Python. It supports Python 3.7+ and offers a clean, dataclass-based interface for sending emails with optional attachments (base64 or URL). Use it in scripts, web apps, or background workers.

WeSend is based on Freesend; the SDK packages keep their upstream names (freesend, @freesend/sdk).

Installation

pip install freesend

Quick Start

from freesend import Freesend, SendEmailRequest, FreesendConfig
 
config = FreesendConfig(api_key="your-api-key-here")
freesend = Freesend(config)
 
email_data = SendEmailRequest(
    fromName="Your Company",
    fromEmail="hello@yourdomain.com",
    to="recipient@example.com",
    subject="Hello from WeSend!",
    html="<h1>Welcome!</h1><p>This email was sent using WeSend.</p>",
    text="Welcome! This email was sent using WeSend."
)
 
response = freesend.send_email(email_data)
print(response.message)  # "Email sent successfully"

Configuration

FreesendConfig

The client is configured via a FreesendConfig instance:

from freesend import FreesendConfig
 
config = FreesendConfig(
    api_key="your-api-key-here",
    base_url="http://localhost:3000"  # Optional
)
OptionTypeRequiredDescription
api_keystrYesYour WeSend API key
base_urlstrNoCustom base URL (defaults to http://localhost:3000)

Example with Custom Base URL

from freesend import Freesend, FreesendConfig
 
config = FreesendConfig(
    api_key="your-api-key-here",
    base_url="https://your-custom-wesend-instance.com"
)
freesend = Freesend(config)

Using Environment Variables

Keep API keys out of source code by using environment variables:

import os
from freesend import Freesend, FreesendConfig
 
config = FreesendConfig(api_key=os.getenv("FREESEND_API_KEY", "your-api-key-here"))
freesend = Freesend(config)

API Reference

send_email

send_email(data: SendEmailRequest) -> SendEmailResponse

Sends an email using the WeSend API. Raises FreesendValidationError for invalid input, FreesendAPIError for API errors, and FreesendNetworkError for connection issues.

Request: SendEmailRequest

FieldTypeRequiredDescription
fromNamestrNoDisplay name for the sender
fromEmailstrYesSender email address
tostrYesRecipient email address
subjectstrYesEmail subject line
htmlstrNo*HTML content of the email
textstrNo*Plain text content of the email
replyTostrNoReply-to email address
ccstrNoCC recipient(s), comma-separated
bccstrNoBCC recipient(s), comma-separated
attachmentslist[Attachment]NoList of attachment objects

*At least one of html or text is required.

Response: SendEmailResponse

FieldTypeDescription
messagestrSuccess message from the API (e.g. "Email sent successfully")

Attachment

FieldTypeRequiredDescription
filenamestrYesName of the attachment file
contentstrYes**Base64-encoded file content
urlstrYes**URL to an external file (HTTP/HTTPS)
contentTypestrNoMIME type (e.g. application/pdf, image/png)

**Either content or url is required, but not both.

Examples

Basic Email

from freesend import Freesend, SendEmailRequest, FreesendConfig
 
freesend = Freesend(FreesendConfig(api_key="your-api-key-here"))
 
try:
    response = freesend.send_email(SendEmailRequest(
        fromName="Your Company",
        fromEmail="hello@yourdomain.com",
        to="user@example.com",
        subject="Welcome to our platform!",
        html="<h1>Welcome!</h1><p>Thank you for joining us.</p>",
        text="Welcome! Thank you for joining us."
    ))
    print("Email sent:", response.message)
except Exception as e:
    print("Failed to send email:", e)

Email with Base64 Attachment

import base64
from freesend import Freesend, SendEmailRequest, FreesendConfig, Attachment
 
freesend = Freesend(FreesendConfig(api_key="your-api-key-here"))
 
with open("invoice.pdf", "rb") as f:
    file_content = base64.b64encode(f.read()).decode("utf-8")
 
attachment = Attachment(
    filename="invoice.pdf",
    content=file_content,
    contentType="application/pdf"
)
 
try:
    response = freesend.send_email(SendEmailRequest(
        fromName="Your Company",
        fromEmail="billing@yourdomain.com",
        to="customer@example.com",
        subject="Your invoice is ready",
        html="<h1>Invoice Attached</h1><p>Please find your invoice attached.</p>",
        text="Invoice attached. Please find your invoice attached.",
        attachments=[attachment]
    ))
    print("Email sent:", response.message)
except Exception as e:
    print("Failed to send email:", e)

Email with URL-based Attachment

from freesend import Freesend, SendEmailRequest, FreesendConfig, Attachment
 
freesend = Freesend(FreesendConfig(api_key="your-api-key-here"))
 
try:
    response = freesend.send_email(SendEmailRequest(
        fromName="Your Company",
        fromEmail="reports@yourdomain.com",
        to="team@example.com",
        subject="Monthly Report",
        html="<h1>Monthly Report</h1><p>Please find the monthly report attached.</p>",
        text="Monthly Report - Please find the monthly report attached.",
        attachments=[
            Attachment(
                filename="monthly-report.pdf",
                url="https://example.com/reports/monthly-report.pdf",
                contentType="application/pdf"
            )
        ]
    ))
    print("Email sent:", response.message)
except Exception as e:
    print("Failed to send email:", e)

Multiple Attachments

from freesend import Freesend, SendEmailRequest, FreesendConfig, Attachment
 
freesend = Freesend(FreesendConfig(api_key="your-api-key-here"))
 
try:
    response = freesend.send_email(SendEmailRequest(
        fromName="Your Company",
        fromEmail="support@yourdomain.com",
        to="customer@example.com",
        subject="Your order details",
        html="<h1>Order Confirmation</h1><p>Please find your order details attached.</p>",
        text="Order Confirmation - Please find your order details attached.",
        attachments=[
            Attachment(
                filename="invoice.pdf",
                url="https://example.com/invoices/12345.pdf",
                contentType="application/pdf"
            ),
            Attachment(
                filename="receipt.jpg",
                url="https://example.com/receipts/12345.jpg",
                contentType="image/jpeg"
            )
        ]
    ))
    print("Email sent:", response.message)
except Exception as e:
    print("Failed to send email:", e)

Error Handling

The SDK raises specific exception types for different failures. Catch them for precise handling:

from freesend import Freesend, SendEmailRequest, FreesendConfig
from freesend.exceptions import FreesendError, FreesendAPIError, FreesendValidationError, FreesendNetworkError
 
freesend = Freesend(FreesendConfig(api_key="your-api-key-here"))
 
try:
    response = freesend.send_email(SendEmailRequest(
        fromEmail="hello@yourdomain.com",
        to="user@example.com",
        subject="Test email"
        # Missing html/text - will raise FreesendValidationError
    ))
except FreesendValidationError as e:
    print("Validation error:", e.message)
except FreesendAPIError as e:
    print("API error:", e.message)
    print("Status code:", e.status_code)
except FreesendNetworkError as e:
    print("Network error:", e.message)
except FreesendError as e:
    print("WeSend error:", e.message)

Exception Hierarchy

ExceptionWhen it's raised
FreesendValidationErrorInvalid or missing request fields (client-side)
FreesendAPIErrorAPI returned an error (4xx/5xx, invalid JSON)
FreesendNetworkErrorConnection failed, timeout, or other request error
FreesendErrorBase class for all SDK errors; also used for unexpected errors

Common Error Codes

Status CodeDescription
400Bad Request - Missing required fields or invalid data
401Unauthorized - Invalid or missing API key
403Forbidden - API key is inactive or invalid
500Internal Server Error - Email sending failed

Python Version and Type Hints

The SDK supports Python 3.7+ and uses type hints throughout. All request and response types are dataclasses, so you get clear constructor signatures and optional IDE support:

from freesend import Freesend, SendEmailRequest, SendEmailResponse, FreesendConfig
 
config = FreesendConfig(api_key="your-api-key-here")
freesend = Freesend(config)
 
# Type-checked request
email_data = SendEmailRequest(
    fromEmail="hello@yourdomain.com",
    to="user@example.com",
    subject="Test",
    html="<h1>Hello</h1>",
    text="Hello"
)
 
# Response is SendEmailResponse
response: SendEmailResponse = freesend.send_email(email_data)
print(response.message)

Best Practices

Error handling

  • Wrap send_email calls in try/except and handle FreesendValidationError, FreesendAPIError, and FreesendNetworkError explicitly where it matters.
  • Use e.message and e.status_code (on FreesendAPIError) for logging and user-facing messages.

Attachments

  • Use base64 content for smaller files (API limit is 25MB per attachment).
  • Use url for larger or already-hosted files; the URL must be publicly accessible (HTTP/HTTPS only).
  • Set contentType for better behavior in email clients.
  • Do not send both content and url for the same attachment; the SDK will raise FreesendValidationError.

API keys

  • Prefer environment variables (e.g. FREESEND_API_KEY) over hardcoding.
  • Do not commit API keys to version control.
  • Rotate keys periodically.

Client reuse

  • Create one Freesend instance per process (or per request in a web app) and reuse it; the client uses a single requests.Session under the hood.

Migration from HTTP API

If you're calling the WeSend API with requests or urllib directly, you can switch to the SDK like this:

Before (raw HTTP)

import requests
 
response = requests.post(
    "http://localhost:3000/api/send-email",
    headers={
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}",
    },
    json={
        "fromEmail": "hello@yourdomain.com",
        "to": "user@example.com",
        "subject": "Test",
        "html": "<p>Hello</p>",
        "text": "Hello",
    },
)
result = response.json()

After (SDK)

from freesend import Freesend, SendEmailRequest, FreesendConfig
 
freesend = Freesend(FreesendConfig(api_key=api_key))
result = freesend.send_email(SendEmailRequest(
    fromEmail="hello@yourdomain.com",
    to="user@example.com",
    subject="Test",
    html="<p>Hello</p>",
    text="Hello",
))
# result is a SendEmailResponse with result.message

The SDK handles validation, headers, serialization, and error mapping for you.

Support