Skip to content

Templates

Templates let you store message structure on the provider side and only inject variables at send time. This keeps formatting concerns out of application code and makes it easy to update copy without a deployment.

Both MailgunClient and TwilioSmsClient expose a notify_from_template() method that follows the same signature defined on NotificationClient.

Mailgun templates

Mailgun templates are created in the Mailgun dashboard or via the Mailgun API and are identified by name. Variables are passed as keyword arguments and serialized to JSON before the request is sent.

from notificator import EmailAddress
from notificator.mail import MailgunClient

client = MailgunClient(
    domain="mg.example.com",
    api_key="key-...",
    sender_email="no-reply@example.com",
    sender_display_name="My Service",
)

await client.notify_from_template(
    "order_shipped",                          # Mailgun template name
    recipient=EmailAddress("user@example.com"),
    order_id="ORD-1234",
    status="shipped",
    tracking_url="https://track.example.com/ORD-1234",
)

Template versions

Mailgun supports versioned templates. Pass the version name as the version keyword:

await client.notify_from_template(
    "order_shipped",
    recipient=EmailAddress("user@example.com"),
    version="v2",
    order_id="ORD-1234",
)

Twilio Content API templates

Twilio templates use the Content API and are identified by a Content SID (e.g. HXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).

Plain SID

If you only need one version per template, pass the Content SID as a plain string when constructing the client:

from notificator import PhoneNumber
from notificator.sms import TwilioSmsClient

client = TwilioSmsClient(
    account_sid="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    token="your_auth_token",
    sender_phone_number=PhoneNumber("+15551234567"),
    templates=["HXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
)

await client.notify_from_template(
    "HXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    recipient=PhoneNumber("+15557654321"),
    first_name="Ada",
    code="123456",
)

Named templates with a version registry

TwilioSmsTemplate let's you assign a friendly name to a template and map human-readable version aliases to their Content SIDs. This is useful when the same logical template has locale variants or A/B versions stored as separate Content SIDs.

from notificator.sms import TwilioSmsClient, TwilioSmsTemplate

shipping_template = TwilioSmsTemplate(
    id="order_shipped",                  # Friendly name used when calling notify_from_template
    version_registry={
        "en": "HXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",   # English variant SID
        "pl": "HXbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",   # Polish variant SID
    },
)

client = TwilioSmsClient(
    account_sid="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    token="your_auth_token",
    sender_phone_number=PhoneNumber("+15551234567"),
    templates=[shipping_template],
)

# Send the Polish variant
await client.notify_from_template(
    "order_shipped",
    recipient=PhoneNumber("+15557654321"),
    version="pl",
    tracking_url="https://track.example.com/ORD-1234",
)

When version is provided, the client resolves the alias through version_registry to get the actual Content SID before sending.

Variable naming

Keep variable names consistent across templates to simplify integration code. Prefer snake_case names to match Python conventions, since they are passed directly as keyword arguments:

# Consistent naming makes call sites predictable
await client.notify_from_template(
    "welcome",
    recipient=...,
    first_name="Ada",
    verification_link="https://...",
)

Error handling

Exception When it is raised
TemplateNotProvidedError notify_from_template() was called with a template name not registered on the client.
TemplateVersionNotAvailableError The requested version alias is not in the template's version_registry.
from notificator.sms import TemplateNotProvidedError, TemplateVersionNotAvailableError

try:
    await client.notify_from_template("unknown_template", recipient=PhoneNumber("+15557654321"))
except TemplateNotProvidedError as e:
    print(f"Template '{e.template_name}' is not configured for this client.")
except TemplateVersionNotAvailableError as e:
    print(f"Version '{e.version}' not found for template '{e.template_name}'.")

Note

These errors are raised locally before any network call is made, so they are cheap and safe to catch without retry logic.