Skip to content

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 SMTPProvider are automatically configured with a retry policy, making them resilient to transient failures.
  • Structured Payloads: Uses Pydantic models like EmailPayload to 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:

  1. NotificationProtocol: A simple contract that all providers must implement. It defines a primary send(payload) method.
  2. NotificationPayload: A set of Pydantic models that define the structure for different types of notifications (e.g., EmailPayload).
  3. 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 a NullNotificationProvider that performs no action, preventing application errors.
  4. Provider Creators: For providers with complex dependencies, like the SMTPProvider which requires a ResilienceOrchestrator, 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.