I have this script, but it doesn't work with stalwart 0.16.6 -

Your question

#!/bin/bash

Modify the script however you like

MY_DOMAINS=(“domain1.de”, “mail.domain1”, “domain2”, “mail.domain.de”)

for RENEWED_DOMAIN in ${RENEWED_DOMAINS}; do
for MY_DOMAIN in “${MY_DOMAINS[@]}”; do
if [ “${RENEWED_DOMAIN}” = “${MY_DOMAIN}” ]; then
CERTIFICATE_DIR=“/etc/stalwart/certs/${RENEWED_DOMAIN}”

        # Copy new certificate to Stalwart directory
        cp "${RENEWED_LINEAGE}/fullchain.pem" "${CERTIFICATE_DIR}/fullchain.pem"
        cp "${RENEWED_LINEAGE}/privkey.pem" "${CERTIFICATE_DIR}/privkey.pem"

        # Set ownership to stalwart-mail
        chown stalwart:stalwart "${CERTIFICATE_DIR}/fullchain.pem" "${CERTIFICATE_DIR}/privkey.pem"

       # Restart Stalwart to reload certificates and configuration
        if systemctl is-active --quiet stalwart; then
            systemctl restart stalwart
        fi
    fi
done

done

It works in setting the certs to that directory, but stalwart doesn’t seem to read them.
how can this be automated? I have manual certificate management enabled, because i fetch the certs for a jabber server too.

The core issue is that simply copying files and restarting Stalwart is not how certificate management works in current Stalwart. Stalwart does not scan a directory for cert files on its own. Instead, Certificate objects must be registered in Stalwart’s database (via the WebUI or CLI), pointing to the file paths on disk. After files are rotated, a hot reload must be triggered via the CLI – a full service restart is not needed and does not re-read file-referenced certs either.

Here’s the correct approach:

1. Register your certificate(s) in Stalwart (one-time setup)

In the WebUI under Settings > TLS > Certificates, create a Certificate object for each domain with @type: File references:

{
  "certificate": {
    "@type": "File",
    "filePath": "/etc/stalwart/certs/domain1.de/fullchain.pem"
  },
  "privateKey": {
    "@type": "File",
    "filePath": "/etc/stalwart/certs/domain1.de/privkey.pem"
  }
}

Do this for each domain. Stalwart will then read the actual PEM content from those paths at load/reload time.

2. Replace your systemctl restart with a CLI hot-reload

After copying the renewed files, instead of restarting the service, call:

stalwart-cli --url https://mail.yourdomain.com --api-key <TOKEN> create action/ReloadTlsCertificates

This tells the running server to re-read the certificate files from disk without any downtime or service interruption.

Updated Certbot deploy hook script

#!/bin/bash

MY_DOMAINS=("domain1.de" "mail.domain1.de" "domain2.de" "mail.domain2.de")

for RENEWED_DOMAIN in ${RENEWED_DOMAINS}; do
    for MY_DOMAIN in "${MY_DOMAINS[@]}"; do
        if [ "${RENEWED_DOMAIN}" = "${MY_DOMAIN}" ]; then
            CERTIFICATE_DIR="/etc/stalwart/certs/${RENEWED_DOMAIN}"

            cp "${RENEWED_LINEAGE}/fullchain.pem" "${CERTIFICATE_DIR}/fullchain.pem"
            cp "${RENEWED_LINEAGE}/privkey.pem" "${CERTIFICATE_DIR}/privkey.pem"

            chown stalwart:stalwart "${CERTIFICATE_DIR}/fullchain.pem" "${CERTIFICATE_DIR}/privkey.pem"
        fi
    done
done

# Trigger Stalwart to re-read all cert files (no restart needed)
stalwart-cli --url https://mail.yourdomain.com --api-key <TOKEN> create action/ReloadTlsCertificates

Note on your original script: there’s also a syntax bug – the array initializer uses commas between elements ("domain1.de", "mail.domain1",...), which is not valid in bash. Array elements should be space-separated only.

Docs references:

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.