Send emails with FastAPI

In this quickstart, you'll learn how to send transactional emails from your FastAPI app with Sidemail. You'll set up the SDK, send your first email, and see examples for common use cases like welcome emails, password resets, and background tasks.

Before you start

  1. Create a Sidemail account → get your API key
  2. Add a sending domain → set up your domain for sending

1. Install

pip install sidemail

2. Configure API key

Add your Sidemail API key to .env:

SIDEMAIL_API_KEY=your-api-key

3. Setup client

Create a shared instance of the Sidemail client.

# services.py
from sidemail import Sidemail
import os

# The SDK automatically reads SIDEMAIL_API_KEY from environment variables
sidemail = Sidemail()

4. Send a welcome email

Send an email when a user registers. We use a standard def route so FastAPI runs the synchronous Sidemail SDK in a threadpool, preventing it from blocking the event loop.

# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from .services import sidemail

app = FastAPI()

class User(BaseModel):
    email: str
    name: str

@app.post("/register")
def register(user: User):
    # ... create user in database ...

    sidemail.send_email(
        toAddress=user.email,
        fromAddress="[email protected]",
        fromName="Your App",
        templateName="Welcome",
        templateProps={"firstName": user.name},
    )

    return {"message": "User registered"}

5. Send a password reset email

# main.py
class PasswordResetRequest(BaseModel):
    email: str

@app.post("/forgot-password")
def forgot_password(request: PasswordResetRequest):
    token = "secure-reset-token" # Generate this securely

    sidemail.send_email(
        toAddress=request.email,
        fromAddress="[email protected]",
        fromName="Your App",
        templateName="Password Reset",
        templateProps={
            "actionUrl": f"https://myapp.com/reset/{token}",
        },
    )

    return {"message": "Reset email sent"}

6. Send a weekly report

You can create a standalone script for cron jobs.

# scripts/send_weekly_report.py
from myapp.services import sidemail

def main():
    # In a real app, fetch this from your database
    new_signups = 150
    chart_data = [100, 200, 300, 400, 200, 300, 200, 500]

    sidemail.send_email(
        toAddress="[email protected]",
        fromAddress="[email protected]",
        fromName="My App",
        templateName="Weekly Report",
        templateProps={
            "signups": new_signups,
            "chart": chart_data,
        },
    )
    print("Weekly report sent")

if __name__ == "__main__":
    main()

Run it via cron:

# Run every Monday at 8:00 AM
0 8 * * 1 python -m scripts.send_weekly_report

7. Send email via Background Tasks

Decouple email sending from the response using FastAPI's BackgroundTasks. This allows you to return a response immediately while the email sends in the background.

# main.py
from fastapi import BackgroundTasks

def send_welcome_email_task(email: str, name: str):
    sidemail.send_email(
        toAddress=email,
        fromAddress="[email protected]",
        fromName="My App",
        templateName="Welcome",
        templateProps={"firstName": name},
    )

@app.post("/register-async")
async def register_async(user: User, background_tasks: BackgroundTasks):
    # ... create user in database ...

    background_tasks.add_task(send_welcome_email_task, user.email, user.name)

    return {"message": "User registered, email sending in background"}

8. Send HTML email

Use jinja2 to generate HTML from templates.

from fastapi.templating import Jinja2Templates

templates = Jinja2Templates(directory="templates")

@app.post("/send-invoice")
def send_invoice(email: str):
    # templates/invoice.html
    template = templates.get_template("invoice.html")
    html_content = template.render(amount=99)

    sidemail.send_email(
        toAddress=email,
        fromAddress="[email protected]",
        fromName="Your App",
        subject="Your Invoice",
        html=html_content,
    )

    return {"message": "Invoice sent"}

9. Send Markdown email

Store your markdown content in a file and load it (learn more).

def send_markdown():
    with open("templates/emails/welcome.md", "r") as f:
        markdown_content = f.read()

    # Subject and sender are defined in the markdown frontmatter
    sidemail.send_email(
        toAddress="[email protected]",
        markdown=markdown_content,
        templateProps={
            "name": "John",
            "link": "https://example.com",
        },
    )

10. Send plain text email

sidemail.send_email(
    toAddress="[email protected]",
    fromAddress="[email protected]",
    fromName="Your App",
    subject="Hello",
    text="Hello! 👋",
)

11. Schedule email

Send email later. Set scheduledAt to an ISO date string.

import datetime

# Schedule for 1 hour from now
scheduled_at = (datetime.datetime.utcnow() + datetime.timedelta(hours=1)).isoformat() + "Z"

sidemail.send_email(
    toAddress="[email protected]",
    fromAddress="[email protected]",
    fromName="Your App",
    templateName="Welcome",
    templateProps={"firstName": "Alex"},
    scheduledAt=scheduled_at,
)

12. Send with attachment

Use the Sidemail.file_to_attachment helper to attach files.

from sidemail import Sidemail

with open("invoice.pdf", "rb") as f:
    pdf_data = f.read()

attachment = Sidemail.file_to_attachment("invoice.pdf", pdf_data)

sidemail.send_email(
    toAddress="[email protected]",
    fromAddress="[email protected]",
    fromName="Your App",
    subject="Your invoice",
    text="See attached.",
    attachments=[attachment],
)

13. Handle errors

from sidemail import SidemailError
import logging

logger = logging.getLogger(__name__)

try:
    sidemail.send_email(
        # ...
    )
except SidemailError as e:
    logger.error(f"Sidemail error: {e.message}")