OneLinersCommand workbench
Guides
Services & Applications / Security

Build a complete Postfix and Dovecot virtual mail stack

Combine SMTP, submission, virtual domains, Dovecot authentication, LMTP delivery, IMAP TLS, quotas, Rspamd, DKIM, DNS, backups, and end-to-end validation.

240 min8 stepsChanges system stateRevision 2
Save or explore
Save to collectionCreate a collection in the sidebar first.
0 of 8 steps completed
Goal

Operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit.

Supported environments
  • Postfix 3.8+
  • Dovecot CE 2.4
  • Rspamd 3.x
Prerequisites
  • Authoritative DNS and stable identity Control forward and reverse DNS, choose the canonical mail hostname and domains, and verify the host is not behind an outbound SMTP-blocking network.hostname -f; getent ahosts $(hostname -f); dig +short -x {{publicIp}}
  • Recovery and queue safety Keep console access, back up active configuration, and record queue state before changing routing, authentication, filters, or mailbox delivery.
  • Abuse and deliverability plan Define relay boundaries, account owners, rate limits, bounce handling, postmaster address, monitoring, and how compromised credentials will be revoked.
Operating boundary

OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.

Full guide

What you will build

System
  • A production Dovecot implementation of “Build a complete Postfix and Dovecot virtual mail stack” with explicit SMTP/IMAP boundaries, identity, durable state and observable delivery evidence.
  • A read-only baseline, staged candidate and end-to-end canary covering DNS, TLS, authentication, recipient or route policy, queue/mailbox state and logs.
  • A security and rollback procedure that avoids open relay, backscatter, plaintext credentials, world-readable keys/mail and unreviewed bulk queue actions.
Observable outcome
  • Operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit. The intended success path is visible in native status, protocol transcript, headers or mailbox evidence.
  • Expected unauthorized relay, unknown-recipient, wrong-sender, invalid-authentication or wrong-certificate tests fail at the declared boundary without harming unrelated mail.

Architecture

How the parts fit together

Postfix owns public SMTP, recipient validation, queueing and outbound delivery. Dovecot owns authentication, LMTP mailbox delivery and IMAP access. Both share an explicit virtual-user/mailbox model but use private Unix sockets with narrow permissions rather than shared root credentials. TLS certificates, DNS identity, DKIM, firewall policy, logs, quotas and backup/restore surround the request path. Each boundary is validated before an end-to-end message is accepted.

PostfixOwns SMTP policy, queue and outbound transport.
DovecotOwns authentication, LMTP delivery and IMAP mailbox access.
Virtual identity/data layerMaps domains/users to private Maildir paths and quotas.
DNS/TLS/DKIM/operationsAuthenticate the service and make delivery recoverable and observable.
  1. Inventory hostname/DNS, listeners, certificates, identities, recipient/relay maps, queue/mailbox state, logs and a recoverable configuration/data baseline.
  2. Prepare the full stack candidate with official Dovecot syntax, protected secrets and one explicit service/data boundary at a time.
  3. Run native configuration validation and immediate read-only checkpoint before reload or acceptance of new messages.
  4. Use controlled local and external canaries plus an expected-denial test, preserve message identifiers/headers, and retain the prior configuration for rollback.

Assumptions

  • The public mail hostname, forward/reverse DNS ownership, supported package version and responsibility for ports 25/587/993 are known.
  • A maintenance or canary window, console recovery and current protected backup of configuration, keys, identity mappings and relevant mailbox/queue data exist.
  • Test sender and recipient addresses are owned by the operator; no unsolicited or third-party traffic is generated during verification.
  • Secrets and private keys are delivered outside shell history and have narrowly defined service ownership and rotation plans.

Key concepts

envelope identity
SMTP sender and recipient used for routing, delivery status and SPF; it is distinct from visible message headers.
open relay
An MTA that accepts unauthorized third-party sender-to-recipient forwarding, enabling abuse and reputation damage.
backscatter
A later non-delivery report sent to a forged sender because an invalid recipient was accepted instead of rejected during SMTP.
alignment
DMARC relationship between visible From domain and authenticated SPF or DKIM domain.
Maildir
A mailbox format storing messages as individual files in cur/new/tmp directories with strict ownership.

