---------------------------------------------------------------------- This is the API documentation for the listmonk library. ---------------------------------------------------------------------- ## Configuration & Authentication Point the client at your Listmonk instance and authenticate. set_url_base(url: str) Set the base URL of your Listmonk instance for all subsequent calls. Each Listmonk instance lives at its own address, for example https://listmonk.somedomain.tech. This must be called before login() and any other API operation. A trailing slash, if present, is removed. Args: url: The base URL of your instance, including the http:// or https:// scheme but without the /api path segment. Raises: ValidationError: If url is empty or whitespace, or if it does not start with the http:// or https:// scheme. get_base_url() -> str | None Return the configured base URL of your Listmonk instance. Each Listmonk instance lives at its own address, for example https://listmonk.somedomain.tech. This getter returns whatever value was previously stored by set_url_base(). Returns: The base URL of your instance (without a trailing slash), or None if set_url_base() has not been called yet. login(user_name: str, pw: str, timeout_config: httpx2.Timeout | None = None) -> bool Log into Listmonk and cache the credentials for the life of your app. The username and password are validated against the server's health endpoint using HTTP Basic auth. On success they are stored in module-level state and reused by every subsequent API call, so you only need to call this once. set_url_base() must be called first. Args: user_name: Your Listmonk username. pw: Your Listmonk password. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: True if the credentials were accepted by the server. Returns False if the server rejected them or could not be reached (no HTTP error is raised in that case). Raises: OperationNotAllowedError: If the base URL has not been set via set_url_base(). ValidationError: If user_name or pw is empty. Examples: >>> import listmonk >>> listmonk.set_url_base('https://listmonk.somedomain.tech') >>> listmonk.login('admin', 'super-secret') True verify_login(timeout_config: httpx2.Timeout | None = None) -> bool Verify that the stored login credentials are still valid at the server. This is a thin alias for is_healthy(): it issues an authenticated request to the server's health endpoint using the cached credentials. Any error (not logged in, network failure, rejected credentials) is reported as False rather than raised. Args: timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: True if the stored credentials are still valid, False otherwise. is_healthy(timeout_config: httpx2.Timeout | None = None) -> bool Check whether the server is reachable and the stored credentials are valid. Issues an authenticated GET to the Listmonk health endpoint using the cached username and password. This call is defensive: any failure—the URL base not being set, not being logged in, a network error, a non-2xx response, or an unparseable body—is caught and reported as False, so it never raises. Args: timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: True if the server responded healthy with valid credentials, False otherwise. ## Mailing Lists Read and manage mailing lists. lists(timeout_config: httpx2.Timeout | None = None) -> list[listmonk.models.MailingList] Get all mailing lists on the server. Retrieves every mailing list in a single request (paged at one large page), so no manual pagination is required. Args: timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A list of MailingList objects with the full details of each list. Returns an empty list if the server has no mailing lists. Raises: OperationNotAllowedError: If the base URL is not set or you are not logged in. ValidationError: If the server returns an empty or invalid JSON response. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. list_by_id(list_id: int, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.MailingList | None Get the full details of a single mailing list by its ID. Args: list_id: The numeric ID of the list to retrieve, e.g. 7. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A MailingList object with the full details of the requested list. Raises: OperationNotAllowedError: If the base URL is not set or you are not logged in. ValidationError: If the server returns an empty or invalid JSON response. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. Exception: If the server returns a result set that does not contain the requested list_id (a workaround for a known Listmonk server quirk). create_list(list_name: str, list_type: str = 'public', optin: str = 'single', tags: list[str] | None = None, description: str | None = None) -> listmonk.models.MailingList | None Create a new mailing list on the server. The list name is stripped of surrounding whitespace before submission. Args: list_name: Name of the new list. Required and must be non-empty after whitespace is stripped. list_type: Visibility of the list. One of 'public' or 'private'. Defaults to 'public'. optin: Opt-in mode. One of 'single' or 'double'. Defaults to 'single'. tags: Optional list of tag strings to associate with the list. description: Optional free-text description for the new list. Returns: The MailingList object that was created on the server, including its assigned id and uuid. Raises: OperationNotAllowedError: If the base URL is not set or you are not logged in. ValueError: If list_name is empty, or if list_type or optin is not one of its accepted values. ValidationError: If the server returns an empty or invalid JSON response. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. Examples: >>> import listmonk >>> new_list = listmonk.create_list('Newsletter', list_type='public', optin='double') >>> new_list.id 7 update_list(list_id: int, list_name: str | None = None, list_type: str | None = None, status: str | None = None, optin: str | None = None, tags: list[str] | None = None, description: str | None = None) -> listmonk.models.MailingList | None Update an existing mailing list on the server. Only the parameters you pass (that are not None) are included in the update payload, so omitted fields are left unchanged. Args: list_id: The numeric ID of the list to update. Required. list_name: Optional new name for the list (stripped of surrounding whitespace). list_type: Optional new visibility. One of 'public' or 'private'. status: Optional new status. One of 'active' or 'archived'. optin: Optional new opt-in mode. One of 'single' or 'double'. tags: Optional new list of tag strings for the list. description: Optional new description for the list. Returns: The updated MailingList object as returned by the server. Raises: OperationNotAllowedError: If the base URL is not set or you are not logged in. ValueError: If list_id is missing, or if list_type, status, or optin is not one of its accepted values. ValidationError: If the server returns an empty or invalid JSON response. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. delete_list(list_id: int) -> bool Delete a mailing list by its ID. The list's existence is checked first via list_by_id; if it does not exist, no delete request is sent and False is returned. Args: list_id: The numeric ID of the list to delete. Must be a truthy value (0 or None is rejected). Returns: True if the server reports the list was deleted, False if the list does not exist or the server response does not confirm deletion. Raises: OperationNotAllowedError: If the base URL is not set or you are not logged in. ValueError: If list_id is missing or falsy. ValidationError: If the server returns an empty or invalid JSON response. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ## Subscribers Create, query, update, and manage the status of subscribers. subscribers(query_text: str | None = None, list_id: int | None = None, timeout_config: httpx2.Timeout | None = None) -> list[listmonk.models.Subscriber] Get the list of subscribers matching the given criteria, or all subscribers if no criteria are given. Results are fetched page by page (500 per page) and combined, so a broad query may issue several HTTP requests and return a large list. Subscribers are ordered by ``updated_at`` descending. Args: query_text: Optional SQL-like filter applied server-side, e.g. ``"subscribers.attribs->>'city' = 'Portland'"``. See https://listmonk.app/docs/querying-and-segmentation/ for the syntax. Defaults to None (no filter). list_id: Optional list ID; when given, only subscribers belonging to that list (and matching ``query_text``, if any) are returned. Defaults to None. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A list of models.Subscriber objects matching the criteria. Returns an empty list (never None) if nothing matches. Raises: OperationNotAllowedError: If the base URL has not been set or you have not logged in. ValidationError: If the server returns an empty body or invalid JSON. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. subscriber_by_email(email: str, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Subscriber | None Retrieve a single subscriber by their email address (e.g. "some_user@talkpython.fm"). The email is matched exactly against ``subscribers.email`` on the server (a ``+`` in the address is URL-encoded automatically), and the first matching subscriber is returned. Args: email: Email address of the subscriber to look up (e.g. "some_user@talkpython.fm"). timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: The matching models.Subscriber, or None if no subscriber has that email. Raises: OperationNotAllowedError: If the base URL has not been set or you have not logged in. ValidationError: If the server returns an empty body or invalid JSON. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. subscriber_by_id(subscriber_id: int, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Subscriber | None Retrieve a single subscriber by their numeric Listmonk ID (e.g. 201). The ID is matched against ``subscribers.id`` on the server and the first matching subscriber is returned. Args: subscriber_id: Numeric ID of the subscriber to look up (e.g. 201). timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: The matching models.Subscriber, or None if no subscriber has that ID. Raises: OperationNotAllowedError: If the base URL has not been set or you have not logged in. ValidationError: If the server returns an empty body or invalid JSON. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. subscriber_by_uuid(subscriber_uuid: str, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Subscriber | None Retrieve a single subscriber by their UUID (e.g. "c37786af-e6ab-4260-9b49-740adpcm6ed"). The UUID is matched against ``subscribers.uuid`` on the server and the first matching subscriber is returned. Args: subscriber_uuid: UUID of the subscriber to look up (e.g. "c37786af-e6ab-4260-9b49-740adpcm6ed"). timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: The matching models.Subscriber, or None if no subscriber has that UUID. Raises: OperationNotAllowedError: If the base URL has not been set or you have not logged in. ValidationError: If the server returns an empty body or invalid JSON. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. create_subscriber(email: str, name: str | None = None, list_ids: set[int] = None, pre_confirm: bool = False, attribs: dict[str, Any] | None = None, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Subscriber Create a new subscriber on the Listmonk server. The email is lowercased and stripped and the name is stripped before the request is sent. The subscriber is always created with a global status of ``enabled``. Args: email: Email address of the subscriber. Required and must be non-empty after stripping. name: Full name (e.g. "first last") of the subscriber. Defaults to None (stored as an empty string). list_ids: Set of list IDs to subscribe this person to. Defaults to None (no lists). pre_confirm: When True, mark the new subscriptions as confirmed immediately so no double opt-in confirmation email is sent. Defaults to False. attribs: Custom attributes to store on the subscriber record (queryable in the subscriber UI). Defaults to None (stored as an empty dict). timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: The newly created models.Subscriber, populated by the server with its ID, UUID, and more. Raises: ValueError: If email is empty. OperationNotAllowedError: If the base URL has not been set or you have not logged in. ValidationError: If the server returns an empty body or invalid JSON. httpx.HTTPStatusError: If the server rejects the request (e.g. a 4xx for a duplicate email) or returns a 5xx status. Examples: >>> import listmonk >>> sub = listmonk.create_subscriber( ... email='some_user@talkpython.fm', ... name='Some User', ... list_ids={1, 4}, ... pre_confirm=True, ... attribs={'city': 'Portland'}, ... ) >>> sub.id 201 update_subscriber(subscriber: listmonk.models.Subscriber | None, add_to_lists: set[int] | None = None, remove_from_lists: set[int] | None = None, status: listmonk.models.SubscriberStatuses = , timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Subscriber | None Update many aspects of a subscriber: email and name, custom attribute data, list membership, and status. Final list membership is computed from the subscriber's existing lists minus ``remove_from_lists`` plus ``add_to_lists``, and the affected subscriptions are preconfirmed. You can enable, disable, or block a subscriber here, but if that is all you want to do there are dedicated, simpler functions (enable_subscriber, disable_subscriber, block_subscriber). Args: subscriber: The full subscriber object to update, with the changed fields already set. Must have a valid id. add_to_lists: List IDs to add this subscriber to. Defaults to None (treated as an empty set). remove_from_lists: List IDs to remove this subscriber from. Defaults to None (treated as an empty set). status: The subscriber's status, one of SubscriberStatuses.enabled, .disabled, or .blocklisted. Defaults to SubscriberStatuses.enabled. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: The refreshed subscriber object fetched from the server after the update, or None if the subscriber can no longer be found. Raises: ValueError: If subscriber is None or has no id. OperationNotAllowedError: If the base URL is not set or you are not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the follow-up fetch returns an empty or invalid JSON response. add_subscribers_to_lists(subscriber_ids: Iterable[int], list_ids: Iterable[int], timeout_config: httpx2.Timeout | None = None, status: str = 'confirmed') -> bool Add a number of subscribers to a number of lists in a single bulk operation. Args: subscriber_ids: An iterable of subscriber IDs to add. Duplicates are de-duplicated. list_ids: An iterable of target list IDs to subscribe them to. Duplicates are de-duplicated. timeout_config: Optional per-request timeout; defaults to 10 seconds. status: The subscription status to assign on the target lists, e.g. 'confirmed' or 'unconfirmed'. Defaults to 'confirmed'. Returns: True on success. False if either ID set is empty or contains only 0, or if the server responds with an error status. Raises: OperationNotAllowedError: If the base URL is not set or you are not logged in. enable_subscriber(subscriber: listmonk.models.Subscriber, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Subscriber | None Set a subscriber's status to enabled so they will receive campaigns. This is a convenience wrapper around update_subscriber that changes only the status. Args: subscriber: The subscriber to enable. Must have a valid id. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: The refreshed subscriber object from the server, or None if the subscriber can no longer be found. Raises: ValueError: If subscriber is None or has no id. OperationNotAllowedError: If the base URL is not set or you are not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the follow-up fetch returns an empty or invalid JSON response. disable_subscriber(subscriber: listmonk.models.Subscriber | None, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Subscriber | None Set a subscriber's status to disabled, pausing their subscription so they will not receive campaigns. This is a convenience wrapper around update_subscriber that changes only the status. Args: subscriber: The subscriber to disable. Must have a valid id. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: The refreshed subscriber object from the server, or None if the subscriber can no longer be found. Raises: ValueError: If subscriber is None or has no id. OperationNotAllowedError: If the base URL is not set or you are not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the follow-up fetch returns an empty or invalid JSON response. block_subscriber(subscriber: listmonk.models.Subscriber, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Subscriber | None Add a subscriber to the blocklist, effectively unsubscribing them so they will not receive any mail. This is a convenience wrapper around update_subscriber that sets the status to SubscriberStatuses.blocklisted. Use delete_subscriber instead if you want to remove the subscriber record entirely. Args: subscriber: The subscriber to block/unsubscribe. Must have a valid id. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: The refreshed subscriber object from the server, or None if the subscriber can no longer be found. Raises: ValueError: If subscriber is None or has no id. OperationNotAllowedError: If the base URL is not set or you are not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the follow-up fetch returns an empty or invalid JSON response. confirm_optin(subscriber_uuid: str | None, list_uuid: str | None, timeout_config: httpx2.Timeout | None = None) -> bool Confirm a subscriber's opt-in to a list via the API. For opt-in lists, subscribers are added as unconfirmed first. Call this to opt them in, but only when they are genuinely opting in (for example, from your own opt-in form handled in your code). This submits the public opt-in form on the subscription endpoint rather than calling a JSON API, so HTTP errors are reported as a False return value rather than raised. Args: subscriber_uuid: The Subscriber.uuid value for the subscriber. Must be non-empty. list_uuid: The MailingList.uuid value for the list. Must be non-empty. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: True if the opt-in succeeded, False if the server responded with a non-success status. Raises: ValueError: If subscriber_uuid or list_uuid is empty. OperationNotAllowedError: If the base URL is not set or you are not logged in. delete_subscriber(email: str | None = None, overriding_subscriber_id: int | None = None, timeout_config: httpx2.Timeout | None = None) -> bool Completely delete a subscriber from your system (as if they were never there). If your goal is to unsubscribe them rather than erase them, use block_subscriber instead. The email is normalized (lowercased and stripped) before lookup. When both arguments are given, overriding_subscriber_id takes precedence. Args: email: Email of the subscriber to delete. Required unless overriding_subscriber_id is provided. overriding_subscriber_id: Optional ID of the subscriber to delete; takes precedence over email. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: True if the subscriber was successfully deleted. False if no subscriber matched the given email (when no overriding id was provided) or if the server reported the delete as unsuccessful. Raises: ValueError: If neither email nor overriding_subscriber_id is provided. OperationNotAllowedError: If the base URL is not set or you are not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the server returns an empty or invalid JSON response. ## Campaigns Create, preview, update, and delete email campaigns. campaigns(timeout_config: httpx2.Timeout | None = None) -> list[listmonk.models.Campaign] Get all campaigns on the server. Fetches the full list of campaigns in a single request (the server is asked for up to one million results per page), so no pagination is required. Args: timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A list of Campaign objects, each with the full details of that campaign. Returns an empty list if the instance has no campaigns. Raises: OperationNotAllowedError: If the base URL is not set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the server returns an empty body or invalid JSON. campaign_by_id(campaign_id: int, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Campaign | None Get the full details of a campaign with the given ID. Args: campaign_id: The numeric ID of the campaign to fetch, e.g. 7. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A Campaign object with the full details of the campaign, or None if the server returns no campaign data for the given ID. Raises: OperationNotAllowedError: If the base URL is not set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the server returns an empty body or invalid JSON. campaign_preview_by_id(campaign_id: int, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.CampaignPreview | None Get the rendered preview of a campaign with the given ID. Args: campaign_id: The numeric ID of the campaign to preview, e.g. 7. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A CampaignPreview object whose ``preview`` attribute holds the rendered HTML body returned by the server. Raises: OperationNotAllowedError: If the base URL is not set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. create_campaign(name: str | None = None, subject: str | None = None, list_ids: set[int] | None = None, from_email: str | None = None, campaign_type: str | None = None, content_type: str | None = None, body: str | None = None, alt_body: str | None = None, send_at: datetime.datetime | None = None, messenger: str | None = None, template_id: int | None = None, tags: list[str] | None = None, headers: dict[str, str | None] | None = None, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Campaign | None Create a new campaign with the given parameters. Name and subject are required; all other fields fall back to defaults (for example, ``list_ids`` defaults to the single list {1} and ``from_email`` falls back to the instance settings when omitted). Args: name: The internal name of the campaign. Required. subject: The email subject line. Required. list_ids: A set of list IDs to send the campaign to. Defaults to {1}. from_email: The 'From' address for campaign emails. Defaults to the instance setting when not provided. campaign_type: The campaign type, 'regular' or 'optin'. content_type: The body format: 'richtext', 'html', 'markdown', or 'plain'. body: The campaign body in the configured content type. alt_body: The optional plain-text alternative body for multipart HTML emails. send_at: Optional timestamp at which to schedule the campaign. messenger: The delivery channel, usually 'email'. template_id: The ID of the template used to render the campaign. tags: A list of tags to attach to the campaign. headers: A list of custom email headers, each a single-entry dict. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A Campaign object with the full details of the newly created campaign. Raises: ValueError: If ``name`` or ``subject`` is not provided. OperationNotAllowedError: If the base URL is not set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the server returns an empty body or invalid JSON. Examples: >>> import listmonk >>> campaign = listmonk.create_campaign( ... name='June Newsletter', ... subject='Our June Update', ... list_ids={1, 2}, ... content_type='html', ... body='

