micromailer
Ultra-fast, modular, zero-dependency async email engine for Python 3.12+.
- Zero runtime dependencies
- Async SMTP via stdlib
smtplib(works on 3.12, 3.13, 3.14) - HTTP API backend for Resend / SES-style providers
SMTPPoolfor connection reuse in bulk sendsvalidate_htmlandrender_templateutilities- PEP 561 typed package (
py.typed)
Install
pip install micromailer
Quick start
import asyncio
from micromailer import AsyncSMTPMailer
async def main() -> None:
async with AsyncSMTPMailer(
host="smtp.gmail.com",
port=587,
username="you@gmail.com",
password="app-password",
) as mailer:
await mailer.send(
to="friend@example.com",
subject="Hello",
html_body="<p>Hi</p>",
)
asyncio.run(main())
Sending patterns
All patterns are async-first. Use async with so the connection is always closed.
Single recipient
await mailer.send(
to="alex@example.com",
subject="Your grade",
html_body="<p>Grade: A</p>",
)
Multiple recipients
await mailer.send(
to=["alex@example.com", "jordan@example.com"],
subject="Your grade",
html_body="<p>Grade: A</p>",
)
Custom sender
await mailer.send(
to="alex@example.com",
subject="Hi",
html_body="<p>Hello</p>",
sender="registrar@university.edu",
)
Plain-text email
text = "Hello,\n\nYour grade is A.\n"
html = f"<pre>{text}</pre>"
await mailer.send(to="alex@example.com", subject="Grade", html_body=html)
HTML email with inline CSS
html = """
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h1 style="color: #1a73e8;">Results</h1>
<p style="color: #444;">Grade: <strong>A</strong></p>
</div>
"""
await mailer.send(to="alex@example.com", subject="Results", html_body=html)
Implicit TLS (port 465)
async with AsyncSMTPMailer(
host="smtp.gmail.com",
port=465,
username="you@gmail.com",
password="app-password",
use_tls=True,
) as mailer:
await mailer.send(to="friend@example.com", subject="Hello", html_body="<p>Hi</p>")
Bulk sends with SMTPPool
from micromailer import SMTPPool
async def bulk(contacts: list[dict]) -> None:
async with SMTPPool(max_size=5, host="smtp.gmail.com", port=587,
username="you@gmail.com", password="app-password") as pool:
for contact in contacts:
mailer = await pool.acquire()
try:
await mailer.send(
to=contact["email"],
subject="Newsletter",
html_body="<p>Hello</p>",
)
finally:
await pool.release(mailer)
HTTP API backend (Resend / SES)
from micromailer import AsyncHTTPMailer
async def send_via_api() -> None:
async with AsyncHTTPMailer(api_key="re_xxx", base_url="https://api.resend.com") as mailer:
await mailer.send(
to="alex@example.com",
subject="Hello",
html_body="<p>Hi from API</p>",
)
Error handling
from micromailer.core.base import SMTPError
try:
await mailer.send(to="alex@example.com", subject="Hi", html_body="<p>Hi</p>")
except SMTPError as e:
print(f"SMTP failed: {e.code} -> {e}")
except Exception as e:
print(f"Unexpected error: {type(e).__name__} -> {e}")
Utilities
from micromailer import validate_html, render_template, encode_base64
validate_html("<div><p>ok</p></div>") # []
validate_html("<div><p>oops</div>") # ["Unclosed tag <div>", ...]
render_template("Hi {name}", {"name": "Alex"}) # "Hi Alex"
encode_base64("raw bytes") # "cmF3IGJ5dGVz"
Module layout
core.base—MailerBackendprotocol,SMTPError,MailerResult,MailerBatchcore.smtp—AsyncSMTPMailercore.http—AsyncHTTPMailercore.pool—SMTPPoolutils.mime—validate_html,render_template,encode_base64,decode_base64
Metadata
Release files for micromailer 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| micromailer-1.0.0.tar.gz | 5.5 kB | Without provenance | Details for micromailer-1.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| micromailer-1.0.0-py3-none-any.whl | Python 3 | none | any | Details for micromailer-1.0.0-py3-none-any.whl |
Total release size: 14.1 kB
Release files / micromailer-1.0.0.tar.gz
| Download URL | micromailer-1.0.0.tar.gz |
|---|---|
| Size | 5.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5d02dbf2bfbf74fd802b531b72923a5148bdb2375e3270dd0310a76ef177eb18
|
|
BLAKE2b-256 checksum How to use checksums |
eb6af52ee6ba884b4ca28ea9880483705e0c3b69c7e66710dbdbd33d1f7d396d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / micromailer-1.0.0-py3-none-any.whl
| Download URL | micromailer-1.0.0-py3-none-any.whl |
|---|---|
| Size | 8.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c14deea18237f3044c4dd2891b11d2709d04b4f3464ff296cce02d19668c5042
|
|
BLAKE2b-256 checksum How to use checksums |
28a2daca364c8bd807b0d2ddb0fba4389fb625d2f1d9081665c3d636e32f0723
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for micromailer 1.0.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.