Before you copy

Values used in this guide

{{canary}}

Operator-reviewed value used by this tutorial for canary; derive it from the target environment and never from untrusted request data.

Example: mail-canary-20260725
{{certFile}}

Operator-reviewed value used by this tutorial for certFile; derive it from the target environment and never from untrusted request data.

Example: /etc/letsencrypt/live/mail.example.com/fullchain.pem
{{domain}}

Fully qualified public or internal hostname served by this configuration.

Example: example.com
{{externalRecipient}}

Operator-reviewed value used by this tutorial for externalRecipient; derive it from the target environment and never from untrusted request data.

Example: owned-test@example.net
{{mailHost}}

Operator-reviewed value used by this tutorial for mailHost; derive it from the target environment and never from untrusted request data.

Example: mail.example.com
{{mailRoot}}

Operator-reviewed value used by this tutorial for mailRoot; derive it from the target environment and never from untrusted request data.

Example: /srv/vmail
{{mailbox}}

Operator-reviewed value used by this tutorial for mailbox; derive it from the target environment and never from untrusted request data.

Example: alice@example.com
{{managementCidr}}

Trusted administration network in CIDR notation.

Example: 192.0.2.0/24
{{protectedSecret}}

Operator-reviewed value used by this tutorial for protectedSecret; derive it from the target environment and never from untrusted request data.

Example: secret-manager-reference
{{publicIp}}

Operator-reviewed value used by this tutorial for publicIp; derive it from the target environment and never from untrusted request data.

Example: 192.0.2.20
{{receivedExternalMessage}}

Operator-reviewed value used by this tutorial for receivedExternalMessage; derive it from the target environment and never from untrusted request data.

Example: example-receivedexternalmessage
{{selector}}

Operator-reviewed value used by this tutorial for selector; derive it from the target environment and never from untrusted request data.

Example: mail2026

Security and production boundaries

  • Never weaken relay/recipient checks, publish private DKIM/TLS keys, enable plaintext authentication, or expose web/IMAP administration broadly to make a test pass.
  • Mail content, credentials, queues, logs and backups contain personal or confidential data; restrict, encrypt, minimize and retain them under an explicit policy.
  • Use dedicated service identities and root-readable credential maps; verify logs and configuration output are redacted before sharing.

Stop before continuing if

  • Stop if a test permits unauthorized relay, accepts unknown recipients for later bounce, sends credentials without verified TLS, or exposes private keys/mailbox files.
  • Do not continue when hostname/PTR ownership, package/config version, recipient map, route, queue, mailbox ownership or rollback backup is ambiguous.
  • Immediately quarantine the candidate when unrelated mail is rerouted, deleted, multiply delivered, signed by the wrong domain, or inaccessible after reload.
01

instruction

Document domains, identities, and complete mail flow

read-only

Draw inbound SMTP to Postfix/Rspamd/LMTP/Maildir, client submission to Dovecot SASL/Postfix, IMAP access, outbound DKIM, queues, DNS, and backup boundaries.

Why this step matters

Document domains, identities, and complete mail flow is a separate checkpoint because it establishes one auditable part of operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Draw inbound SMTP to Postfix/Rspamd/LMTP/Maildir, client submission to Dovecot SASL/Postfix, IMAP access, outbound DKIM, queues, DNS, and backup boundaries. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Document domains, identities, and complete mail flow”. The scope must remain limited to the selected application and supported host.

Syntax explained

printf
Invokes the principal tool or configuration operation for “Document domains, identities, and complete mail flow”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
Command
printf '%s\n' '25/tcp -> Postfix -> Rspamd -> Dovecot LMTP -> Maildir' '587/tcp -> Postfix submission -> Dovecot auth' '993/tcp -> Dovecot IMAP TLS'
Example output / evidence
Every port, Unix socket, identity, storage path, and policy owner is named.

Checkpoint: Checkpoint: Document domains, identities, and complete mail flow

Continue whenEvery port, Unix socket, identity, storage path, and policy owner is named. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when printf reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Document domains, identities, and complete mail flow” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v printf 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
02

instruction

Prepare DNS and certificate identity

read-only

