• Halloween is coming! To celebrate the occasion, we dusted off a couple of old skins, and even created a brand new one (Pixel).
    To get into the festive spirit, install the Skins extension.
  • The new Python extension is now available. It allows customers to deploy and manage WSGI-based Python applications on their websites directly from Plesk.
  • The Plesk Mobile apps for iOS and Android and the Plesk Mobile Center extension have been deprecated, and are no longer available for new installations. In Plesk Obsidian 18.0.84, the Plesk Mobile Center extension will be removed from servers during the upgrade, and the Plesk Mobile apps will lose their server management features.
  • The Social Login extension has been deprecated and will be removed in Plesk Obsidian 18.0.84. After that, it will no longer be possible to log in to Plesk with a Google, Facebook, GitHub account, or with a passkey. Plesk usernames and passwords, as well as logging in with a WebPros Account, are not affected.

Question Add disclaimer/signature to every email from one domain

miloszryckobozenski

New Pleskian
Server operating system version
Ubuntu 20.04
Plesk version and microupdate number
18.0.48
Hi!

I need to add some kind of disclaimer in html to every email address from one domain.

I found alterMIME which looks fine.

But I have a question: is it safe to modify /etc/postfix/master.cf and add files to /etc/postfix/ ? Or how to do it without worrying that some Plesk updates will reset configuration?

In some KB article I found warning:

Warning: any customization made in Postfix configuration can be overwritten by Plesk update (for example, in case of bug fix, when configuration files are updated), Plesk upgrade or by mchk utility, which resets default mail server configuration.

But for example, here: https://support.plesk.com/hc/en-us/...-and-SMTP-banner-in-Postfix-on-a-Plesk-server there is no warning about modyfing master.cf.

So I would be thankful for any ideas how to extend postfix configuration safely without worrying about updates or mchk utility.

Thanks!
Milosz
 
Disclosure first: I build a commercial product in this space, so read this as a vendor answer. The technical part holds regardless of what you use.

To your actual question: no, it is not safe long term. The KB article IgorG linked applies to master.cf as well as main.cf: any change to the Postfix config, including an alterMIME content_filter, can be reverted by a Plesk update or by mchk. It may survive for months and then silently disappear after a microupdate.

The approach that survives updates is to keep the signature logic outside Plesk entirely: in Tools & Settings > Mail Server Settings you set an authenticated external SMTP relay for outgoing mail (a supported Plesk setting, so updates leave it alone), and the relay adds the disclaimer and DKIM-signs the result. Nothing in /etc/postfix is touched, and it works the same for Roundcube, Outlook, Thunderbird and phones.

If you build or pick such a relay, check two things: it must only modify the text/html and text/plain parts and leave the rest of the MIME tree as it is (otherwise inline cid: images and calendar invitations break), and it must DKIM-sign after modifying the body, because the body change invalidates any earlier signature. S/MIME-signed or encrypted mail should pass through untouched.

We run exactly this as a hosted service; Plesk setup steps are here: How to Set Up Email Signatures in Plesk — Badex Signature — Badex Signature. Happy to answer technical questions in this thread.
 
Hi Milosz,

short answer: no, it's not safe, and the warning in the KB article applies to master.cf just as much as to main.cf. The article IgorG linked says these resets are intended: Plesk rewrites the Postfix config when you run "plesk repair mail", install microupdates, change something in Tools & Settings > Mail Server Settings, use the Email Security extension, and also when the Postfix package itself gets updated. In practice not every custom line gets wiped (settings Plesk doesn't manage often survive for a long time), but you can't predict when it happens. The nasty part is that mail keeps flowing, just without the disclaimer, so you might not notice for a while.

Also keep in mind that a disclaimer changes the message body. That breaks any DKIM signature that was added before the filter ran. So whatever you do, the signing has to happen after the disclaimer is added. Test this with a mail to a Gmail account and look at the "Authentication-Results" header (dkim=pass).

