mailcow-dockerized
mailcow-dockerized copied to clipboard
Aliases for all domains
Summary
Allow to create an alias for all domains, currently existing ones as well as newly created domains.
Motivation
Use case would mainly be for RFC required aliases, such as postmaster (or hostmaster, webmaster, ...) which is usually the same person for all domains.
Creating the aliases for every new domain is tedious and likely to be forgotten, resulting in an unreachable postmaster address.
Additional context
As we can create a catchall-all-users alias using @example.org
, a complementary syntax would be to use postmaster@
as a catch-all-domains alias.
I hacked together a little python script that creates aliases for all domains:
from urllib.request import Request, urlopen
import json, re, itertools
import logging
class MailcowAPI:
def __init__(self, domain: str, key: str):
self.domain = domain
self.key = key
def rest_call(self, path: str, body = None):
url = "https://" + self.domain + "/api/v1/" + path
headers = {"accept" : "application/json",
"X-API-Key" : self.key,
'content-type' : 'application/json'}
data = json.dumps(body).encode("utf-8") if body else None
request = Request(url, data, headers)
logging.debug("Opening URL: %s with body: %s", url, body)
with urlopen(request) as response:
content = response.read().decode("utf-8")
try:
json_content = json.loads(content)
message_type = json_content["type"]
message_content = json_content["msg"]
except (json.JSONDecodeError, AttributeError, TypeError):
pass
else:
if message_type == "error":
raise Exception(f"Error calling URL {url} with data {data} returned with message: {message_content}.")
return json.loads(content)
def mailboxes(self):
return self.rest_call(path = "get/mailbox/all")
def logs(self, log_type: str, count: int = 10):
return self.rest_call("get/logs/" + log_type + "/" + str(count))
def aliases(self, id = "all"):
return self.rest_call("get/alias/" + str(id))
def add_alias(self, address, goto):
self.rest_call("add/alias", {"address" : address, "goto" : goto, "active" : True})
logging.debug("Created alias: %s -> %s", address, goto)
def delete_alias(self, id: int):
self.rest_call("delete/alias", body = [str(id)])
logging.debug("Deleted alias %s", id)
def domains(self, id = "all"):
return self.rest_call("get/domain/" + str(id))
def set_aliases_for_every_domain(mc: MailcowAPI):
target = "[email protected]"
aliases = ["postmaster", "hostmaster"]
domain_regexp = r".*"
force = False # delete existing aliases and recreate
domains = [ i["domain_name"] for i in mc.domains() if re.match(domain_regexp, i["domain_name"]) ]
existing_aliases = { i["address"]: i["id"] for i in mc.aliases() }
aliases_to_create = [ a+"@"+d for a in aliases for d in domains ]
for a in aliases_to_create:
if a in existing_aliases and force is False:
logging.info("Aliases for %s already exists, skipping.", a)
elif a in existing_aliases and force is True:
logging.info("Aliases for %s already exists, deleting and set again.", a)
mc.delete_alias(existing_aliases[a])
mc.add_alias(a, target)
else:
mc.add_alias(a, target)
def main():
logging.basicConfig(level = logging.DEBUG)
key = "An API key with write permissions"
domain = "the.mail.domain"
mc = MailcowAPI(domain, key)
set_aliases_for_every_domain(mc)
main()
Fell free to use, modify and distribute (public domain).