Publish A/AAAA, PTR, MX, SPF, DKIM, DMARC, autoconfig records as required, then issue a certificate covering SMTP and IMAP client hostnames.

Why this step matters

Prepare DNS and certificate identity is a separate checkpoint because it establishes one auditable part of operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Publish A/AAAA, PTR, MX, SPF, DKIM, DMARC, autoconfig records as required, then issue a certificate covering SMTP and IMAP client hostnames. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Prepare DNS and certificate identity”. The scope must remain limited to the selected application and supported host.

Syntax explained

dig
Invokes the principal tool or configuration operation for “Prepare DNS and certificate identity”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
Command
Fill variables0/4 ready

Values stay on this page and are never sent or saved.

dig +short A {{mailHost}}; dig +short -x {{publicIp}}; dig +short MX {{domain}}; dig +short TXT {{domain}}; openssl x509 -in {{certFile}} -noout -ext subjectAltName -dates
Example output / evidence
DNS and certificate identities match the architecture.

Checkpoint: Checkpoint: Prepare DNS and certificate identity

Continue whenDNS and certificate identities match the architecture. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when dig reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Prepare DNS and certificate identity” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v dig 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
03

command

Install services and create virtual storage identity

caution

Install Postfix, Dovecot IMAP/LMTP, Rspamd, Redis, testing tools, and create the non-login vmail account with protected storage.

Why this step matters

Install services and create virtual storage identity is a separate checkpoint because it establishes one auditable part of operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Install Postfix, Dovecot IMAP/LMTP, Rspamd, Redis, testing tools, and create the non-login vmail account with protected storage. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Install services and create virtual storage identity”. The scope must remain limited to the selected application and supported host.

Syntax explained

apt
Invokes the principal tool or configuration operation for “Install services and create virtual storage identity”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
&&
Runs the following operation only when the previous command succeeds, preventing a reload or state transition after a failed validation.
Command
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

sudo apt update && sudo apt install --yes postfix dovecot-core dovecot-imapd dovecot-lmtpd rspamd redis-server swaks; sudo groupadd --system vmail; sudo useradd --system --gid vmail --home-dir {{mailRoot}} --shell /usr/sbin/nologin vmail; sudo install -d -o vmail -g vmail -m 0750 {{mailRoot}}
Example output / evidence
All services and the vmail storage identity exist.

Checkpoint: Checkpoint: Install services and create virtual storage identity

Continue whenAll services and the vmail storage identity exist. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when apt reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Install services and create virtual storage identity” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v apt 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
04

config

Configure Dovecot auth, virtual users, LMTP, IMAP TLS, and quotas

caution

Define protected passdb/userdb, Maildir path, private auth and LMTP sockets inside Postfix spool, TLS-only authentication, IMAPS, and quota behavior.

Why this step matters

Configure Dovecot auth, virtual users, LMTP, IMAP TLS, and quotas is a separate checkpoint because it establishes one auditable part of operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Define protected passdb/userdb, Maildir path, private auth and LMTP sockets inside Postfix spool, TLS-only authentication, IMAPS, and quota behavior. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Configure Dovecot auth, virtual users, LMTP, IMAP TLS, and quotas”. The scope must remain limited to the selected application and supported host.

Syntax explained

doveconf
Invokes the principal tool or configuration operation for “Configure Dovecot auth, virtual users, LMTP, IMAP TLS, and quotas”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
|
Passes standard output to the next read-only inspection stage; review each stage separately if the combined result is surprising.
/etc/dovecot
Is the persistent configuration boundary changed by this step. Keep an attributable backup and validate the consumer before reload.
File /etc/dovecot
Configuration
sudo doveconf -n; sudo ls -l /var/spool/postfix/private/{auth,dovecot-lmtp} 2>/dev/null || true
Example output / evidence
Dovecot configuration resolves identities and declares Postfix-readable private sockets.

Checkpoint: Checkpoint: Configure Dovecot auth, virtual users, LMTP, IMAP TLS, and quotas

Continue whenDovecot configuration resolves identities and declares Postfix-readable private sockets. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when doveconf reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Configure Dovecot auth, virtual users, LMTP, IMAP TLS, and quotas” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v doveconf 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
05