Option 1 (the one I'd pick): keep it out of Plesk's Postfix completely.
Set up a small relay on a separate box or VM (Postfix + alterMIME + OpenDKIM, or a hosted service) and send outgoing mail through it as an authenticated smarthost. Then nothing in /etc/postfix on the Plesk server is touched, and Plesk updates can't break it. Do the "only this one domain" check on the relay (by sender address), and let the relay do the DKIM signing after the body was modified. Turn off DKIM signing for that domain in Plesk, otherwise you send a signature that is broken by design. If you want to rely on a product for this, just check that it only modifies the text/plain and text/html parts and leaves the rest of the MIME tree alone, otherwise inline images and calendar invites can break.

Option 2: do it on the Plesk server, but assume it will get reverted and make it self-healing.
Keep your master.cf lines in a separate snippet file and let a small script check regularly whether the hook is still there. If not, it puts it back and reloads Postfix. First make a backup:

Code:
mkdir -p /root/postfix-custom
cp -a /etc/postfix/main.cf /etc/postfix/master.cf /root/postfix-custom/

Put your own master.cf lines (filter service and reinjection port) into this file:

Code:
/root/postfix-custom/master.cf.snippet

Then create the check script (replace <filtername> with the name of your filter service):

Code:
#!/bin/bash
# /usr/local/sbin/postfix-disclaimer-check.sh
if [ "$(postconf -h content_filter)" = "<filtername>:dummy" ] && grep -q "^<filtername> unix" /etc/postfix/master.cf; then
    exit 0
fi
postconf -e "content_filter = <filtername>:dummy"
grep -q "^<filtername> unix" /etc/postfix/master.cf || cat /root/postfix-custom/master.cf.snippet >> /etc/postfix/master.cf
postfix check && postfix reload
logger -t postfix-disclaimer "hook was reverted, re-applied"

Make it executable and run it every 5 minutes:

Code:
chmod 700 /usr/local/sbin/postfix-disclaimer-check.sh
echo '*/5 * * * * root /usr/local/sbin/postfix-disclaimer-check.sh' > /etc/cron.d/postfix-disclaimer-check

Notes on this:
- It's a skeleton, test it on a non-production box first, especially after running "plesk repair mail".
- A global content_filter also catches inbound and other domains' mail, so your disclaimer script must pass everything that is not from your domain straight through to the reinjection port untouched.
- On the reinjection smtpd you will most likely have to disable milters, which means Plesk's DKIM signing (done earlier in the chain) no longer matches the body. This is the main weak spot of option 2, and it's why I'd go with option 1.
- If you also want to be notified when Plesk touches the files, incron or a simple checksum check in the same cron job works well.

Hope that helps, and let us know how it goes.

Regards
Tessa
 
Hi Milosz,

I thought about this again and I want to revise my earlier answer. Both options I gave you have a real weakness, and the more I looked at it, the less happy I was with either of them. Option 1 needs a second box, and Option 2 has the DKIM problem baked in.

So here is Option 3, which I think is the actual clean solution: a small local relay running in Docker on the same Plesk host, and Plesk's Postfix only hands off outgoing mail for your one domain to it via a transport map. Nothing in `master.cf` gets touched, the relay does the disclaimer and the DKIM signing afterwards, so the signature is valid, and other domains are completely unaffected.

Before I start, one honest correction to what I wrote earlier: I had a couple of things in that draft that would not have worked as-is. The `boky/postfix` image does not ship alterMIME, so the filter script would have failed. The `content_filter` approach inside the relay is also unnecessary and fragile. And the DKIM key handling via that image's env vars is not flexible enough for "sign only one domain with an existing key". In Option 3 below I use a plain `postfix` + `opendkim` + `altermime` container that I build myself, which is more work up front but does exactly what we need and nothing else. I also dropped the `content_filter` inside the relay and use a proper `smtp` transport + `always_bcc`-free pipe service instead, so the MIME structure stays intact.

One thing I want to be upfront about: this is a real setup, please test it on a non-production domain first, and read the whole thing before you start.

Option 3: local relay in Docker, transport-map hand-off from Plesk (PART 1)

How it works in one paragraph: Plesk's Postfix stays exactly as Plesk wants it. The only addition is a `transport_maps` entry that says "mail from `example.com` goes to `127.0.0.1:2525`". On port 2525 a small Postfix instance in a container accepts the mail, runs it through alterMIME to add the disclaimer, signs it with OpenDKIM using the DKIM key that is already published in DNS for that domain, and then relays it out to the internet. Because signing happens after the body is modified, DKIM passes. Because the transport map only matches one domain, nothing else is affected. Because the container is separate from Plesk, Plesk updates cannot break it.

Step 1 – Check prerequisites:
You need Docker (or Podman) on the Plesk host, and you need to know the DKIM selector and key that Plesk currently uses for the domain.
Code:
docker --version
docker compose version
Code:
# List DKIM keys Plesk manages
plesk bin dkim_manager -l 2>/dev/null || true

# Typical location of the private key
ls -la /etc/opendkim/keys/<your-domain>/

Write down the selector (usually `default`) and the **private key path**. You will need both later. If Plesk uses its own DKIM implementation and the key is not in `/etc/opendkim/keys`, check:
Code:
plesk bin dkim_manager -i -domain <your-domain>

Step 2 – Create the directory layout:
Code:
mkdir -p /opt/disclaimer-relay/{conf,dkim,bin,spool}
chmod 700 /opt/disclaimer-relay/dkim

Step 3 – The Dockerfile:
Build our own image so you control exactly which packages are present.
Code:
# /opt/disclaimer-relay/Dockerfile
FROM debian:bookworm-slim

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y --no-install-recommends \
        postfix \
        opendkim \
        opendkim-tools \
        altermime \
        ca-certificates \
        libsasl2-modules \
        rsyslog \
    && rm -rf /var/lib/apt/lists/*

COPY bin/add-disclaimer /usr/local/bin/add-disclaimer
RUN chmod 755 /usr/local/bin/add-disclaimer

COPY conf/main.cf        /etc/postfix/main.cf
COPY conf/master.cf      /etc/postfix/master.cf
COPY conf/opendkim.conf  /etc/opendkim.conf
COPY conf/KeyTable       /etc/opendkim/KeyTable
COPY conf/SigningTable   /etc/opendkim/SigningTable
COPY conf/TrustedHosts   /etc/opendkim/TrustedHosts

COPY disclaimer.txt      /etc/disclaimer/disclaimer.txt
COPY disclaimer.html     /etc/disclaimer/disclaimer.html

EXPOSE 2525

COPY bin/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod 755 /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

Step 4 – The relay's `main.cf`:
Note: no `content_filter` here. The disclaimer is applied by a `pipe` service that reinjects into a second `smtpd` on port 10026, and OpenDKIM runs as a milter on that second `smtpd` only. That way the body is already modified when the signature is computed.
Code:
# /opt/disclaimer-relay/conf/main.cf
myhostname = relay.<your-domain>
mydomain   = <your-domain>
myorigin   = <your-domain>
mydestination =

# Accept only from localhost (Plesk hands off to 127.0.0.1:2525)
inet_interfaces = 127.0.0.1
mynetworks = 127.0.0.0/8

# Never relay for anyone else
smtpd_relay_restrictions = permit_mynetworks, reject

# No local delivery at all
local_recipient_maps =
luser_relay =

# Outbound: send to the internet directly.
# If your host blocks port 25, put your provider's smarthost here instead.
relayhost =
smtp_tls_security_level = may

# Reinjection port: no content_filter, DKIM milter active
# (configured in master.cf, not here)

# Size limit, keep sane
message_size_limit = 51200000

# No local alias lookups that could bounce
alias_maps =
alias_database =

Step 5 – The relay's `master.cf`:
Code:
# /opt/disclaimer-relay/conf/master.cf
# service            type  private unpriv  chroot  wakeup  maxproc command
2525                 inet  n       -       n       -       -       smtpd
  -o content_filter=disclaimer-filter:
  -o receive_override_options=no_address_mappings
  -o smtpd_milters=
  -o non_smtpd_milters=

# Reinjection after the disclaimer was added. DKIM milter runs HERE.
10026                inet  n       -       n       -       -       smtpd
  -o content_filter=
  -o receive_override_options=no_address_mappings
  -o smtpd_milters=inet:127.0.0.1:12301
  -o non_smtpd_milters=inet:127.0.0.1:12301
  -o smtpd_client_restrictions=permit_mynetworks,reject

# The disclaimer pipe service
disclaimer-filter    unix  -       n       n       -       -       pipe
  flags=Rq user=nobody argv=/usr/local/bin/add-disclaimer ${sender} ${recipient}

pickup               fifo  n       -       n       60      1       pickup
cleanup              unix  n       -       n       -       0       cleanup
qmgr                 fifo  n       -       n       300     1       qmgr
tlsmgr               unix  -       -       n       1000?   1       tlsmgr
rewrite              unix  -       -       n       -       -       trivial-rewrite
bounce               unix  -       -       n       -       0       bounce
defer                unix  -       -       n       -       0       bounce
trace                unix  -       -       n       -       0       bounce
verify               unix  -       -       n       -       1       verify
flush                unix  n       -       n       1000?   0       flush
proxymap             unix  -       -       n       -       -       proxymap
proxywrite           unix  -       -       n       -       1       proxymap
smtp                 unix  -       -       n       -       -       smtp
relay                unix  -       -       n       -       -       smtp
showq                unix  n       -       n       -       -       showq
error                unix  -       -       n       -       -       error
retry                unix  -       -       n       -       -       error
discard              unix  -       -       n       -       -       discard
local                unix  -       n       n       -       -       local
anvil                unix  -       -       n       -       1       anvil
scache               unix  -       -       n       -       1       scache

Note: `2525` is the port Plesk hands off to. `10026` is the reinjection port where OpenDKIM signs. Do not expose either port to the outside – they are bound to `127.0.0.1` only (see `inet_interfaces` and the `docker-compose.yml` port mapping in Step 9).
 
PART 2

Step 6 – The disclaimer script:
This is the only place where the "only this domain" check happens inside the relay. Everything that does not come from `<your-domain>` is passed through untouched.
Code:
#!/bin/bash
# /opt/disclaimer-relay/bin/add-disclaimer
set -euo pipefail

SENDER="$1"
RECIPIENT="$2"

# Pass-through for anything that is not from our domain
if ! printf '%s' "$SENDER" | grep -qiE '@<your-domain>$'; then
    /usr/sbin/sendmail -i -G -f "$SENDER" -- "$RECIPIENT"
    exit 0
fi

# Add disclaimer to text/plain and text/html only.
# alterMIME leaves other MIME parts (images, calendar invites) alone.
/usr/bin/altermime \
    --input=- \
    --output=- \
    --disclaimer=/etc/disclaimer/disclaimer.txt \
    --disclaimer-html=/etc/disclaimer/disclaimer.html \
    --xheader="X-Disclaimer-Added: yes" \
  | /usr/sbin/sendmail -i -G -f "$SENDER" -- "$RECIPIENT"

Two things worth pointing out:
- `-G` tells sendmail this is a relayed message (no local submission), which prevents "user unknown" bounces.
- Because this pipe service reinjects via `sendmail`, the message goes through `smtpd` on port `10026` (via the `smtp` transport in `master.cf`), where the DKIM milter signs it. That is the whole trick.

Step 7 – OpenDKIM configuration:
Code:
# /opt/disclaimer-relay/conf/opendkim.conf
Syslog                  yes
SyslogSuccess           yes
LogWhy                  yes
UMask                   002

Domain                  <your-domain>
Selector                <your-selector>
KeyFile                 /etc/opendkim/keys/<your-domain>.private

Socket                  inet:[email protected]
PidFile                 /run/opendkim/opendkim.pid

Mode                    sv
Canonicalization        relaxed/relaxed
SigningTable            refile:/etc/opendkim/SigningTable
KeyTable                refile:/etc/opendkim/KeyTable
ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts

OversignHeaders         From

Code:
# /opt/disclaimer-relay/conf/KeyTable
<your-selector>._domainkey.<your-domain> <your-domain>:<your-selector>:/etc/opendkim/keys/<your-domain>.private

Code:
# /opt/disclaimer-relay/conf/SigningTable
*@<your-domain> <your-selector>._domainkey.<your-domain>

Code:
# /opt/disclaimer-relay/conf/TrustedHosts
127.0.0.1
::1
localhost

Replace `<your-selector>` with the selector Plesk uses (usually `default`) and `<your-domain>` with your domain.

Step 8 – Disclaimer content:
Code:
# /opt/disclaimer-relay/disclaimer.txt
--
This e-mail originates from <your-domain>. It may contain confidential
information. If you are not the intended recipient, please delete it.

Code:
<!-- /opt/disclaimer-relay/disclaimer.html -->
<br><hr>
<p style="font-size:12px;color:#666;">
This e-mail originates from <your-domain>. It may contain confidential
information. If you are not the intended recipient, please delete it.
</p>
 
PART 3

Step 9 – `docker-compose.yml`:

Code:
# /opt/disclaimer-relay/docker-compose.yml
services:
  relay:
    build: .
    container_name: disclaimer-relay
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./dkim/<your-domain>.private:/etc/opendkim/keys/<your-domain>.private:ro
    healthcheck:
      test: ["CMD-SHELL", "postfix status && test -S /var/spool/postfix/public/pickup"]
      interval: 30s
      timeout: 5s
      retries: 3

`network_mode: host` is deliberate: the container needs to reach `127.0.0.1:2525` and `127.0.0.1:12301`, and binding to `127.0.0.1` inside a bridged network would not be reachable from Plesk's Postfix. With `network_mode: host` it listens on the host's loopback, which is exactly what we want and nothing more.

Step 10 – Entrypoint:
Code:
#!/bin/bash
# /opt/disclaimer-relay/bin/entrypoint.sh
set -e

mkdir -p /run/opendkim /var/spool/postfix
chown -R opendkim:opendkim /run/opendkim /etc/opendkim

# Start OpenDKIM in the background
opendkim -x /etc/opendkim.conf &
sleep 1

# Validate Postfix configuration before starting
postfix check

# Start Postfix in the foreground so the container stays alive
exec postfix start-fg
Code:
chmod 755 /opt/disclaimer-relay/bin/entrypoint.sh
chmod 755 /opt/disclaimer-relay/bin/add-disclaimer

Step 11 – Copy the DKIM private key:
Code:
cp /etc/opendkim/keys/<your-domain>/<your-selector>.private \
   /opt/disclaimer-relay/dkim/<your-domain>.private
chmod 600 /opt/disclaimer-relay/dkim/<your-domain>.private

Make sure the file name and selector match what is in `KeyTable` and `opendkim.conf`.

Step 12 – Build and start the relay:
Code:
cd /opt/disclaimer-relay
docker compose build
docker compose up -d
docker compose logs -f relay

Check the logs for:
- `opendkim: ... listening on 127.0.0.1:12301`
- Postfix starting without `warning` or `fatal`

Quick smoke test from the host:
Code:
# Should connect and show the SMTP banner
nc -zv 127.0.0.1 2525
nc -zv 127.0.0.1 10026

Step 13 – Plesk side: the transport map:
This is the only change on the Plesk host, and it is a file that Plesk does not manage. We do not touch `master.cf` at all.
Code:
cat > /etc/postfix/transport-disclaimer <<'EOF'
<your-domain>    smtp:[127.0.0.1]:2525
EOF

postmap /etc/postfix/transport-disclaimer
chmod 644 /etc/postfix/transport-disclaimer /etc/postfix/transport-disclaimer.db

Then add the map to `main.cf`. To avoid clobbering an existing `transport_maps` line, do it with `postconf`:
Code:
# Show current value
postconf -h transport_maps

# Append our map (keeps existing entries if any)
CURRENT=$(postconf -h transport_maps)
if [ -z "$CURRENT" ]; then
    postconf -e "transport_maps = hash:/etc/postfix/transport-disclaimer"
else
    case "$CURRENT" in
        *transport-disclaimer*) echo "already present" ;;
        *) postconf -e "transport_maps = $CURRENT, hash:/etc/postfix/transport-disclaimer" ;;
    esac
fi

postfix check && postfix reload

Step 14 – Self-healing for the transport map (the only Plesk-touchable bit):
Plesk can theoretically rewrite `main.cf` and drop the `transport_maps` line. The map file itself survives, so the fix is trivial and safe. A tiny cron job is enough:

Code:
cat > /usr/local/sbin/plesk-transport-check.sh <<'EOF'
#!/bin/bash
# Re-add the disclaimer transport map if Plesk removed it.
MAP="hash:/etc/postfix/transport-disclaimer"
CURRENT=$(postconf -h transport_maps 2>/dev/null || true)

if printf '%s' "$CURRENT" | grep -q "transport-disclaimer"; then
    exit 0
fi

if [ -z "$CURRENT" ]; then
    postconf -e "transport_maps = $MAP"
else
    postconf -e "transport_maps = $CURRENT, $MAP"
fi

postfix check && postfix reload
logger -t disclaimer-relay "transport_maps was reset by Plesk, re-applied"
EOF

chmod 700 /usr/local/sbin/plesk-transport-check.sh
echo '*/5 * * * * root /usr/local/sbin/plesk-transport-check.sh' \
    > /etc/cron.d/plesk-transport-check
chmod 644 /etc/cron.d/plesk-transport-check

This is far less invasive than the `master.cf` surgery from Option 2: it only ever re-adds one `postconf` line, and if it fails, mail still flows (just without the disclaimer), so nothing breaks.

Step 15 – Disable Plesk's DKIM for this domain:
This is important. If Plesk keeps signing outgoing mail for `<your-domain>` before it reaches the relay, the relay's disclaimer invalidates that signature, and you end up with `dkim=fail` again.
Code:
# Turn off Plesk's DKIM signing for the domain
plesk bin dkim_manager -d -domain <your-domain>

The DNS record (`<your-selector>._domainkey.<your-domain>`) stays in place – the relay uses the same key, so external verifiers still find it. Only the *signing* moves from Plesk to the relay.

Double-check that no other DKIM signer is active for this domain (for example the Email Security extension or a milter in Plesk's `main.cf`):
Code:
postconf -h smtpd_milters non_smtpd_milters

If Plesk is signing via a milter for all domains, you may need to scope that down in Plesk's own settings rather than in `main.cf`. In the default Plesk setup, DKIM is done per-domain by Plesk itself, so `plesk bin dkim_manager -d` is enough.

Step 16 – Test:
1. Send a mail from an address in `<your-domain>` to a Gmail account.
2. In Gmail, open the message → "Show original".
3. Check:
- The disclaimer is visible in the body.
- `Authentication-Results` contains `dkim=pass header.d=<your-domain>`.
- `X-Disclaimer-Added: yes` is present.
4. Send a mail from a different domain on the same Plesk server to the same Gmail account and confirm no disclaimer and no `X-Disclaimer-Added` header.

If DKIM fails, check the relay logs:
Code:
docker compose logs --tail=200 relay | grep -Ei 'dkim|opendkim|sign'

Common causes: wrong selector in `KeyTable`/`opendkim.conf`, private key permissions, or Plesk still signing for the domain.

Step 17 – Rollback (if you need it):
Code:
# Remove the transport map entry
CURRENT=$(postconf -h transport_maps)
NEW=$(printf '%s' "$CURRENT" | sed 's#,\?[[:space:]]*hash:/etc/postfix/transport-disclaimer##g')
postconf -e "transport_maps = $NEW"
postfix check && postfix reload

# Remove the cron job
rm -f /etc/cron.d/plesk-transport-check

# Stop and remove the relay
cd /opt/disclaimer-relay && docker compose down

# Re-enable Plesk DKIM if you want it back
plesk bin dkim_manager -e -domain <your-domain>

Why this should be a clean solution?

1. Plesk's Postfix is untouched except for one `transport_maps` line, which is trivially re-addable and whose loss does not break mail flow.
2. DKIM is valid because signing happens in the relay, after the body was modified.
3. Only `<your-domain>` is affected. The transport map matches exactly one domain; everything else goes out exactly as before.
4. Plesk updates cannot break it in any way that matters: even if `main.cf` is rewritten, the cron job restores the one line within 5 minutes, and mail keeps flowing meanwhile.
5. No second server needed. The relay runs on the same host, isolated in Docker, bound to `127.0.0.1` only.
6. MIME safety. alterMIME only touches `text/plain` and `text/html`, so inline images and calendar invites survive.
7. You are now running a second Postfix on the host. Keep it updated (`docker compose build --pull` and `docker compose up -d` on a regular schedule, e.g. monthly, or via a cron job). A stale relay is a security risk, just like a stale Plesk.
8. Outbound port 25. The relay sends mail directly to the internet on port 25. If your host or provider blocks it, set `relayhost` in the relay's `main.cf` to your provider's smarthost and add SASL credentials – Plesk's own outbound settings do **not** apply to the container.
9. No greylisting / no Plesk spam checks on the relay. The relay is a pass-through, so it does not need them. But if you ever route inbound mail through it, that would change – don't do that. The transport map only matches outgoing mail for one domain, and that is the intended scope.
10. The disclaimer is added to all outgoing mail from `<your-domain>`, including internal mail between two mailboxes on the same server. If that is not what you want, add a recipient check in `add-disclaimer` (e.g. skip if `$RECIPIENT` matches a local mailbox).
11. DKIM key rotation. If you ever rotate the DKIM key in Plesk, you must copy the new private key into `/opt/disclaimer-relay/dkim/` and restart the container. Add this to your runbook.
12. Test first. Set this up on a test domain, send to Gmail, Outlook and a self-hosted recipient, and check `Authentication-Results` in all three before you touch production.
13. Monitoring. Watch the relay logs and the cron job's `logger` tag `disclaimer-relay`. If the relay is down, mail for `<your-domain>` will queue in Plesk's Postfix (it does not get lost), but it will not go out until the relay is back. A simple check like `docker compose ps` in your monitoring is enough.

Let me know how the test goes.

And please, no comments about whether I had a lot of free time. There was a bit of self-interest involved, because I need something like this myself. ;)

Regards
Tessa
 
Back
Top