Skip to content

Templates

Greg Svoboda edited this page Oct 28, 2026 · 2 revisions

Templates

Template management is done through ServerClient. Template pushes across servers use AccountClient.

import postmark

client = postmark.ServerClient("your-server-token")
account = postmark.AccountClient("your-account-token")

Send with a Template

Send a single email using a Postmark template. Reference the template by ID or alias.

import asyncio
from postmark.models.templates import TemplateEmail

async def main():
    # By template ID
    response = await client.outbound.send_with_template(
        TemplateEmail(
            sender="you@example.com",
            to="recipient@example.com",
            template_id=12345,
            template_model={
                "name": "Alice",
                "action_url": "https://example.com/confirm",
            },
        )
    )
    print(f"Sent: {response.message_id}")

    # By template alias (using a dict)
    response = await client.outbound.send_with_template({
        "From": "you@example.com",
        "To": "recipient@example.com",
        "TemplateAlias": "welcome-email",
        "TemplateModel": {
            "name": "Bob",
            "action_url": "https://example.com/confirm",
        },
    })
    print(f"Sent: {response.message_id}")

asyncio.run(main())

Send Batch with Templates

Send multiple templated emails in a single API call.

import asyncio

async def main():
    responses = await client.outbound.send_batch_with_template([
        {
            "From": "you@example.com",
            "To": "alice@example.com",
            "TemplateAlias": "welcome-email",
            "TemplateModel": {"name": "Alice"},
        },
        {
            "From": "you@example.com",
            "To": "bob@example.com",
            "TemplateAlias": "welcome-email",
            "TemplateModel": {"name": "Bob"},
        },
    ])
    for resp in responses:
        if resp.success:
            print(f"  Sent: {resp.message_id}")
        else:
            print(f"  Failed [error_code={resp.error_code}]: {resp.message}")

asyncio.run(main())

As with plain batches, Postmark answers HTTP 200 even when an entry fails (for example an unknown template alias), so check success on every result. A failed entry has no message_id.

List Templates

async def main():
    result = await client.templates.list()
    print(f"Total: {result.total}")
    for t in result.items:
        print(f"  [{t.template_id}] {t.name}  alias={t.alias}")

Filter the list

from postmark.models.templates import TemplateTypeFilter

async def main():
    # Only standard templates, or only layouts
    standard = await client.templates.list(template_type=TemplateTypeFilter.STANDARD)
    layouts = await client.templates.list(template_type=TemplateTypeFilter.LAYOUT)

    # Only the templates that use a particular layout (give the layout's alias)
    branded = await client.templates.list(layout_template="my-layout")
    for t in branded.items:
        print(f"  {t.alias} uses {t.layout_template}")
  • layout_template takes the layout's alias, not its numeric ID. An alias that does not exist is an error (ValidationException), not an empty list.
  • Both filters can be combined with count and offset (count up to 500).

Get a Template

Retrieve a template by its ID or alias.

async def main():
    # By ID
    template = await client.templates.get(12345)
    print(f"Name:    {template.name}")
    print(f"Subject: {template.subject}")

    # By alias
    template = await client.templates.get("welcome-email")

Create a Template

import asyncio
from postmark.models.templates import CreateTemplateRequest

async def main():
    result = await client.templates.create(
        CreateTemplateRequest(
            name="Welcome Email",
            alias="welcome-email",
            subject="Welcome, {{name}}!",
            html_body="<p>Hi {{name}}, thanks for joining!</p>",
            text_body="Hi {{name}}, thanks for joining!",
        )
    )
    print(f"Created: id={result.template_id}  alias={result.alias}")

asyncio.run(main())

Edit a Template

async def main():
    result = await client.templates.edit(
        12345,
        {"Subject": "Updated subject — {{name}}!"},
    )
    print(f"Updated: {result.template_id}")

Delete a Template

async def main():
    await client.templates.delete(12345)
    print("Deleted")

Validate a Template

Check template syntax and preview rendered output before sending.

async def main():
    result = await client.templates.validate({
        "subject": "Hello, {{name}}!",
        "html_body": "<p>Hi {{name}}</p>",
        "test_render_model": {"name": "Alice"},  # sample data used to render a preview
    })
    print(f"All content valid: {result.all_content_is_valid}")
    print(f"Subject valid:     {result.subject.content_is_valid}")
    print(f"Rendered subject:  {result.subject.rendered_content}")
    for err in result.html_body.validation_errors:
        print(f"  line {err.line}: {err.message}")

The request is a flat set of fields (subject, html_body, text_body, test_render_model, ...) and the result has one entry per part you sent. A part you did not send is None.

Push Templates to Another Server

Copy templates from one server to another using AccountClient. Server IDs are the numeric IDs shown in Postmark; they can be passed as integers or as strings.

import asyncio
from postmark.models.templates import PushTemplatesRequest

async def main():
    # Dry run — preview what would change
    result = await account.templates.push({
        "SourceServerID": 12345,
        "DestinationServerID": 67890,
        "PerformChanges": False,
    })
    print(f"Dry run — {result.total_count} template(s) would be affected:")
    for t in result.templates:
        print(f"  action={t.action}  [{t.template_id}]  {t.name}")

    # Apply — push templates for real
    result = await account.templates.push(
        PushTemplatesRequest(
            SourceServerID=12345,
            DestinationServerID=67890,
            PerformChanges=True,
        )
    )
    print(f"Pushed — {result.total_count} template(s) updated.")

asyncio.run(main())

Further Reading

Clone this wiki locally