Skip to content
Development
Skill

/litestar-email

Use when working with litestar_email, EmailPlugin, EmailConfig, EmailService, EmailMessage, SMTPConfig, ResendConfig, SendGridConfig, MailgunConfig, SESConfig. Not for marketing APIs — use vendor SDKs.

From plugin
litestar
1720 skills1 agent2 hooks

Claude Code

$ npx -y skills add litestar-org/litestar-skills --skill litestar-email --agent claude-code

SKILL.md

litestar-email.SKILL.md
name: litestar-email
description: "Use when working with litestar_email, EmailPlugin, EmailConfig, EmailService, EmailMessage, SMTPConfig, ResendConfig, SendGridConfig, MailgunConfig, SESConfig. Not for marketing APIs — use vendor SDKs."

litestar-email

`litestar-email` 0.4.0 provides one async sending interface for console, memory, SMTP, Resend, SendGrid, Mailgun, Amazon SES, and custom backends. Match the backend already selected by the project; keep message construction independent from the transport.

Code Style Rules

  • Use `NamedDependency[EmailService]` with `Provide(email_config.provide_service().__aiter__)`

(or `FromDishka[EmailService]` when the project uses Dishka) for direct `EmailService` handler injection.

  • Pass recipient collections as `list[str]`. `to`, `cc`, `bcc`, and `reply_to`

are list fields.

  • Pass attachment content as `bytes`. Do file I/O before constructing the

message and keep that I/O async.

  • Await `send_message()` and `send_messages()`. Both return the count sent.
  • Keep API keys and SMTP credentials in the project's settings layer.

Quick Reference

Install

pip install "litestar-email>=0.4.0"
pip install "litestar-email[smtp]>=0.4.0"   # aiosmtplib
pip install "litestar-email[ses]>=0.4.0"    # botocore for SigV4
pip install "litestar-email[httpx]>=0.4.0"   # default HTTP transport
pip install "litestar-email[aiohttp]>=0.4.0" # alternative HTTP transport

The HTTP API backends select `httpx` by default, but the transport is optional in `litestar-email` itself. Install the `httpx` or `aiohttp` extra (unless the project already provides that dependency), and select `aiohttp` only when the project standardizes on it.

Configure the Plugin

from os import environ

from litestar import Litestar
from litestar_email import EmailConfig, EmailPlugin, SMTPConfig

email_config = EmailConfig(
    backend=SMTPConfig(
        host="smtp.example.com",
        port=587,
        username=environ["SMTP_USERNAME"],
        password=environ["SMTP_PASSWORD"],
        use_tls=True,
    ),
    from_email="noreply@example.com",
    from_name="Example App",
)

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

`EmailConfig` fields:

| Field | Default | Contract | | --- | --- | --- | | `backend` | `"console"` | Registered name, import path, or built-in backend config object | | `from_email` | `"noreply@localhost"` | Default sender address | | `from_name` | `""` | Default display name | | `fail_silently` | `False` | Backend-specific best-effort delivery behavior | | `email_service_dependency_key` | `"mailer"` | Litestar DI key | | `email_service_state_key` | `"mailer"` | Key holding the config in app state |

The dependency and state keys occupy separate namespaces. Change them independently when the application already uses either key:

email_config = EmailConfig(
    backend="memory",
    email_service_dependency_key="email_service",
    email_service_state_key="email_config",
)

Inject `EmailService`

`EmailPlugin.on_app_init()` registers:

  • `Provide(config.provide_service, sync_to_thread=False)` under `email_service_dependency_key`;
  • `config.signature_namespace` (`BaseEmailBackend`, `EmailConfig`, `EmailMessage`,

`EmailMultiAlternatives`, `EmailService`, `MailgunConfig`, `ResendConfig`, `SESConfig`, `SMTPConfig`, `SendGridConfig`) in Litestar's signature namespace;

  • the `EmailConfig` instance under `email_service_state_key` in app state.

Because `EmailConfig.provide_service()` is a synchronous method returning an `AsyncServiceProvider` instance rather than an `async def` generator function, Litestar's default `Provide(config.provide_service, sync_to_thread=False)` injects `AsyncServiceProvider` rather than `EmailService`.

To inject an open `EmailService` with request-scoped connection cleanup, bind `Provide(email_config.provide_service().__aiter__)` on the router, controller, or handler (or use Dishka's `FromDishka[EmailService]`):

from litestar import post
from litestar.di import NamedDependency, Provide
from litestar_email import EmailConfig, EmailMessage, EmailService

email_config = EmailConfig(backend="memory", from_email="noreply@example.com")


@post(
    "/notifications",
    dependencies={"mailer": Provide(email_config.provide_service().__aiter__)},
)
async def send_notification(
    mailer: NamedDependency[EmailService],
) -> dict[str, int]:
    sent = await mailer.send_message(
        EmailMessage(
            subject="Notification",
            body="You have a new notification.",
            to=["recipient@example.com"],
        ),
    )
    return {"sent": sent}

If using the plugin's default dependency directly without overriding `dependencies`, register `signature_types=[AsyncServiceProvider]`, annotate the parameter as `mailer: NamedDependency[AsyncServiceProvider]`, and enter `async with mailer as service:` inside the handler.

If the project uses Dishka, yield `EmailService` from a `Scope.REQUEST` provider and inject `FromDishka[EmailService]`:

from collections.abc import AsyncIterator

from dishka import Provider, Scope
from dishka.integrations.litestar import FromDishka, inject
from litestar import post
from litestar_email import EmailConfig, EmailMessage, EmailService


def build_email_provider(config: EmailConfig) -> Provider:
    async def provide_mailer() -> AsyncIterator[EmailService]:
        async with config.provide_service() as mailer:
            yield mailer

    provider = Provider(scope=Scope.REQUEST)
    provider.provide(provide_mailer)
    return provider


@post("/welcome")
@inject
async def send_welcome(
    email_service: FromDishka[EmailService],
) -> dict[str, int]:
    sent = await email_service.send_message(
        EmailMessage(subject="Welcome", body="Hello!", to=["user@example.com"]),
    )
    return {"sent": sent}

App state does not contain a permanently open `EmailService`. Use `plugin.get_service(app.state

Read more
@litestar-org
Ships withlitestar

Opinionated, first-party agent skills, plugins, subagents, hooks, and rules for the Litestar framework and its ecosystem — published from a single-root repository across Google Antigravity, Claude Code, Codex CLI, Cursor, OpenCode, and VS Code / Copilot.

1720 skills1 agent
Get the whole plugin

Stars on GitHub

Momentum

stars in total
17
Star history of litestar-org/litestar-skills on GitHub, a chart by star-history.com

Other skills on litestar.

advanced-alchemy

advanced-alchemy

Use when working with advanced_alchemy, alembic/, SQLAlchemyAsyncRepositoryService, SQLAlchemyAsyncConfig, repository_type,…

litestar-autowire

litestar-autowire

Use when working with litestar_autowire, AutowirePlugin, AutowireConfig, domain_packages, AutowireIntegration, AutowireLoader, or…

litestar-build

litestar-build

Use when working with uv build, uv_build, hatch build, PyApp, scie-jump, PYAPP_*, wheel assets, GitHub release matrices,…

litestar-docs

litestar-docs

Use when working with zensical.toml, docs/conf.py, sphinx, shibuya, litestar-sphinx-theme, mkdocstrings, Griffe, objects.inv, or…

litestar-granian

litestar-granian

Use when working with litestar_granian, GranianPlugin, litestar run Granian options, runtime threads, HTTP/2, TLS, access logs,…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about litestar-email.

Which coding agents can use litestar-email?
litestar-email installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.