Skip to main content

altissimo-sendgrid

CI Python License Code style: ruff

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() reads SENDGRID_API_KEY from the environment
  • 🔌 Optional dependency — sendgrid SDK is lazily imported with a helpful error message
  • 📐 Typed — full type annotations with py.typed PEP 561 marker
  • ✅ Consistent return type — all methods return a SendResult dataclass
  • 🔄 Retry with backoff — configurable retry for transient failures
  • 🔔 Fails loudly — send failures raise SendGridSendError by 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 DEBUG when raise_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)

Source distribution for altissimo-sendgrid 0.2.2
File Size Uploaded
altissimo_sendgrid-0.2.2.tar.gz 16.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for altissimo-sendgrid 0.2.2
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.2.2 This release

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