Skip to content

Configuration

Apprise configuration is built around a single core abstraction: AppriseConfig.

This object is responsible for loading, resolving, and producing notification service definitions that can be consumed by the Apprise CLI, the Apprise-API, or embedded Python applications.

Unlike notification services, configuration does not send messages. It defines what can send messages, how they are grouped, and how they are discovered.

AppriseConfig is the central configuration loader used throughout Apprise.

It is responsible for:

  • Loading notification definitions from one or more sources
  • Resolving include directives
  • Applying tag-based filtering
  • Producing a unified configuration that can be consumed by Apprise

Every Apprise execution, regardless of interface, ultimately operates on an AppriseConfig instance.

from apprise import Apprise, AppriseConfig
apprise = Apprise()
config = AppriseConfig()
config.add('config.yml')
apprise.add(config)
apprise.notify(
title='Status',
body='All systems operational',
)
from apprise import Apprise, AppriseConfig
apprise = Apprise()
config = AppriseConfig()
config.add('config.yml')
apprise.add(config)
apprise.notify(
title='Single Config',
body='Loaded from one configuration source',
)

An AppriseConfig instance may load configuration from multiple sources. Each source is processed and merged into a single effective configuration.

Supported sources include:

  • Local files
  • Remote URLs
  • In-memory configuration
  • Inline configuration content

Each source is treated uniformly by the configuration engine, regardless of origin.

Apprise supports both text and YAML configuration files. The formats are functionally equivalent, but structured differently.

For a side-by-side explanation and examples, see Getting Started: Configuration.

YAML configuration can describe an Apprise URL as either a plain string or as a mapping with additional keys:

urls:
- mailto://gmail.com:
user: alerts
password: "myP@ss#w0rd!"
to: ops@example.com
tag: ops

The YAML keys are merged into the parsed URL before the plugin is created. Common URL fields such as user, password, host, port, verify, and tag can be supplied this way, along with service-specific parameters from the service’s parameter table.

When a list is placed under one URL, Apprise creates one service definition per list item. Each item starts with the same parsed URL and then applies that item’s YAML values:

urls:
- mailto://user:pass@gmail.com:
- to: manager@example.com
tag: boss
- to: coworker@example.com
tag: new-hire

This loads two email services with shared credentials and different targets.

A YAML configuration may include a template: section and reference those names as ${NAME} in its URLs or settings. See Template Variables for the YAML syntax and placement guidance.

An entry that still needs a value is kept as an apprise.NotifyTemplate. It retains its tags for filtering, and url() shows its ${NAME} markers.

import apprise
CONFIG = """
template:
api_key:
urls:
- sendgrid://${API_KEY}:noreply@example.com/you@example.com
"""
config = apprise.AppriseConfig()
config.add_config(CONFIG, format="yaml")
apobj = apprise.Apprise()
apobj.add(config)
# What is still required?
apobj.template_vars()
# {'api_key': {'default': None, 'services': 1}}
# Supply it for this call
apobj.notify(body="Hello", template={"api_key": "your-secret-key"})

template_vars() reports the default itself; a None means the configuration gave the variable no default, so a value must come from the call or environment. Treat returned defaults as configuration content.

Values are resolved per call, in this order:

  1. the template mapping passed to notify() or find()
  2. the default declared in the configuration
  3. the APPRISE_TEMPLATE_<NAME> environment variable

Blank or whitespace-only call and environment values are ignored. An explicit empty-string default (api_key: "") is still a value, so it takes priority over APPRISE_TEMPLATE_API_KEY.

template must be a mapping, and each key a valid variable name used only once. Any collections.abc.Mapping works, so a MappingProxyType or a UserDict works alongside a plain dict. Invalid input raises apprise.exception.AppriseTemplateError from find(); notify() returns FAILURE.

An entry with no available value is skipped. The result is PARTIAL when another matching entry sends, or FAILURE when every matching entry is skipped.

find(..., resolve=False) returns pending entries without filling them in. urls() and iteration do the same.