config

Configure Postfix domains, submission, SASL, and LMTP delivery

caution

Set canonical identity, narrow trust, reject unauthorized relay and unknown recipients, define virtual maps, use Dovecot SASL on 587, and LMTP transport.

Why this step matters

Configure Postfix domains, submission, SASL, and LMTP delivery is a separate checkpoint because it establishes one auditable part of operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Set canonical identity, narrow trust, reject unauthorized relay and unknown recipients, define virtual maps, use Dovecot SASL on 587, and LMTP transport. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Configure Postfix domains, submission, SASL, and LMTP delivery”. The scope must remain limited to the selected application and supported host.

Syntax explained

postconf
Invokes the principal tool or configuration operation for “Configure Postfix domains, submission, SASL, and LMTP delivery”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
|
Passes standard output to the next read-only inspection stage; review each stage separately if the combined result is surprising.
/etc/postfix
Is the persistent configuration boundary changed by this step. Keep an attributable backup and validate the consumer before reload.
File /etc/postfix
Configuration
postconf -n; postconf -M; postconf -P | grep submission
Example output / evidence
Postfix policy separates public SMTP, authenticated submission, and virtual LMTP delivery.

Checkpoint: Checkpoint: Configure Postfix domains, submission, SASL, and LMTP delivery

Continue whenPostfix policy separates public SMTP, authenticated submission, and virtual LMTP delivery. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when postconf reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Configure Postfix domains, submission, SASL, and LMTP delivery” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v postconf 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
06

config

Integrate Rspamd and DKIM signing

caution

Connect local milters, start with measured actions, sign only authenticated owned-domain mail, publish selector DNS, and configure fail behavior.

Why this step matters

Integrate Rspamd and DKIM signing is a separate checkpoint because it establishes one auditable part of operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Connect local milters, start with measured actions, sign only authenticated owned-domain mail, publish selector DNS, and configure fail behavior. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Integrate Rspamd and DKIM signing”. The scope must remain limited to the selected application and supported host.

Syntax explained

rspamadm
Invokes the principal tool or configuration operation for “Integrate Rspamd and DKIM signing”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
/etc/rspamd
Is the persistent configuration boundary changed by this step. Keep an attributable backup and validate the consumer before reload.
File /etc/rspamd
Configuration
Fill variables0/2 ready

Values stay on this page and are never sent or saved.

sudo rspamadm configtest; postconf smtpd_milters non_smtpd_milters milter_default_action; dig +short TXT {{selector}}._domainkey.{{domain}}
Example output / evidence
Rspamd validates and DKIM public record is visible.

Checkpoint: Checkpoint: Integrate Rspamd and DKIM signing

Continue whenRspamd validates and DKIM public record is visible. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when rspamadm reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Integrate Rspamd and DKIM signing” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v rspamadm 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
07

verification

Constrain exposure and restart the full dependency chain

caution

Expose 25, 587, and 993 plus management SSH; keep Redis, Dovecot auth/LMTP, databases, and Rspamd controller private; validate and restart in order.

Why this step matters

Constrain exposure and restart the full dependency chain is a separate checkpoint because it establishes one auditable part of operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Expose 25, 587, and 993 plus management SSH; keep Redis, Dovecot auth/LMTP, databases, and Rspamd controller private; validate and restart in order. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Constrain exposure and restart the full dependency chain”. The scope must remain limited to the selected application and supported host.

Syntax explained

ufw
Invokes the principal tool or configuration operation for “Constrain exposure and restart the full dependency chain”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
Command
Fill variables0/1 ready

Values stay on this page and are never sent or saved.

sudo ufw allow 25/tcp; sudo ufw allow 587/tcp; sudo ufw allow 993/tcp; sudo ufw allow from {{managementCidr}} to any port 22 proto tcp; sudo doveconf -n >/dev/null; sudo rspamadm configtest; sudo postfix check; sudo systemctl restart redis-server rspamd dovecot postfix; sudo ss -lntup
Example output / evidence
Only intended public ports listen and all services are active.

Checkpoint: Checkpoint: Constrain exposure and restart the full dependency chain

