Stalwart Mail Alias Creation Script
I just run: al <name for the alias> and get a new mail redirecting all mails to my main inbox.

#
Why?
You might want to hide your mail from websites where you register, as they might sell your mail address (which is then used to profile or spam you), they might get hacked and you get tons of spam, or they just spam you right away. An alias mail can be easily disabled and tada, finished, no more wories, no more mails from that address (and the site you gave it to) without having to change your whole mailbox …
This is the 2nd part of the series about setting up your own mail server. I’m presuming you already have a Stalwart Mail Server running.
#
Preparations
-
Obtain your API Key from the Stalwart WebUI, in the default installation its under: http://{your-domain}:8080/, head to your account settings (left side panel, at the bottom the right option |
/account/Account/x:ApiKey). Then go to Credentials and add a API Key. You need to use your admin account to create this api key, as it requires more permissions than a default mailbox has. -
Install Stalwart CLI on your System
#
Script
Install the dependencies via:
uv venv && uv pip install pyperclipand configure the script
import json
import os
import subprocess
import sys
import pyperclip
# --------------------
DOMAIN = "example.de" # <--- Here your domain ending, like if your mail is 'admin@example.de', then example.de
HOSTNAME = "mail.example.de" # <--- your domain with the .mail prefix usually, where the server is actually running at
TOKEN = "API_AAA...." # <---- Paste here your API Key
USERNAME = "admin" # <---- the mailbox you usually use, like if it's admin@example.de, its admin,
# if you use me@example.de as your mailbox, then enter 'me'
ALIAS_POSTFIX = "" # <---- e.g. "-alias", if you want to have a default ending for every alias, e.g. 'al test' should
# produce the alias 'test-alias@example.de' as alias mail
# --------------------
CACHE_FILE = ".stalwart-alias-cache.json"
# --------------------
# Usage: uv run create_alias.py <alias_prefix>
# or uv run create_alias.py
# ------------
if not len(sys.argv) > 1:
new_alias_prefix = input("alias: ")
else:
new_alias_prefix = sys.argv[1]
user_id_cached = None
domain_id_cached = None
if os.path.isfile(CACHE_FILE):
with open(CACHE_FILE, "r") as f:
cache = json.load(f)
if "users" in cache and USERNAME in cache["users"]:
user_id_cached = cache["users"][USERNAME]
if "domains" in cache and DOMAIN in cache["domains"]:
domain_id_cached = cache["domains"][DOMAIN]
def run_stalwart_cmd(cmd, nojson=False):
env = os.environ.copy()
env["STALWART_URL"] = f"https://{HOSTNAME}"
env["STALWART_TOKEN"] = TOKEN
cmd = "stalwart-cli " + cmd
if not nojson:
cmd += " --json"
# print(cmd)
result = subprocess.check_output(
cmd,
env=env,
shell=True,
text=True,
)
if nojson:
return result
else:
return json.loads(result)
if not user_id_cached:
user_account = run_stalwart_cmd(
f"query Account --where name={USERNAME} --fields id,name,emailAddress"
)
user_id = user_account["id"]
print(f"[+] obtained user id: {user_id}")
else:
user_id = user_id_cached
print(f"[+] loaded user id from cache: {user_id}")
if not domain_id_cached:
domain_id = run_stalwart_cmd(
f"query Domain --fields id,name --where name={DOMAIN}"
)["id"]
print(f"[+] obtained domain id: {domain_id}")
else:
domain_id = domain_id_cached
print(f"[+] loaded domain id from cache: {domain_id}")
user_aliases = run_stalwart_cmd(f"get Account {user_id} --fields aliases")["aliases"]
if len(list(map(int, list(user_aliases)))) == 0:
new_alias_id = "0"
else:
new_alias_id = str(max(list(map(int, list(user_aliases)))) + 1)
alias_list = [user_aliases[a]["name"] for a in user_aliases]
print(f"[+] obtained next alias id: {new_alias_id}")
new_alias = f"{new_alias_prefix}{ALIAS_POSTFIX}"
if new_alias in alias_list:
print("[-] FAILURE: alias already exists! - exiting")
exit()
print(f"[+] alias can be created: {new_alias}@{DOMAIN}")
alias_patch = {
f"aliases/{new_alias_id}": {
"enabled": True,
"name": new_alias,
"domainId": domain_id,
"description": None,
}
}
result = run_stalwart_cmd(
"update Account " + user_id + " --json '" + json.dumps(alias_patch) + "'",
nojson=True,
)
if result.startswith("Updated"):
print("[+] created alias - copying to clipboard")
cache = {"users": {USERNAME: user_id}, "domains": {DOMAIN: domain_id}}
with open(CACHE_FILE, "w") as f:
json.dump(cache, f, indent=4)
pyperclip.copy(f"{new_alias}@{DOMAIN}")
else:
print(f"[-] FAILURE: {result}")Now you can run it via uv run create_alias.py <alias to create>
And you might create an alias for the script for this edit your .bashrc (or .zshrc if you use zsh) and add sth at the bottom like:
# ...
alias al="uv run create_alias.py"so you can run in the future al <alias> and it gets copied right into your clipboard
stalwart mail aliasing privacy self-hosting
691 Words
2026-07-03 22:18 (Last updated: 2026-07-03 23:04)
1156a52 @ 2026-07-03