Skip to main content

litestar-email

Email support for Litestar applications. This plugin provides a pluggable email backend system for sending transactional emails with support for multiple providers.

Installation

pip install litestar-email

For production backends, install with the appropriate extra:

# SMTP backend
pip install litestar-email[smtp]

# Amazon SES backend (adds botocore for SigV4 signing)
pip install litestar-email[ses]

# aiohttp transport (alternative to httpx for API backends)
pip install litestar-email[aiohttp]

Note: API backends (Resend, SendGrid, Mailgun, SES) use httpx which is bundled with Litestar. No extra HTTP transport installation is needed. SES additionally requires the [ses] extra for AWS Signature Version 4 signing.

Usage

from litestar import Litestar
from litestar_email import EmailConfig, EmailPlugin

# Development: console output
config = EmailConfig(
    backend="console",
    from_email="noreply@example.com",
    from_name="My App",
)

app = Litestar(plugins=[EmailPlugin(config=config)])

For production, pass a backend config object directly:

from litestar_email import EmailConfig, EmailPlugin, SMTPConfig

config = EmailConfig(
    backend=SMTPConfig(host="smtp.example.com", port=587, use_tls=True),
    from_email="noreply@example.com",
)

app = Litestar(plugins=[EmailPlugin(config=config)])

Sending Email

from litestar_email import EmailMessage

message = EmailMessage(
    subject="Welcome!",
    body="Thanks for signing up.",
    to=["user@example.com"],
)

async with config.provide_service() as mailer:
    await mailer.send_message(message)

If message.from_email is omitted, the service uses config.from_email and config.from_name as defaults.

Dependency Injection

The plugin registers a mailer dependency for handlers by default:

from litestar import get
from litestar_email import EmailMessage, EmailService

@get("/welcome/{email:str}")
async def send_welcome(email: str, mailer: EmailService) -> dict[str, str]:
    message = EmailMessage(
        subject="Welcome!",
        body="Thanks for signing up.",
        to=[email],
    )
    await mailer.send_message(message)
    return {"status": "sent"}

This works for both router handlers and controller methods the same way, since the dependency is registered on the app.

If you need a service outside of Litestar (e.g., for a worker), use config.get_service() for a one-off instance or config.provide_service() for batch sending.

Events and Listeners

Event listeners in Litestar execute outside request context and cannot receive DI-injected dependencies. Pass the mailer explicitly:

from litestar import Litestar, get
from litestar.events import listener
from litestar_email import EmailConfig, EmailMessage, EmailPlugin, EmailService, SMTPConfig

config = EmailConfig(
    backend=SMTPConfig(host="localhost", port=1025),
    from_email="noreply@example.com",
    from_name="My App",
)

@get("/register/{email:str}")
async def register(email: str, mailer: EmailService) -> dict[str, str]:
    # Pass the DI-injected mailer to the event
    request.app.emit("user.registered", email, mailer=mailer)
    return {"status": "queued"}

@listener("user.registered")
async def on_user_registered(email: str, mailer: EmailService) -> None:
    # mailer is passed explicitly from emit(), not injected via DI
    await mailer.send_message(
        EmailMessage(subject="Welcome!", body="Thanks for signing up.", to=[email]),
    )

app = Litestar(
    plugins=[EmailPlugin(config=config)],
    listeners=[on_user_registered],
)

You can override the dependency and state keys via EmailConfig if needed: email_service_dependency_key="email_service" and email_service_state_key="email_service".

Standalone (No Litestar)

Use the config helpers directly without Litestar:

from litestar_email import EmailConfig, EmailMessage, SMTPConfig

config = EmailConfig(
    backend=SMTPConfig(host="localhost", port=1025),
    from_email="noreply@example.com",
)
message = EmailMessage(
    subject="Hello!",
    body="This is a standalone send.",
    to=["user@example.com"],
)

async with config.provide_service() as mailer:
    await mailer.send_message(message)

For batch sends, use the context manager to reuse the connection:

async with config.provide_service() as mailer:
    await mailer.send_messages([message1, message2, message3])

HTML Email

from litestar_email import EmailMultiAlternatives

message = EmailMultiAlternatives(
    subject="Welcome!",
    body="Thanks for signing up.",  # Plain text fallback
    html_body="<h1>Welcome!</h1><p>Thanks for signing up.</p>",
    to=["user@example.com"],
)

Available Backends

Backend Config Class Use Case
console - Development (prints to stdout)
memory - Testing (stores in memory)
smtp SMTPConfig Production SMTP servers
resend ResendConfig Resend HTTP API
sendgrid SendGridConfig SendGrid HTTP API
mailgun MailgunConfig Mailgun HTTP API
ses SESConfig Amazon SES API v2 (SigV4-signed)

API backends (Resend, SendGrid, Mailgun, SES) support configurable HTTP transports:

from litestar_email import ResendConfig

# Default: uses httpx (bundled with Litestar)
config = ResendConfig(api_key="re_xxx...")

# Alternative: use aiohttp
config = ResendConfig(api_key="re_xxx...", http_transport="aiohttp")

Testing

The InMemoryBackend is designed for testing:

from litestar_email.backends import InMemoryBackend

def test_sends_welcome_email():
    InMemoryBackend.clear()

    # ... code that sends email ...

    assert len(InMemoryBackend.outbox) == 1
    assert InMemoryBackend.outbox[0].subject == "Welcome!"

If you need direct backend access in tests, use config.get_backend():

from litestar_email import EmailConfig, EmailMessage

config = EmailConfig(backend="memory")
backend = config.get_backend()

message = EmailMessage(subject="Hello", body="Body", to=["user@example.com"])
await backend.send_messages([message])

Development

make install    # Install dependencies
make test       # Run tests
make lint       # Run linting
make check-all  # Run all checks

License

MIT

Metadata

Release files for litestar-email 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for litestar-email 0.4.0
File Size Uploaded
litestar_email-0.4.0.tar.gz 245.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for litestar-email 0.4.0
File Interpreter ABI Platform
litestar_email-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 290.3 kB

Release files / litestar_email-0.4.0.tar.gz

Download URL litestar_email-0.4.0.tar.gz
Size 245.0 kB
Tags Source
SHA-256 checksum
How to use checksums
942c101f1afb3c9d5c3fe528023cbba5657d5b7ad2ee7e1a699d6da0ba8c7670
BLAKE2b-256 checksum
How to use checksums
7b73b07fbe4eb1a88443d33d4a31f75c8f31b4dce706a9df5f67d1a6c0e298cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 3, 2026.

Transparency log

Release files / litestar_email-0.4.0-py3-none-any.whl

Download URL litestar_email-0.4.0-py3-none-any.whl
Size 45.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
de79248036647d6a7008bbe9505ff58fa994797eb82e0f71378e02661fbe02ec
BLAKE2b-256 checksum
How to use checksums
c7dd66846552f682441702c556ce2353d27890cd04bb4027d1bcce8f5ee40c5a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page