Python + SMTPfast
SMTPfast's REST API works with any HTTP client. In Python, that means the requests library you probably already have installed.
Prerequisites
- Python 3.8+
requestslibrary (pip install requests)- An SMTPfast account with a verified domain
- An API key from the SMTPfast dashboard
Send Your First Email
import requests
import os
def send_email(to, subject, html):
response = requests.post(
"https://smtpfa.st/api/v1/emails",
headers={
"Authorization": f"Bearer {os.environ['SMTPFAST_API_KEY']}",
"Content-Type": "application/json",
},
json={
"from": "[email protected]",
"to": to,
"subject": subject,
"html": html,
},
)
response.raise_for_status()
return response.json()
result = send_email(
"[email protected]",
"Welcome!",
"<h1>Welcome to our app!</h1>"
)
print(f"Email sent! ID: {result['id']}")
Run it:
SMTPFAST_API_KEY=sf_your_api_key python send_email.py
A Production-Ready Helper
Add retries, timeouts, and proper error handling:
import requests
import os
import time
from typing import Optional
SMTPFAST_URL = "https://smtpfa.st/api/v1/emails"
class SMTPfastError(Exception):
def __init__(self, message, status_code=None):
super().__init__(message)
self.status_code = status_code
def send_email(
to: str | list[str],
subject: str,
html: Optional[str] = None,
text: Optional[str] = None,
from_address: str = "[email protected]",
reply_to: Optional[str] = None,
tags: Optional[list[dict]] = None,
retries: int = 3,
):
payload = {
"from": from_address,
"to": to,
"subject": subject,
}
if html:
payload["html"] = html
if text:
payload["text"] = text
if reply_to:
payload["reply_to"] = reply_to
if tags:
payload["tags"] = tags
headers = {
"Authorization": f"Bearer {os.environ['SMTPFAST_API_KEY']}",
"Content-Type": "application/json",
}
for attempt in range(1, retries + 1):
try:
response = requests.post(
SMTPFAST_URL,
headers=headers,
json=payload,
timeout=10,
)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", "1"))
time.sleep(retry_after)
continue
if not response.ok:
error = response.json()
raise SMTPfastError(error.get("message", "Unknown error"), response.status_code)
return response.json()
except requests.exceptions.RequestException as e:
if attempt == retries:
raise SMTPfastError(f"Request failed after {retries} attempts: {e}")
time.sleep(2 ** attempt * 0.1)
raise SMTPfastError("Max retries exceeded")
FastAPI Integration
Here is how to integrate SMTPfast into a FastAPI application:
from fastapi import FastAPI, HTTPException, BackgroundTasks
from pydantic import BaseModel, EmailStr
app = FastAPI()
class InviteRequest(BaseModel):
email: EmailStr
team_name: str
def send_invite_email(email: str, team_name: str):
"""Send invite email in the background."""
try:
send_email(
to=email,
subject=f"You're invited to join {team_name}",
html=f"<h1>Join {team_name}</h1><p>Click the link below to accept your invitation.</p>",
tags=[{"name": "type", "value": "invite"}],
)
except SMTPfastError as e:
# Log the error - do not crash the background task
print(f"Failed to send invite email: {e}")
@app.post("/api/invite")
async def invite_user(invite: InviteRequest, background_tasks: BackgroundTasks):
# Queue the email send as a background task
background_tasks.add_task(send_invite_email, invite.email, invite.team_name)
return {"status": "invite_sent"}
The key pattern: use BackgroundTasks so the API response returns immediately while the email sends in the background.
Django Integration
For Django, create a utility module and use it from your views:
# emails/utils.py
from django.conf import settings
import requests
def send_transactional_email(to, subject, html, tags=None):
response = requests.post(
"https://smtpfa.st/api/v1/emails",
headers={
"Authorization": f"Bearer {settings.SMTPFAST_API_KEY}",
"Content-Type": "application/json",
},
json={
"from": settings.DEFAULT_FROM_EMAIL,
"to": to,
"subject": subject,
"html": html,
"tags": tags or [],
},
timeout=10,
)
response.raise_for_status()
return response.json()
Add your API key to Django settings:
# settings.py
SMTPFAST_API_KEY = os.environ.get("SMTPFAST_API_KEY")
DEFAULT_FROM_EMAIL = "[email protected]"
Use it in a view:
# views.py
from django.http import JsonResponse
from .utils import send_transactional_email
def password_reset(request):
user = request.user
token = generate_reset_token(user)
send_transactional_email(
to=user.email,
subject="Reset your password",
html=f'<p>Click <a href="https://yourapp.com/reset/{token}">here</a> to reset your password.</p>',
tags=[{"name": "type", "value": "password-reset"}],
)
return JsonResponse({"status": "reset_email_sent"})
For production Django apps, consider using Celery to send emails asynchronously:
# tasks.py
from celery import shared_task
from .utils import send_transactional_email
@shared_task(bind=True, max_retries=3)
def send_email_task(self, to, subject, html, tags=None):
try:
return send_transactional_email(to, subject, html, tags)
except Exception as e:
self.retry(exc=e, countdown=2 ** self.request.retries)
# views.py
from .tasks import send_email_task
def password_reset(request):
user = request.user
token = generate_reset_token(user)
send_email_task.delay(
to=user.email,
subject="Reset your password",
html=f'<p>Click <a href="https://yourapp.com/reset/{token}">here</a> to reset.</p>',
)
return JsonResponse({"status": "reset_email_sent"})
Check Delivery Status
def check_email_status(email_id):
response = requests.get(
f"https://smtpfa.st/api/v1/emails/{email_id}",
headers={
"Authorization": f"Bearer {os.environ['SMTPFAST_API_KEY']}",
},
timeout=10,
)
response.raise_for_status()
data = response.json()
print(f"Status: {data['last_event']}")
return data
Key Takeaways
- Use the
requestslibrary - no special SDK needed - Always set a timeout on HTTP requests
- Handle rate limits (429) with retry-after
- Send emails in the background (FastAPI BackgroundTasks, Django Celery)
- Use environment variables for API keys, never hardcode them
Ready to get started?
Start sending transactional email today. Free to start, no credit card required.
Get Started for FreeRelated Posts
One approval instead of five DNS records: Domain Connect on SMTPfast
If your domain is on Cloudflare, SMTPfast can publish its sending records, and separately the inbound MX, through Domain Connect. You review each set on Cloudflare's screen, approve, and the records are written for you. Here is how it works, what gets written, and what to do when your DNS lives elsewhere.
Logs API and webhook deliveries: answer 'did it send?' without opening the dashboard
Two additions for the debugging side of email: the event log behind the Logs page is now an API, and every webhook has a delivery log with attempts, responses, automatic retries and a retry button.