One case-insensitive set of values covers everything in an Apprise object. Extra valid names are ignored and recorded by name in the local debug log.

Templates can be switched off entirely through the asset:

asset = apprise.AppriseAsset(allow_templates=False)

This ignores template: sections and environment values, and treats ${NAME} as ordinary text. Only the application can change this setting.

Per-call values do not change the cached configuration or later calls. Reusing the same values also reuses the built service and storage identity.

Missing variable names are written to the local log, but not to AppriseResult or log_callback output.

The include directive allows one configuration source to reference another.

Includes are resolved recursively and may be used to:

  • Share common notification definitions
  • Centralise configuration
  • Layer environment-specific configuration
  • Reduce duplication

From the perspective of AppriseConfig, an include is simply another configuration source to load and merge.

Includes may reference:

  • Local files
  • Remote URLs

Includes are resolved in the order they are encountered.

Configuration sources are processed sequentially.

Later sources may:

  • Add new notification definitions
  • Extend existing entries
  • Refine tags and routing behaviour

Apprise does not impose a fixed base-or-override model. All configuration entries are additive unless explicitly filtered or constrained by tags.

To prevent unsafe or unintended configuration behaviour, Apprise applies safety rules when resolving includes.

These rules control whether a configuration source may include another source of a different type.

For example:

  • A local file may include another local file
  • A remote configuration source may be restricted from including arbitrary local files
  • Recursive include depth is limited to prevent infinite loops

These rules are enforced by the configuration engine and may vary depending on the host environment.

Authenticated Remote Configuration Sources

Section titled “Authenticated Remote Configuration Sources”

Remote configuration sources may require authentication.

When using HTTP or HTTPS URLs, basic authentication credentials can be embedded directly into the URL:

config = AppriseConfig()
config.add('https://user:pass@apprise.example.com/cfg/mykey')

When provided in this form, credentials are used automatically when retrieving the configuration.

AppriseConfig itself does not enforce security policy.

It is responsible for loading and resolving configuration, but trust decisions are enforced by the host environment.

For example:

  • The Apprise CLI may allow unrestricted local includes
  • A running Apprise-API server may restrict which configuration sources are permitted
  • Embedded applications may impose their own security constraints

If a configuration source is rejected due to host policy, it is excluded before being merged into the final configuration.

When configuration is hosted by an Apprise-API instance, additional security controls may apply.

An Apprise-API server may enable configuration locking to prevent remote clients from loading server-side configuration.

When configuration locking is enabled:

  • An authenticated global administrator retains full configuration access
  • Other callers cannot add, retrieve, inspect, list, move, or delete configuration
  • Only locally-defined configuration is available to those callers

This behaviour is enforced by the Apprise-API server, not by AppriseConfig itself.

Configuration locking exists to prevent:

  • Accidental credential exposure
  • Unauthorized configuration discovery
  • Server-side request forgery (SSRF)

Configuration locking does not affect:

  • Stateful notifications sent through an existing Config ID, including optional tag filtering
  • Stateless notifications that provide their own notification URLs
  • Local configuration files
  • In-memory configuration
  • Custom configuration sources hosted outside of Apprise-API

Configuration entries may be associated with one or more tags.

Tags are used to control which notification services are selected when a message is sent.

Filtering may be applied to:

  • Include only matching tags
  • Always include untagged services
  • Combine multiple tags using OR or AND semantics

Tag resolution is performed at notification time, not during configuration loading.

When sending through the Python library, notify(tag=...) follows these rules:

notify(tag=...) expressionSelected services
"TagA"Has TagA
"TagA,TagB"Has TagA AND TagB
["TagA", "TagB"]Has TagA OR TagB
["TagA,TagC", "TagB"]Has (TagA AND TagC) OR TagB
Questions or Feedback?

Documentation

Notice a typo or an error?

Technical Issues

Having trouble with the code? Open an issue on GitHub:

Made with love from Canada