altissimo-sendgrid
Reusable SendGrid email client for Altissimo Python projects.
Features
- 📧 Plain text emails via
send_text() - 🎨 HTML emails via
send_html() - 📋 Dynamic templates via
send_template() - 🏗️ Factory method —
SendGridClient.from_env()readsSENDGRID_API_KEYfrom the environment - 🔌 Optional dependency —
sendgridSDK is lazily imported with a helpful error message - 📐 Typed — full type annotations with
py.typedPEP 561 marker - ✅ Consistent return type — all methods return a
SendResultdataclass - 🔄 Retry with backoff — configurable retry for transient failures
- 🔔 Fails loudly — send failures raise
SendGridSendErrorby default; opt out per client for batch sends
Requirements
- Python 3.11+
Installation
Published on PyPI as altissimo-sendgrid;
the import name is altissimo.sendgrid.
pip install "altissimo-sendgrid[sendgrid]" # core + SendGrid SDK
Quick Start
from altissimo.sendgrid import SendGridClient
client = SendGridClient.from_env()
# Plain text
result = client.send_text(
to="user@example.com",
subject="Hello",
body="Welcome aboard!",
)
# HTML
result = client.send_html(
to="user@example.com",
subject="Hello",
html="<h1>Welcome!</h1>",
reply_to="support@example.com",
)
# Template
result = client.send_template(
to="user@example.com",
template_id="d-abc123",
dynamic_data={"first_name": "Alice", "year": 2026},
)
print(result.status_code)
Error Handling
By default a failed send raises SendGridSendError. The originating exception
is preserved as __cause__, and the full SendResult is attached as .result:
from altissimo.sendgrid import SendGridClient, SendGridSendError
try:
result = client.send_html(to="user@example.com", subject="Hi", html="<p>Hi</p>")
except SendGridSendError as exc:
logger.error("Welcome email failed (status=%s): %s", exc.status_code, exc)
else:
logger.info("Welcome email sent: status=%s", result.status_code)
For batch sends where one bad recipient should not abort the run, opt out and
check result.ok yourself:
client = SendGridClient.from_env(raise_on_error=False)
for user in users:
result = client.send_text(to=user.email, subject="Hi", body="Hello")
if not result.ok:
failures.append((user.email, result.status_code, result.error))
SendResult.raise_for_status() converts a result to an exception on demand
(mirroring requests.Response.raise_for_status), which is handy when you want
swallow semantics in one place and raise semantics in another:
client.send_html(to=..., subject=..., html=...).raise_for_status()
Note: the library does not log send failures above
DEBUGwhenraise_on_error=True— it has no recipient or subject/template context worth logging from that frame, and a log there would make the failure look handled. Reporting is the caller's job.
API Reference
SendGridClient
| Method | Description |
|---|---|
SendGridClient(api_key, default_from?, max_retries?, retry_delay?, sandbox_mode?, raise_on_error?) |
Create a client with an explicit API key |
SendGridClient.from_env(env_var?, default_from?, max_retries?, retry_delay?, sandbox_mode?, raise_on_error?) |
Create a client from an environment variable |
send_text(to, subject, body, from_email?, reply_to?, cc?, bcc?, sandbox?) |
Send a plain-text email |
send_html(to, subject, html, from_email?, reply_to?, cc?, bcc?, sandbox?) |
Send an HTML email |
send_template(to, template_id, dynamic_data?, from_email?, reply_to?, cc?, bcc?, sandbox?) |
Send a dynamic template email |
SendResult
| Field | Type | Description |
|---|---|---|
ok |
bool |
Whether the request succeeded (2xx status) |
status_code |
int |
HTTP status code from SendGrid |
body |
str |
Response body |
headers |
dict[str, str] |
Response headers |
error |
str | None |
Error message on failure |
exception |
Exception | None |
Originating exception on failure |
| Method | Description |
|---|---|
raise_for_status(context?) |
Raise SendGridSendError if ok is False; no-op otherwise |
Exceptions
| Exception | Raised when |
|---|---|
SendGridError |
Base class for all library errors |
SendGridImportError |
The sendgrid SDK is not installed |
SendGridSendError |
A send failed (carries status_code and result) |
Architecture
altissimo.sendgrid
├── __init__.py # Public API surface
├── client.py # SendGridClient with lazy SDK initialization
├── exceptions.py # SendGridError, SendGridImportError, SendGridSendError
├── models.py # SendResult and EmailAddress dataclasses
└── py.typed # PEP 561 marker
Development
# Install all dependencies
poetry sync
# Run tests
poetry run pytest
# Run tests with coverage
poetry run pytest --cov=altissimo --cov-report=term-missing
# Run linters
poetry run ruff check .
poetry run ruff format --check .
See CONTRIBUTING.md for detailed development guidelines.
Changelog
See CHANGELOG.md for version history.
Security
For reporting security vulnerabilities, see SECURITY.md.
License
Apache License 2.0 — see LICENSE for details.
Metadata
Release files for altissimo-sendgrid 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| altissimo_sendgrid-0.2.2.tar.gz | 16.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| altissimo_sendgrid-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.0 kB
Release files / altissimo_sendgrid-0.2.2.tar.gz
| Download URL | altissimo_sendgrid-0.2.2.tar.gz |
|---|---|
| Size | 16.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8a1aea00cc4fa1296029a1d1a8f2992f491601342ac389e1ee3bacdc39e9b1df
|
|
BLAKE2b-256 checksum How to use checksums |
f3f9c7cab33e283f3f997b8481830a4c868c2c764bceff83a91faa5bdf813ca9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Sep 28, 2026.
Transparency logRelease files / altissimo_sendgrid-0.2.2-py3-none-any.whl
| Download URL | altissimo_sendgrid-0.2.2-py3-none-any.whl |
|---|---|
| Size | 16.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b8ef7bccef70fa44e411d9ebc5ff74ea6674e882c0697b8d6eb71d1da2126b05
|
|
BLAKE2b-256 checksum How to use checksums |
5ddb556f30b7f603aeb1c1374f0b0f2c89058733beae4c7f3aa4f5018021de48
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Sep 28, 2026.
Transparency log