litestar-org/litestar-skills/litestar-email
Claude Code and agent skill by litestar-org/litestar-skills
- community
Checking that the SKILL.md file is still in the repository.
Use when working with litestar_email, EmailPlugin, EmailConfig, EmailService, EmailMessage, SMTPConfig, ResendConfig, SendGridConfig, MailgunConfig, SESConfig. Not for marketing APIs — use vendor SDKs.
Install
npx vskill@latest install litestar-org/litestar-skills/litestar-emailSKILL.md
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]withProvide(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, andreply_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()andsend_messages(). Both return the count sent. - Keep API keys and SMTP credentials in the project's settings layer.
Quick Reference
Install
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
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:
Inject EmailService
EmailPlugin.on_app_init() registers:
Provide(config.provide_service, sync_to_thread=False)underemail_service_dependency_key;config.signature_namespace(BaseEmailBackend,EmailConfig,EmailMessage,
EmailMultiAlternatives, EmailService, MailgunConfig, ResendConfig, SESConfig, SMTPConfig, SendGridConfig) in Litestar's signature namespace;
- the
EmailConfiginstance underemail_service_state_keyin 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]):
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]:
App state does not contain a permanently open EmailService. Use plugin.get_service(app.state) or config.get_service(app.state) when code outside handler DI needs a service derived from app state.
Construct Messages
subject and body are required constructor arguments. Recipient lists have empty-list defaults, so provide at least one delivery recipient before sending.
EmailMessage does not accept html_body or from_name. Put a per-message display name in from_email, as shown above. Use EmailMultiAlternatives.html_body for the HTML convenience constructor:
The message collections have these exact shapes:
| Field | Type | |
|---|---|---|
to, cc, bcc, reply_to | list[str] | |
headers | dict[str, str] | |
attachments | list[tuple[str, bytes, str]] | |
alternatives | list[tuple[str, str]] |
recipients() returns to + cc + bcc; it does not include reply_to.
Pick a Backend
| Existing project constraint | Configuration | Extra | |
|---|---|---|---|
| Local output only | backend="console" | None | |
| Unit or integration tests | backend="memory" | None | |
| SMTP server or Mailpit | backend=SMTPConfig(...) | smtp | |
| Existing Resend account | backend=ResendConfig(...) | httpx or aiohttp | |
| Existing SendGrid account | backend=SendGridConfig(...) | httpx or aiohttp | |
| Existing Mailgun account | backend=MailgunConfig(...) | httpx or aiohttp | |
| Existing AWS SES setup | backend=SESConfig(...) | ses plus httpx or aiohttp | |
| Project-owned backend | Registered name or backend-class import path | Project-specific |
Backend config fields:
| Config | Fields and defaults | |
|---|---|---|
SMTPConfig | host="localhost", port=25, username=None, password=None, use_tls=False, use_ssl=False, timeout=30 | |
ResendConfig | api_key="", timeout=30, http_transport="httpx" | |
SendGridConfig | api_key="", timeout=30, http_transport="httpx" | |
MailgunConfig | api_key="", domain="", region="us", timeout=30, http_transport="httpx" | |
SESConfig | region="us-east-1", aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None, timeout=30, http_transport="httpx" |
For SMTP, use_tls=True performs STARTTLS after connecting; use_ssl=True uses implicit TLS. Select the mode required by the SMTP server.
For HTTP backends, http_transport accepts "httpx", "aiohttp", or an HTTPTransport class (from litestar_email.transports import HTTPTransport, HTTPResponse, get_transport). Keep the default when the project has no transport preference.
For custom backends, subclass BaseEmailBackend and either pass its dotted import path to EmailConfig(backend="my_app.email.CustomBackend") or register a short name with @email_backend("custom"). Inspect registered names with list_backends() and resolve classes or instances with get_backend_class() or get_backend(). ConsoleBackend also accepts stream: TextIO | None = None when instantiated directly.
Amazon SES Contract
The 0.4.0 SES backend:
- calls the SES API v2
SendEmailendpoint withSimplecontent; - signs the exact transmitted JSON bytes with botocore SigV4;
- uses explicit
SESConfigcredentials when bothaws_access_key_idand
aws_secret_access_key are set (with optional aws_session_token);
- otherwise uses botocore's default credential chain;
- supports text plus the first
text/htmlalternative; - supports
to,cc,bcc, and the completereply_tolist; - rejects attachments with
EmailDeliveryErrorbecauseSimplecontent does
not support raw MIME attachments;
- rejects messages with neither a non-empty text body nor an HTML alternative;
- always propagates
EmailRateLimitErrorandEmailAuthenticationError, even
when fail_silently=True (all HTTP API backends — Resend, SendGrid, Mailgun, and SES — always propagate EmailRateLimitError).
Use SMTP or another attachment-capable backend when the message includes files. Do not imply that SES 0.4.0 sends raw MIME content.
Service Lifecycle
Outside a service context, each send_message() or send_messages() call creates, opens, and closes a backend. Inside config.provide_service() or async with EmailService(config), calls reuse one open backend until context exit. When bound via Provide(config.provide_service().__aiter__) (or a Dishka request-scoped async generator), DI enters and closes that context per request.
send_messages([]) returns 0. send_message(message) delegates to send_messages([message]) and returns 0 or 1.
Exception Hierarchy
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/litestar-email/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/litestar-org/litestar-skills/litestar-email)