Continue whenOnly intended public ports listen and all services are active. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when ufw reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Constrain exposure and restart the full dependency chain” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v ufw 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.
08

verification

Run an end-to-end delivery and recovery test matrix

read-only

Test inbound known/unknown recipient, authenticated submission, relay denial, IMAP login, LMTP, spam action, DKIM/SPF/DMARC, quota, queue deferral, certificate validation, restart, and mailbox backup/restore.

Why this step matters

Run an end-to-end delivery and recovery test matrix is a separate checkpoint because it establishes one auditable part of operate a coherent self-hosted mail stack whose trust boundaries, delivery paths, authentication, storage, and recovery are all explicit. Performing it independently keeps a failed prerequisite, syntax error, or compatibility mismatch from being hidden by later actions.

What to understand

Test inbound known/unknown recipient, authenticated submission, relay denial, IMAP login, LMTP, spam action, DKIM/SPF/DMARC, quota, queue deferral, certificate validation, restart, and mailbox backup/restore. Read the complete command or configuration before execution, replace the documented placeholders, and compare the target host with the supported environments listed at the beginning of this tutorial.

Capture the before-state and the exact output in the change record. If this step modifies a file or service, validate the candidate with its native checker before any reload; a successful process exit alone does not prove that the application uses the intended value.

Use a representative staging or canary host first. Repeat the stated checkpoint immediately, because proceeding with ambiguous evidence makes the later end-to-end verification and rollback materially harder.

System changes

  • This step may affect the files, packages, identities, services, or runtime policy named in “Run an end-to-end delivery and recovery test matrix”. The scope must remain limited to the selected application and supported host.

Syntax explained

swaks
Invokes the principal tool or configuration operation for “Run an end-to-end delivery and recovery test matrix”; confirm that it resolves to the expected packaged executable or file before using elevated privileges.
{{…}}
Marks an operator-supplied value. Replace every placeholder deliberately; do not paste untrusted text or leave braces in the production command.
Command
Fill variables0/5 ready

Values stay on this page and are never sent or saved.

swaks --server {{mailHost}} --to {{mailbox}} --from sender@example.net --header 'X-Test: {{canary}}'; swaks --server {{mailHost}} --port 587 --tls --tls-verify --auth --auth-user {{mailbox}} --auth-password '{{protectedSecret}}' --to {{externalRecipient}}; sudo doveadm search -u {{mailbox}} mailbox INBOX HEADER X-Test {{canary}}
Example output / evidence
Inbound mail reaches IMAP, outbound passes authentication, denial paths fail, and recovery evidence is recorded.

Checkpoint: Checkpoint: Run an end-to-end delivery and recovery test matrix

Continue whenInbound mail reaches IMAP, outbound passes authentication, denial paths fail, and recovery evidence is recorded. Treat this concrete evidence as the minimum success signal and also confirm that unrelated services and the previous healthy path remain unchanged.

Stop whenStop before the next step when swaks reports an error, the output differs materially from the example, an unexpected package/service/path is affected, or the required before-state and rollback artifact are missing.

If this step fails

The command for “Run an end-to-end delivery and recovery test matrix” fails, produces no useful evidence, or the expected service/configuration state is absent.

Likely causeA placeholder targets the wrong environment, the installed version uses another path or unit name, permissions are insufficient, or an earlier prerequisite was not satisfied.

Safe checks
  • command -v swaks 2>/dev/null || true
  • systemctl --failed --no-pager 2>/dev/null || true
  • journalctl -p warning -n 50 --no-pager 2>/dev/null || true

ResolutionDo not improvise a privileged workaround. Re-read the environment and variable table, inspect the official source for the installed version, restore the candidate file if necessary, and repeat only this checkpoint.

Security notes

  • Keep secrets out of shell history, process arguments, screenshots, logs, and tutorial placeholders. Elevate only the narrow command that requires it and preserve package signature and TLS verification.

Alternatives

  • When the host layout or software version differs, use the vendor-supported equivalent in a disposable staging environment and document the mapping before touching production.

Stop conditions

  • Stop if the action broadens network exposure, permissions, package sources, writable paths, or service privileges beyond the tutorial's declared architecture.

Finish line

Verification checklist

