Notifications
Overview
The Notification module provides a reliable, extensible, and provider-agnostic system for sending notifications, with an initial focus on email. It is designed to decouple your application's business logic from the specific details of how notifications are delivered.
Key Features
- Multi-Provider Support: Comes with built-in providers for SMTP and a console logger, and can be easily extended to support others like SendGrid or Twilio.
- Resilient by Default: Network-based providers like the
SMTPProviderare automatically configured with a retry policy, making them resilient to transient failures. - Structured Payloads: Uses Pydantic models like
EmailPayloadto ensure that all necessary data for a notification is provided in a structured and validated way. - Centralized Configuration: All provider settings, including credentials and retry policies, are managed in a single configuration section.
How It Works
The module is built around a few key abstractions:
NotificationProtocol: A simple contract that all providers must implement. It defines a primarysend(payload)method.NotificationPayload: A set of Pydantic models that define the structure for different types of notifications (e.g.,EmailPayload).NotificationFactory: A singleton factory that is the main entry point for the application. It reads the configuration and instantiates the correct provider (e.g.,SMTPProvider). If notifications are disabled in the settings, it safely returns aNullNotificationProviderthat performs no action, preventing application errors.- Provider Creators: For providers with complex dependencies, like the
SMTPProviderwhich requires aResilienceOrchestrator, a dedicated creator class handles the dependency injection, ensuring the provider is properly assembled.
Available Providers
SMTPProvider: Sends emails using a standard SMTP server. This provider is automatically wrapped with a retry mechanism.ConsoleNotificationProvider: Does not send any real notifications. Instead, it prints the content of the notification payload to the console, making it perfect for local development and testing.NullNotificationProvider: A "no-op" provider that does absolutely nothing. It is used as a safe fallback when the notification module is disabled in the configuration.
Usage Example
Sending an email is a simple, two-step process: build the payload and send it using the factory.
from nala.athomic.notification import NotificationFactory
from nala.athomic.notification.payloads import EmailPayload
async def send_welcome_email(user_email: str, user_name: str):
# 1. Create the structured payload
email = EmailPayload(
to=[user_email],
subject=f"Welcome, {user_name}!",
body="Thank you for joining our platform.",
html_body="<p>Thank you for joining our platform.</p>"
)
try:
# 2. Get the configured provider and send the payload
notifier = NotificationFactory.create()
success = await notifier.send(email)
if success:
print("Welcome email sent successfully!")
else:
print("Failed to send welcome email.")
except Exception as e:
print(f"An error occurred: {e}")
Configuration
Notifications are configured under the [notifications] section in your settings.toml.
Console Provider Example (for Development)
[default.notifications]
enabled = true
default_from_email = "dev@nala.com"
[default.notifications.provider]
backend = "console"
SMTP Provider Example (for Production)
[default.notifications]
enabled = true
default_from_email = "noreply@nala.com"
# Configure a retry policy for sending emails
[default.notifications.retry]
attempts = 3
wait_min_seconds = 1.0
backoff = 2.0
# Configure the SMTP provider
[default.notifications.provider]
backend = "smtp"
host = "smtp.mailprovider.com"
port = 587
username = "my-user"
# The password should always be a secret reference
password = { path = "smtp/prod", key = "password" } # pragma: allowlist secret
use_tls = true
API Reference
nala.athomic.notification.protocol.NotificationProtocol
Bases: Protocol
Protocol defining the standard interface for notification providers.
close()
async
Closes connections or releases resources, if applicable.
is_available()
async
Checks if the provider is configured and ready.
send(payload)
async
Sends a notification based on the provided payload.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
payload
|
NotificationPayload
|
A structured data object (e.g., EmailPayload, SMSPayload) containing all necessary information for the notification. |
required |
Returns: bool: True if sending was successful, False otherwise.
nala.athomic.notification.factory.NotificationFactory
Factory responsible for creating and managing the singleton instance of the configured NotificationProtocol provider.
It uses a Registry for provider discovery and implements a fallback to NullProvider if the notifications module is disabled in settings.
clear()
classmethod
Clears the singleton instance.
Primarily used for test isolation to ensure fresh setup between tests.
create(settings=None)
classmethod
Retrieves or creates the singleton instance of the NotificationProtocol.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
Optional[NotificationSettings]
|
Optional explicit settings to override application configuration. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If no provider creator is registered for the configured backend. |
RuntimeError
|
If initialization of the concrete provider fails. |
Returns:
| Name | Type | Description |
|---|---|---|
NotificationProtocol |
NotificationProtocol
|
The shared singleton instance. |
nala.athomic.notification.payloads.EmailPayload
Bases: BasePayload
Specific payload structure required for sending email notifications.
nala.athomic.notification.providers.smtp_provider.SMTPProvider
Bases: BaseNotification, CredentialResolve
SMTPProvider implementation specialized for EmailPayload, using a resilience orchestrator.
close()
async
Closes any open resources. (No-op for smtplib as connection is per-send).
is_available()
async
Verifies SMTP availability by sending a NOOP command.
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the SMTP connection was successful, False otherwise. |