Python SDK
Official Python SDK for the Freesend email API.
Overview
The Freesend Python SDK provides a simple, reliable way to integrate with the Freesend 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.
Installation
pip install freesendQuick 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 Freesend!",
html="<h1>Welcome!</h1><p>This email was sent using Freesend.</p>",
text="Welcome! This email was sent using Freesend."
)
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="https://freesend.metafog.io" # Optional
)| Option | Type | Required | Description |
|---|---|---|---|
api_key | str | Yes | Your Freesend API key |
base_url | str | No | Custom base URL (defaults to https://freesend.metafog.io) |
Example with Custom Base URL
from freesend import Freesend, FreesendConfig
config = FreesendConfig(
api_key="your-api-key-here",
base_url="https://your-custom-freesend-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) -> SendEmailResponseSends an email using the Freesend API. Raises FreesendValidationError for invalid input, FreesendAPIError for API errors, and FreesendNetworkError for connection issues.
Request: SendEmailRequest
| Field | Type | Required | Description |
|---|---|---|---|
fromName | str | No | Display name for the sender |
fromEmail | str | Yes | Sender email address |
to | str | Yes | Recipient email address |
subject | str | Yes | Email subject line |
html | str | No* | HTML content of the email |
text | str | No* | Plain text content of the email |
attachments | list[Attachment] | No | List of attachment objects |
*At least one of html or text is required.
Response: SendEmailResponse
| Field | Type | Description |
|---|---|---|
message | str | Success message from the API (e.g. "Email sent successfully") |
Attachment
| Field | Type | Required | Description |
|---|---|---|---|
filename | str | Yes | Name of the attachment file |
content | str | Yes** | Base64-encoded file content |
url | str | Yes** | URL to an external file (HTTP/HTTPS) |
contentType | str | No | MIME 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("Freesend error:", e.message)Exception Hierarchy
| Exception | When it's raised |
|---|---|
FreesendValidationError | Invalid or missing request fields (client-side) |
FreesendAPIError | API returned an error (4xx/5xx, invalid JSON) |
FreesendNetworkError | Connection failed, timeout, or other request error |
FreesendError | Base class for all SDK errors; also used for unexpected errors |
Common Error Codes
| Status Code | Description |
|---|---|
| 400 | Bad Request - Missing required fields or invalid data |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - API key is inactive or invalid |
| 500 | Internal 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_emailcalls in try/except and handleFreesendValidationError,FreesendAPIError, andFreesendNetworkErrorexplicitly where it matters. - Use
e.messageande.status_code(onFreesendAPIError) for logging and user-facing messages.
Attachments
- Use base64
contentfor smaller files (API limit is 25MB per attachment). - Use
urlfor larger or already-hosted files; the URL must be publicly accessible (HTTP/HTTPS only). - Set
contentTypefor better behavior in email clients. - Do not send both
contentandurlfor the same attachment; the SDK will raiseFreesendValidationError.
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
Freesendinstance per process (or per request in a web app) and reuse it; the client uses a singlerequests.Sessionunder the hood.
Migration from HTTP API
If you're calling the Freesend API with requests or urllib directly, you can switch to the SDK like this:
Before (raw HTTP)
import requests
response = requests.post(
"https://freesend.metafog.io/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.messageThe SDK handles validation, headers, serialization, and error mapping for you.
Support
- SDK source: sdk/python
- PyPI: freesend
- GitHub Issues: Report bugs or request features
- API reference: Send Email API