Service and socket matrixsystemctl is-active postfix dovecot rspamd redis-server; sudo ss -lntup; sudo ss -lxnp | grep -E 'dovecot|rspamd|postfix'All dependencies are active and public/private endpoints match the design.
Authentication resultsgrep -iE 'Authentication-Results:.*(spf=pass|dkim=pass|dmarc=pass)' {{receivedExternalMessage}}The external canary passes SPF, DKIM, and DMARC alignment.

Recovery guidance

Common problems and safe checks

A message remains queued or the remote server returns a temporary 4xx response.

Likely causeDNS/MX resolution, routing, network reachability, TLS negotiation, remote greylisting/rate limits, reputation or recipient policy prevents delivery.

Safe checks
  • exim -bp 2>/dev/null || postqueue -p
  • dig +short MX example.net
  • journalctl -u exim4 -u postfix --since '-30 min' --no-pager

ResolutionInspect one message's recorded diagnostic and route first, fix the evidenced dependency, then retry only that message; do not force an undiagnosed bulk queue.

SMTP accepts a recipient, but the mailbox is absent, unreadable or never visible over IMAP.

Likely causeRecipient maps, LMTP/LDA route, virtual UID/GID, Maildir path, quota, Dovecot namespace or filesystem permissions disagree.

Safe checks
  • doveconf -n
  • doveadm user user@example.com
  • doveadm mailbox list -u user@example.com

ResolutionTrace the exact address through recipient validation, delivery socket and resolved mailbox path; correct the narrow mapping/ownership mismatch before accepting more mail.

Authentication or TLS fails despite apparently correct credentials and certificate files.

Likely causeThe listener uses another configuration, hostname/SAN does not match, chain/key permissions are wrong, authentication is attempted without TLS, or the identity backend maps another username.

Safe checks
  • openssl s_client -connect mail.example.com:587 -starttls smtp -servername mail.example.com </dev/null
  • openssl s_client -connect mail.example.com:993 -servername mail.example.com </dev/null
  • journalctl -u dovecot -u postfix -u exim4 -p warning -n 100 --no-pager

ResolutionVerify the advertised hostname, chain, listener and mapped user independently; never disable certificate verification or enable plaintext authentication to bypass the failure.

After the procedure

Alternatives and next steps

Consider these alternatives

  • Use a reputable managed mail transport or mailbox provider when staffing, deliverability, abuse response, DNS reputation and 24/7 queue operations cannot be sustained.
  • Separate inbound, outbound, submission and mailbox roles across hosts only when TLS identity, routing, backups and observability remain end-to-end testable.

Operate it safely

  • Alert on queue age/depth, delivery deferrals, authentication failures, TLS/certificate expiry, disk/quota pressure, DKIM/DMARC failures and backup restore age.
  • Review relay/recipient maps, dormant users, supported versions, DNS policy and key/certificate rotation at least every 90 days.
  • Practice one-message queue diagnosis and an isolated mailbox/config restore so incident steps are proven before a real outage.

Reference

Frequently asked questions

Why is one successful test email insufficient?

It may bypass the actual external DNS, authentication, recipient, DKIM, queue retry or IMAP path. Test each boundary and preserve protocol/header evidence.

Can TLS be tested by checking that encryption is present?

No. Verify the chain and hostname and ensure authentication is unavailable before STARTTLS; encryption to an unverified endpoint is not server authentication.

Should a stuck queue be forced immediately?

No. Read one message's diagnostic and fix the dependency first. Bulk retries can amplify rate limits, duplicates or reputation damage.

Recovery

Rollback

Roll back one boundary at a time—DNS/signing, filtering, submission, delivery, or IMAP—while preserving queues and mail storage.

  1. Restore archived service configurations, validate each daemon, and restart dependency order.
  2. Keep Postfix queue and vmail storage intact; disable new routing before moving any data.
  3. Keep old DKIM DNS selectors published through delayed-message lifetime and retain verified backups.

Evidence

Sources and review

Verified 2026-07-25Review due 2026-10-23
Postfix virtual domain hostingofficialPostfix SASL supportofficialDovecot SASL authentication for PostfixofficialDovecot LMTP with PostfixofficialRspamd MTA integrationofficial