Hello

', ... ) >>> campaign.id 7 update_campaign(campaign: listmonk.models.Campaign, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Campaign | None Update an existing campaign with the provided campaign information. The campaign's target lists are normalized to their IDs before sending, and a ``send_at`` value already in the past is dropped so the update does not fail on a stale scheduled time. After the update succeeds, the campaign is re-fetched from the server and returned. Args: campaign: The Campaign object containing the updated information. Must have a valid ``id``. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: The updated Campaign object as freshly fetched from the server, or None if the campaign can no longer be found after the update. Raises: ValueError: If ``campaign`` is None or has no ``id``. OperationNotAllowedError: If the base URL is not set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the follow-up fetch returns an empty or invalid JSON response. delete_campaign(campaign_id: int | None = None, timeout_config: httpx2.Timeout | None = None) -> bool Completely delete a campaign from your system. The campaign is first looked up by ID; if no such campaign exists the function returns False without issuing a delete request. Args: campaign_id: The numeric ID of the campaign to delete. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: True if the campaign was successfully deleted; False if no campaign with the given ID was found or the server reported it was not deleted. Raises: ValueError: If ``campaign_id`` is not provided. OperationNotAllowedError: If the base URL is not set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the server returns an empty body or invalid JSON. ## Templates Manage email templates and set the default. templates(timeout_config: httpx2.Timeout | None = None) -> list[listmonk.models.Template] Retrieve all templates defined on the Listmonk instance. This fetches both campaign and transactional templates in a single (large) paginated request. Args: timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A list of models.Template objects, one per template on the server. Returns an empty list if no templates are defined. Raises: OperationNotAllowedError: If the base URL has not been set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the response is empty or is not valid JSON. template_by_id(template_id: int, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Template | None Retrieve a single template by its numeric ID. Args: template_id: The numeric ID of the template to retrieve, e.g. 7. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A models.Template built from the server's response for the given ID. Raises: OperationNotAllowedError: If the base URL has not been set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status (e.g. an unknown template ID). ValidationError: If the response is empty or is not valid JSON. template_preview_by_id(template_id: int, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.TemplatePreview | None Render and return a preview of a template. The preview is rendered by the server using lorem-ipsum sample content, so it can be inspected without sending real data through the template. Args: template_id: The numeric ID of the template to preview, e.g. 7. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A models.TemplatePreview whose 'preview' field holds the rendered HTML. Raises: OperationNotAllowedError: If the base URL has not been set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status (e.g. an unknown template ID). create_template(name: str | None = None, body: str | None = None, type: str | None = None, is_default: bool | None = None, subject: str | None = None, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Template | None Create a new template on the Listmonk instance. The body must contain the placeholder {{ template "content" . }} exactly where the rendered content should be injected; a template is rejected without it. Args: name: The template name. Required; a ValueError is raised if empty. body: The template body markup. Required, and must contain the {{ template "content" . }} placeholder. type: The template type, e.g. 'campaign' or 'tx' (transactional). is_default: Whether the new template should become the default for its type. subject: The default subject line for the template, if any. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A models.Template representing the newly created template. Raises: ValueError: If name is empty, if body is empty, or if body does not contain the {{ template "content" . }} placeholder. OperationNotAllowedError: If the base URL has not been set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the response is empty or is not valid JSON. Examples: >>> import listmonk >>> body = 'Header {{ template "content" . }} Footer' >>> tmpl = listmonk.create_template(name='Welcome', body=body, type='tx') >>> tmpl.id 7 update_template(template: listmonk.models.Template, timeout_config: httpx2.Timeout | None = None) -> listmonk.models.Template | None Update an existing template on the Listmonk instance. The template's name, subject, body, and type are sent in the update; the is_default flag is not changed by this call (use set_default_template for that). After the update succeeds, the template is re-fetched and returned. Args: template: The models.Template to update. Must be non-None and have an id. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: A freshly fetched models.Template reflecting the saved changes. Raises: ValueError: If template is None or has no id. OperationNotAllowedError: If the base URL has not been set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the re-fetch response is empty or is not valid JSON. set_default_template(template_id: int | None = None, timeout_config: httpx2.Timeout | None = None) -> bool Mark the given template as the default for its type. The template is first looked up by ID; if it does not exist, the default is not changed and False is returned. Args: template_id: The numeric ID of the template to set as default. Required. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: True if the default was set successfully. False if no template with the given ID exists. Raises: ValueError: If template_id is missing or falsy. OperationNotAllowedError: If the base URL has not been set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the response is empty or is not valid JSON. delete_template(template_id: int | None = None, timeout_config: httpx2.Timeout | None = None) -> bool Permanently delete a template from the Listmonk instance. The template is first looked up by ID; if it does not exist, no delete is attempted and False is returned. Args: template_id: The numeric ID of the template to delete. Required. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: True if the template was deleted successfully. False if no template with the given ID exists. Raises: ValueError: If template_id is missing or falsy. OperationNotAllowedError: If the base URL has not been set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the response is empty or is not valid JSON. ## Transactional Email Send one-off transactional messages. send_transactional_email(subscriber_email: str, template_id: int, from_email: str | None = None, template_data: dict[str, Any] | None = None, messenger_channel: str = 'email', content_type: str = 'markdown', altbody: str | None = None, attachments: list[pathlib.Path] | None = None, email_headers: list[dict[str, str | None]] | None = None, timeout_config: httpx2.Timeout | None = None) -> bool Send a transactional email through Listmonk to a single recipient. The recipient must already be a subscriber on at least one list. Delivery errors may surface in the logs section of your Listmonk dashboard rather than as exceptions here. The subscriber_email is lowercased and stripped before sending. Args: subscriber_email: The recipient's email address. Required; they must be a subscriber of some list on your server. template_id: The ID of the template to render. Must be a 'tx' (transactional) template, not a campaign template. from_email: The From address. Omit to use the default address at your sending provider. template_data: Merge parameters available in the template as {{ .Tx.Data.* }}. Defaults to an empty dict. messenger_channel: The delivery channel. Defaults to 'email'; use another configured channel (e.g. SMS) if available. content_type: The body format: 'html', 'markdown', or 'plain'. Defaults to 'markdown'. altbody: Optional alternate plain-text body for multipart HTML emails. attachments: Optional list of pathlib.Path objects pointing to files to attach. Each path must exist and be a file. email_headers: Optional list of custom headers, each a single-entry dict, e.g. [{'X-Custom': 'value'}]. timeout_config: Optional per-request timeout; defaults to 10 seconds. Returns: True if the server accepted the send, False otherwise. Raises: ValueError: If subscriber_email is empty. ListmonkFileNotFoundError: If any attachment path does not exist or is not a file. OperationNotAllowedError: If the base URL has not been set or you have not logged in. httpx.HTTPStatusError: If the server responds with a 4xx or 5xx status. ValidationError: If the response is empty or is not valid JSON. Examples: >>> import listmonk >>> listmonk.send_transactional_email( ... subscriber_email='person@example.com', ... template_id=3, ... template_data={'name': 'Sam'}, ... ) True ## Data Models Pydantic models returned by and passed to the API functions. MailingList(*, id: int, created_at: datetime.datetime, updated_at: datetime.datetime | None = None, uuid: str, name: str | None = None, type: str | None = None, optin: str | None = None, tags: list[str], description: str | None = None, subscriber_count: int | None = None, subscriber_statuses: listmonk.models.SubscriberStatus | None = None) -> None A mailing list on the Listmonk instance. Attributes: id: The numeric list ID assigned by Listmonk. created_at: When the list was created. updated_at: When the list was last modified, if ever. uuid: The globally unique identifier for the list. name: The human-readable list name. type: The list visibility, typically ``public`` or ``private``. optin: The opt-in mode, either ``single`` or ``double``. tags: Arbitrary labels attached to the list. description: A free-text description of the list. subscriber_count: The total number of subscribers on the list. subscriber_statuses: A breakdown of subscriber counts by subscription status. SubscriberStatus(*, unconfirmed: int | None = None) -> None A breakdown of subscriber counts by subscription status for a mailing list. Attributes: unconfirmed_count: The number of subscriptions still awaiting double opt-in confirmation (read from the API's ``unconfirmed`` field). SubscriberStatuses(*values) The subscription status of a subscriber within a given mailing list. Attributes: enabled: The subscriber is actively subscribed and will receive campaigns. disabled: The subscription exists but is paused; the subscriber will not receive campaigns. blocklisted: The subscriber has been blocked and will not receive any mail. Subscriber(*, id: int, email: str, name: str | None = None, created_at: datetime.datetime, updated_at: datetime.datetime | None = None, uuid: str | None = None, lists: list[dict[str, typing.Any]] = , attribs: dict[str, typing.Any] = , status: str | None = None) -> None A subscriber (contact) on the Listmonk instance. Attributes: id: The numeric subscriber ID assigned by Listmonk. email: The subscriber's email address (their primary identifier). name: The subscriber's display name, if provided. created_at: When the subscriber was created. updated_at: When the subscriber was last modified, if ever. uuid: The globally unique identifier for the subscriber. lists: The lists this subscriber belongs to, each as a dict describing the membership (list id, subscription status, and so on). attribs: Arbitrary custom attributes stored against the subscriber. status: The subscriber's global status, e.g. ``enabled``, ``disabled``, or ``blocklisted``. CreateSubscriberModel(*, email: str, name: str | None = None, status: str, lists: list[int] = , preconfirm_subscriptions: bool, attribs: dict[str, typing.Any] = ) -> None The payload used to create a new subscriber. This is the raw request body sent to Listmonk; the higher-level ``create_subscriber`` helper populates it (always sending ``status='enabled'``). Attributes: email: The email address for the new subscriber (required). name: The subscriber's display name, if any. status: The initial global status (required), e.g. ``enabled``, ``disabled``, or ``blocklisted``. lists: The IDs of the lists to subscribe this person to. Defaults to an empty list. preconfirm_subscriptions: Required flag; when ``True``, mark the new subscriptions as confirmed immediately (skipping double opt-in confirmation emails). attribs: Arbitrary custom attributes to store against the subscriber. Defaults to an empty dict. Campaign(*, id: int, created_at: datetime.datetime, updated_at: datetime.datetime | None = None, views: int, clicks: int, lists: list[dict[str, typing.Any]] = , started_at: datetime.datetime | None = None, to_send: int, sent: int, uuid: str, name: str | None = None, type: str | None = None, subject: str | None = None, from_email: str | None = None, body: str | None = None, altbody: str | None = None, send_at: datetime.datetime | None = None, status: str | None = None, content_type: str | None = None, tags: list[str] = , template_id: int, messenger: str | None = None, headers: list[dict[str, str | None]] = ) -> None An email campaign on the Listmonk instance. Attributes: id: The numeric campaign ID assigned by Listmonk. created_at: When the campaign was created. updated_at: When the campaign was last modified, if ever. views: The number of times the campaign has been opened/viewed. clicks: The number of link clicks recorded for the campaign. lists: The target lists for the campaign, each as a dict describing the list. started_at: When sending began, if the campaign has started. to_send: The total number of recipients the campaign will be sent to. sent: The number of messages sent so far. uuid: The globally unique identifier for the campaign. name: The internal campaign name. type: The campaign type, e.g. ``regular`` or ``optin``. subject: The email subject line. from_email: The sender (From) address. body: The campaign body in the configured content type. altbody: The optional plain-text alternative body for multipart HTML emails. send_at: The scheduled send time, if the campaign is scheduled. status: The campaign status, e.g. ``draft``, ``scheduled``, ``running``, ``paused``, ``cancelled``, or ``finished``. content_type: The body format, e.g. ``richtext``, ``html``, ``markdown``, or ``plain``. tags: Arbitrary labels attached to the campaign. template_id: The ID of the template used to render the campaign. messenger: The delivery channel, typically ``email``. headers: Custom email headers to include, each as a single-entry dict. CreateCampaignModel(*, name: str | None = None, subject: str | None = None, lists: list[int] = , from_email: str | None = None, type: str | None = None, content_type: str | None = None, body: str | None = None, altbody: str | None = None, send_at: datetime.datetime | None = None, messenger: str | None = None, template_id: int | None, tags: list[str] = , headers: list[dict[str, str | None]] = ) -> None The payload used to create a new campaign. This is the raw request body sent to Listmonk; the higher-level ``create_campaign`` helper validates that name and subject are present and defaults the target list to ``{1}`` before populating this model. Attributes: name: The internal campaign name. subject: The email subject line. lists: The IDs of the lists to send the campaign to. Defaults to an empty list. from_email: The sender (From) address. Omit to use the instance default. type: The campaign type, e.g. ``regular`` or ``optin``. content_type: The body format, e.g. ``richtext``, ``html``, ``markdown``, or ``plain``. body: The campaign body in the configured content type. altbody: The optional plain-text alternative body for multipart HTML emails. send_at: The scheduled send time, if the campaign should be scheduled. Serialized to an ISO-8601 string (or ``None``) when sent. messenger: The delivery channel, typically ``email``. template_id: The ID of the template used to render the campaign. Required field that may be ``None`` (it has no default and must be supplied explicitly). tags: Arbitrary labels to attach to the campaign. Defaults to an empty list. headers: Custom email headers to include, each as a single-entry dict. Defaults to an empty list. UpdateCampaignModel(*, name: str | None = None, subject: str | None = None, lists: list[int] = , from_email: str | None = None, type: str | None = None, content_type: str | None = None, body: str | None = None, altbody: str | None = None, send_at: datetime.datetime | None = None, messenger: str | None = None, template_id: int | None, tags: list[str] = , headers: list[dict[str, str | None]] = ) -> None The payload used to update an existing campaign. Shares all fields with [CreateCampaignModel][listmonk.models.CreateCampaignModel]. As a safeguard, a ``send_at`` value that is already in the past is dropped (set to ``None``) before sending, so that updating a campaign does not fail on a stale scheduled time. CampaignPreview(*, preview: str | None = None) -> None A rendered preview of a campaign. Attributes: preview: The rendered HTML preview of the campaign body. Template(*, id: int, created_at: datetime.datetime, updated_at: datetime.datetime | None = None, name: str | None = None, subject: str | None = None, body: str | None = None, type: str | None = None, is_default: bool | None = None) -> None An email template on the Listmonk instance. Attributes: id: The numeric template ID assigned by Listmonk. created_at: When the template was created. updated_at: When the template was last modified, if ever. name: The template name. subject: The default subject line for the template, if any. body: The template body markup. type: The template type, e.g. ``campaign`` or ``tx`` (transactional). is_default: Whether this is the default template for its type. CreateTemplateModel(*, name: str | None = None, subject: str | None = None, body: str | None = None, type: str | None = None, is_default: bool | None = False) -> None The payload used to create a new template. Attributes: name: The template name. subject: The default subject line for the template, if any. body: The template body markup. type: The template type, e.g. ``campaign`` or ``tx`` (transactional). is_default: Whether the new template should become the default for its type. Defaults to ``False``. TemplatePreview(*, preview: str | None = None) -> None A rendered preview of a template. Attributes: preview: The rendered HTML preview of the template, using lorem-ipsum sample content. ## Exceptions Errors raised by the client. ValidationError Raised when an argument fails client-side validation before a request is sent. OperationNotAllowedError Raised when an operation is not permitted in the client's current state. For example, calling an API before the base URL has been set, or before a successful login. ListmonkFileNotFoundError Raised when a local file referenced for upload (e.g. a transactional email attachment) cannot be found.