Linux Mail Server
Distro support
Postfix and Dovecot run on both families and their config layout
(/etc/postfix/main.cf, /etc/dovecot/) is largely identical;
postconf, postmap, postqueue, newaliases behave the same. The
differences are a few package names, the mail log path, and SELinux. Body uses
Debian/Ubuntu; the RHEL family (Fedora, RHEL, CentOS Stream, Rocky, Alma,
Oracle) equivalents are in the matrix.
| Concept |
Debian/Ubuntu |
RHEL family |
| Postfix package / unit |
postfix |
postfix (same) |
| Default MTA |
sometimes exim4 |
postfix |
| Dovecot |
dovecot-core, dovecot-imapd |
dovecot |
| DKIM |
opendkim (main) |
opendkim (EPEL) |
| Mail log |
/var/log/mail.log |
/var/log/maillog |
| Config paths |
/etc/postfix, /etc/dovecot |
same |
| Tools |
postconf, postmap, postqueue, newaliases |
identical |
RHEL-family gotchas: opendkim (and some milters) come from EPEL
(ensure_epel) on RHEL/Rocky/Alma, but ship in main on Fedora. SELinux governs
Postfix/Dovecot — non-default mail-spool or maildir paths need the right
contexts (restorecon, semanage fcontext) and some integrations need
booleans. Mail logs are in /var/log/maillog (cross-ref linux-log-management).
Deep SELinux coverage is in linux-server-hardening / Phase 2.
In sk-* scripts use the common.sh primitives (pkg_install, ensure_epel,
svc_name) instead of hardcoding the family. See
linux-bash-scripting and
docs/multi-distro/plan.md.
Use when
- Managing Postfix, Exim, Dovecot, queue behavior, or SMTP testing.
- Debugging delivery failures, spam-folder placement, or TLS/authentication issues.
- Updating SPF, DKIM, or DMARC-related server-side behavior.
Do not use when
- The task is general DNS hosting unrelated to mail service; use
linux-dns-server.
- The task is generic network reachability without a mail-specific angle; use
linux-network-admin.
Required inputs
| Artefact |
Source |
Required? |
If absent |
| Mail role, software, domain/hostname, and current configuration |
Mail host and service owner |
required |
Return discovery commands; do not edit a guessed topology. |
| Symptom, timestamps, queue IDs, sender/recipient domain, and relevant redacted logs |
Incident report and host |
required for diagnosis |
Mark the affected transport stage not assessed. |
| DNS/TLS/relay ownership and approved test recipient |
Domain and service owners |
required for change/test |
Stop before publishing records or sending mail. |
Workflow
- Identify whether the issue is configuration, queueing, transport, or authentication.
- Inspect current config, queue state, and relevant logs.
- Apply the matching workflow below for reputation, submission, queue, or domain changes.
- Re-test SMTP flow and authentication to confirm the result.
- Stop if relay scope, DNS/TLS ownership, queue impact, test-recipient authority, or rollback is unresolved.
- Recover by restoring the prior validated config/records, reloading the service, and retesting a controlled message before resuming the queue.
Quality standards
- Verify with real SMTP tests and queue inspection, not assumption.
- Keep authentication records and mail config aligned.
- Separate transport problems from reputation and policy problems.
Anti-patterns
- Treating spam placement as only connectivity. Fix: inspect SPF, DKIM, DMARC, reverse DNS, TLS, reputation, and message evidence separately.
- Flushing/deleting a queue before diagnosis. Fix: sample queue IDs, reasons, age, destination patterns, and logs first.
- Enabling an open relay or broad trusted network. Fix: restrict relay to authenticated/explicit clients and test rejection externally.
- Publishing mail-authentication records without alignment tests. Fix: validate selectors, policy, envelope/header domains, and authoritative DNS.
- Logging or sharing message bodies/credentials unnecessarily. Fix: use queue IDs, headers, and redacted protocol traces.
Outputs
| Artefact |
Consumer |
Acceptance condition |
| Mail-path diagnosis or configuration change |
Mail operator |
Locates failure at submission, queue, DNS, transport, policy, mailbox, or reputation layer with evidence. |
| Authentication/TLS evidence |
Domain owner |
SPF/DKIM/DMARC alignment and certificate/hostname checks are observed, or explicitly unassessed. |
| Delivery verification |
Service owner |
Approved test mail receives expected SMTP codes and reaches the intended mailbox without creating an open relay. |
References
references/postfix-reference.md
references/email-authentication.md
references/debugging-delivery.md
Evidence Produced
| Artefact |
Acceptance condition |
| Mail-operation evidence |
Includes redacted config, queue samples, log timeline, SMTP transcript, DNS/authentication/TLS results, authorised headers, and rollback. |
Capability contract
Diagnosis defaults to read-only. Mail configuration, queue mutation, DNS publication, certificate changes, service reloads, or sending external test mail require explicit authority. Never expose mailbox credentials, private keys, or message content beyond approved evidence.
Degraded mode
Without host, DNS, or recipient access, assess only available layers and label the rest not assessed. A successful TCP connection is not a delivery or reputation pass.
Decision rules
| Choice |
Action |
Failure or risk avoided |
| Queue deferral cluster |
Inspect enhanced status/log cause before retry |
Amplifying a persistent failure. |
| Authentication passes but spam persists |
Examine reputation/content/provider feedback |
Rewriting healthy transport config. |
| Submission auth failure |
Test SASL/TLS listener and policy |
Weakening relay controls. |
Worked example
For a growing Postfix queue to one provider, sample deferred queue IDs, correlate enhanced status codes and logs, verify DNS/TLS/authentication, correct the evidenced cause, reload only after config validation, retry a small sample, and record delivery before releasing the remainder.
This skill is self-contained. Every command below is a standard mail
tool (postfix, postqueue, postconf, swaks, openssl, dig) present on
both Debian/Ubuntu and the RHEL family; body examples use Debian/Ubuntu
syntax, with RHEL-family differences in the Distro support matrix above.
The sk-* scripts in the Optional fast path section
are convenience wrappers — never required.
This skill covers running and debugging mail on a Debian/Ubuntu or RHEL-family server:
Postfix (default), Exim (alternative), Dovecot for IMAP, and the three
pillars of email authentication — SPF, DKIM, DMARC.
It does not own:
- Firewall rules for SMTP ports —
linux-firewall-ssl.
- DNS records themselves (MX, SPF, DKIM, DMARC live at the DNS host) —
but this skill validates them.
- Mail clients — out of scope.
Informed by Linux Network Administrator's Guide (Sendmail/Exim chapters,
translated to Postfix) and modern email authentication practice.
When to use
- Setting up a server to send mail (transactional, notifications, relay).
- Diagnosing "my email goes to spam."
- Checking a mail queue for stuck messages.
- Testing SMTP from the command line (EHLO, STARTTLS, auth, RCPT).
- Validating SPF, DKIM, DMARC records for a domain.
- Inspecting a remote MX's reachability and TLS.
When NOT to use
- Setting up cloud email (SES, SendGrid, Postmark) — those are API-based.
- Managing DNS records at a registrar — use the registrar's UI or API.
Standing rules
- Never run a mail server without SPF + DKIM + DMARC. Unauthenticated
mail is treated as spam by every modern receiver.
- Never relay mail for third parties without authentication. Open
relays are abuse vectors.
mynetworks in main.cf must be
127.0.0.0/8 only by default.
- Always enable TLS for submission (port 587). STARTTLS only, reject
plain auth.
- Always validate config before reload.
postfix check for Postfix,
exim -bV for Exim.
- The queue is the first thing to check on delivery problems.
- Log everything to
/var/log/mail.log (syslog) and
journalctl -u postfix — both exist on modern Ubuntu.
- Reverse DNS (PTR) of the sending IP must match the HELO name.
Mismatched PTR is the single biggest reason mail is flagged as spam.
Quick reference — manual commands
Postfix config and status
# Validate config — always run before reload
sudo postfix check
# Show effective config (difference from default)
postconf -n
# Reload
sudo postfix reload
# Or full restart if service behavior is stuck:
sudo systemctl restart postfix
# Service status
sudo systemctl status postfix --no-pager
sudo journalctl -u postfix -n 50 --no-pager
sudo tail -f /var/log/mail.log
Queue inspection
# Show queue
sudo postqueue -p
sudo mailq # alias
# Count by status
sudo postqueue -p | grep -c '^[A-F0-9]'
# Inspect a specific message
sudo postcat -q <queue-id>
# Force a flush (try delivery now)
sudo postqueue -f
# Delete a specific stuck message
sudo postsuper -d <queue-id>
# Delete everything (use with extreme care)
sudo postsuper -d ALL
SMTP testing from the command line
# Install swaks if needed
sudo apt install swaks
# Full SMTP conversation with TLS and auth
swaks --server mail.example.com \
--port 587 \
--from sender@example.com \
--to recipient@example.org \
--auth LOGIN \
--auth-user sender@example.com \
--tls \
--header "Subject: test $(date)" \
--body "test body"
# Just the handshake (no auth, no send)
swaks --server mail.example.com --port 587 --quit-after STARTTLS
# With openssl (lower level):
openssl s_client -starttls smtp -connect mail.example.com:587 -crlf
# Type: EHLO test.example.com
# Then: QUIT
Email authentication checks
# SPF lookup
dig +short TXT example.com | grep spf1
# DKIM selector (replace "default" with your actual selector)
dig +short TXT default._domainkey.example.com
# DMARC
dig +short TXT _dmarc.example.com
# MX record with priorities
dig +short MX example.com
# Reverse DNS (PTR) — must match HELO
dig +short -x $(curl -s https://api.ipify.org)
# Online checkers (for humans, but record the dig output yourself first):
# - https://mxtoolbox.com
# - Gmail Postmaster Tools
Full email-auth deep dive (record syntax, DKIM key generation via
opendkim-genkey, DMARC reporting, example DNS zone snippet) — see
references/email-authentication.md.
Typical workflows
Workflow: "Our emails are going to spam"
Walk references/debugging-delivery.md.
Condensed:
# 1. Queue health
sudo postqueue -p
# 2. Reject reason on a deferred message
sudo postcat -q <queue-id> | tail -20
# 3. SPF / DKIM / DMARC present?
dig +short TXT example.com | grep spf1
dig +short TXT default._domainkey.example.com
dig +short TXT _dmarc.example.com
# 4. PTR matches HELO?
dig +short -x $(postconf -h inet_interfaces | awk '{print $1}')
postconf -h myhostname
# 5. TLS working for submission?
swaks --server mail.example.com --port 587 --quit-after STARTTLS
Workflow: "Is port 587 submission working?"
swaks --server mail.example.com \
--port 587 \
--auth LOGIN \
--auth-user bot@example.com \
--tls
Reports each step (connection, STARTTLS, AUTH, MAIL FROM, RCPT TO, DATA).
Workflow: "The queue is growing"
# 1. How bad?
sudo postqueue -p | tail -5 # last line says "Total requests"
# 2. What's stuck and why?
sudo postqueue -p | head -30
# 3. Pick a message and see the specific rejection:
sudo postcat -q <queue-id>
# 4. Common fixes:
# - Greylist: just wait; Postfix will retry automatically
# - TLS handshake error: check recipient server's cert, your own
# - Auth required: fix relay credentials
# - Relay denied: check mynetworks, smtpd_recipient_restrictions
Workflow: "Add a new domain to an existing Postfix"
# 1. Edit main.cf — add to mydestination or virtual_mailbox_domains
sudo nano /etc/postfix/main.cf
# 2. If using virtual mailboxes, update the virtual maps:
sudo nano /etc/postfix/virtual_alias_maps
sudo postmap /etc/postfix/virtual_alias_maps
# 3. Validate
sudo postfix check
# 4. Reload
sudo postfix reload
# 5. Test with swaks
Troubleshooting / gotchas
- PTR record mismatch is the #1 spam trigger. If your server's IP
reverse-resolves to
vps-12345.provider.net but Postfix HELOs as
mail.example.com, receivers downgrade you immediately. Fix the PTR
at the VPS provider.
postfix reload doesn't reload everything. Changes to master.cf
require sudo systemctl restart postfix. postfix reload only
re-reads main.cf.
- TLS fails on port 465 but works on 587. Port 465 is implicit TLS
(SMTPS), 587 is STARTTLS. They need separate service stanzas in
master.cf — enable both.
- DKIM signs but receivers fail DMARC. Check alignment: the signing
domain (
d=) must match the From: header domain (relaxed alignment)
or exactly (strict). A DKIM-signed bounce that uses the mail server's
hostname as d= won't align with the sender's domain.
- Postfix is silently deferring. Look in
/var/log/mail.log — the
rejection reason is there. The queue only shows the summary.
- Dovecot and Postfix disagree about a user. Postfix's
virtual_mailbox_maps must match Dovecot's passdb / userdb. Use
a single source of truth (MySQL, LDAP, or a flat file) and point both
at it.
References
references/postfix-reference.md —
full Postfix reference: main.cf parameters, master.cf, queue
management, 3 complete config examples.
references/email-authentication.md —
SPF, DKIM (with opendkim), DMARC deep dive with DNS record examples.
references/debugging-delivery.md —
decision tree for delivery problems.
- Book: Linux Network Administrator's Guide (Kirch & Dawson) — mail
chapters (Sendmail/Exim, translated to Postfix).
- Book: Ubuntu Server Guide (Canonical) — Postfix and Dovecot.
- Man pages:
postfix(1), postconf(5), master(5), postqueue(1),
postcat(1), swaks(1).
Optional fast path (when sk-* scripts are installed)
Running sudo install-skills-bin linux-mail-server installs:
| Task |
Fast-path script |
| MX records for domain + reachability + TLS + PTR match |
sudo sk-mx-check --domain <d> |
| Audit SPF, DKIM, DMARC records for a domain |
sudo sk-spf-dkim-dmarc --domain <d> |
| Postfix/Exim queue inspection grouped by recipient |
sudo sk-mail-queue |
| Full SMTP conversation tester (wraps swaks) |
sudo sk-smtp-test --host <h> --port 587 --tls |
These are optional wrappers around dig, swaks, postqueue, and
openssl s_client.
Scripts
This skill installs the following scripts to /usr/local/bin/. To install:
sudo install-skills-bin linux-mail-server
| Script |
Source |
Core? |
Purpose |
| sk-mx-check |
scripts/sk-mx-check.sh |
no |
MX records for a domain, preference order, reachability, reverse DNS, TLS cert of each MX. |
| sk-spf-dkim-dmarc |
scripts/sk-spf-dkim-dmarc.sh |
no |
Audit SPF, DKIM, and DMARC records for a domain; report missing or misaligned. |
| sk-mail-queue |
scripts/sk-mail-queue.sh |
no |
Postfix/Exim queue inspection: depth, oldest, stuck, by recipient domain. |
| sk-smtp-test |
scripts/sk-smtp-test.sh |
no |
Full SMTP handshake tester (EHLO / STARTTLS / AUTH / MAIL FROM / RCPT TO / DATA), reports each step. |
1---2name: linux-mail-server3description: Use when operating or diagnosing Postfix, Exim, Dovecot, SMTP submission, mail queues, TLS, or SPF/DKIM/DMARC on a Linux mail host. Use linux-network-admin for general reachability and linux-dns-server when the task is authoritative zone operation.4license: MIT5---67# Linux Mail Server89## Distro support1011Postfix and Dovecot run on both families and their config layout12(`/etc/postfix/main.cf`, `/etc/dovecot/`) is **largely identical**;13`postconf`, `postmap`, `postqueue`, `newaliases` behave the same. The14differences are a few package names, the mail log path, and SELinux. Body uses15Debian/Ubuntu; the **RHEL family** (Fedora, RHEL, CentOS Stream, Rocky, Alma,16Oracle) equivalents are in the matrix.1718| Concept | Debian/Ubuntu | RHEL family |19|---|---|---|20| Postfix package / unit | `postfix` | `postfix` (same) |21| Default MTA | sometimes `exim4` | `postfix` |22| Dovecot | `dovecot-core`, `dovecot-imapd` | `dovecot` |23| DKIM | `opendkim` (main) | `opendkim` (**EPEL**) |24| Mail log | `/var/log/mail.log` | `/var/log/maillog` |25| Config paths | `/etc/postfix`, `/etc/dovecot` | same |26| Tools | `postconf`, `postmap`, `postqueue`, `newaliases` | identical |2728**RHEL-family gotchas:** `opendkim` (and some milters) come from **EPEL**29(`ensure_epel`) on RHEL/Rocky/Alma, but ship in main on Fedora. SELinux governs30Postfix/Dovecot — non-default mail-spool or maildir paths need the right31contexts (`restorecon`, `semanage fcontext`) and some integrations need32booleans. Mail logs are in `/var/log/maillog` (cross-ref `linux-log-management`).33Deep SELinux coverage is in `linux-server-hardening` / Phase 2.3435In `sk-*` scripts use the `common.sh` primitives (`pkg_install`, `ensure_epel`,36`svc_name`) instead of hardcoding the family. See37[`linux-bash-scripting`](../../10-automation-and-scripting/linux-bash-scripting/SKILL.md) and38[`docs/multi-distro/plan.md`](../../docs/multi-distro/plan.md).3940<!-- dual-compat-start -->41## Use when4243- Managing Postfix, Exim, Dovecot, queue behavior, or SMTP testing.44- Debugging delivery failures, spam-folder placement, or TLS/authentication issues.45- Updating SPF, DKIM, or DMARC-related server-side behavior.4647## Do not use when4849- The task is general DNS hosting unrelated to mail service; use `linux-dns-server`.50- The task is generic network reachability without a mail-specific angle; use `linux-network-admin`.5152## Required inputs5354| Artefact | Source | Required? | If absent |55|---|---|---|---|56| Mail role, software, domain/hostname, and current configuration | Mail host and service owner | required | Return discovery commands; do not edit a guessed topology. |57| Symptom, timestamps, queue IDs, sender/recipient domain, and relevant redacted logs | Incident report and host | required for diagnosis | Mark the affected transport stage `not assessed`. |58| DNS/TLS/relay ownership and approved test recipient | Domain and service owners | required for change/test | Stop before publishing records or sending mail. |5960## Workflow61621. Identify whether the issue is configuration, queueing, transport, or authentication.632. Inspect current config, queue state, and relevant logs.643. Apply the matching workflow below for reputation, submission, queue, or domain changes.654. Re-test SMTP flow and authentication to confirm the result.665. Stop if relay scope, DNS/TLS ownership, queue impact, test-recipient authority, or rollback is unresolved.676. Recover by restoring the prior validated config/records, reloading the service, and retesting a controlled message before resuming the queue.6869## Quality standards7071- Verify with real SMTP tests and queue inspection, not assumption.72- Keep authentication records and mail config aligned.73- Separate transport problems from reputation and policy problems.7475## Anti-patterns7677- Treating spam placement as only connectivity. Fix: inspect SPF, DKIM, DMARC, reverse DNS, TLS, reputation, and message evidence separately.78- Flushing/deleting a queue before diagnosis. Fix: sample queue IDs, reasons, age, destination patterns, and logs first.79- Enabling an open relay or broad trusted network. Fix: restrict relay to authenticated/explicit clients and test rejection externally.80- Publishing mail-authentication records without alignment tests. Fix: validate selectors, policy, envelope/header domains, and authoritative DNS.81- Logging or sharing message bodies/credentials unnecessarily. Fix: use queue IDs, headers, and redacted protocol traces.8283## Outputs8485| Artefact | Consumer | Acceptance condition |86|---|---|---|87| Mail-path diagnosis or configuration change | Mail operator | Locates failure at submission, queue, DNS, transport, policy, mailbox, or reputation layer with evidence. |88| Authentication/TLS evidence | Domain owner | SPF/DKIM/DMARC alignment and certificate/hostname checks are observed, or explicitly unassessed. |89| Delivery verification | Service owner | Approved test mail receives expected SMTP codes and reaches the intended mailbox without creating an open relay. |9091## References9293- [`references/postfix-reference.md`](references/postfix-reference.md)94- [`references/email-authentication.md`](references/email-authentication.md)95- [`references/debugging-delivery.md`](references/debugging-delivery.md)9697## Evidence Produced9899| Artefact | Acceptance condition |100|---|---|101| Mail-operation evidence | Includes redacted config, queue samples, log timeline, SMTP transcript, DNS/authentication/TLS results, authorised headers, and rollback. |102103## Capability contract104105Diagnosis defaults to read-only. Mail configuration, queue mutation, DNS publication, certificate changes, service reloads, or sending external test mail require explicit authority. Never expose mailbox credentials, private keys, or message content beyond approved evidence.106107## Degraded mode108109Without host, DNS, or recipient access, assess only available layers and label the rest `not assessed`. A successful TCP connection is not a delivery or reputation pass.110111## Decision rules112113| Choice | Action | Failure or risk avoided |114|---|---|---|115| Queue deferral cluster | Inspect enhanced status/log cause before retry | Amplifying a persistent failure. |116| Authentication passes but spam persists | Examine reputation/content/provider feedback | Rewriting healthy transport config. |117| Submission auth failure | Test SASL/TLS listener and policy | Weakening relay controls. |118119## Worked example120121For a growing Postfix queue to one provider, sample deferred queue IDs, correlate enhanced status codes and logs, verify DNS/TLS/authentication, correct the evidenced cause, reload only after config validation, retry a small sample, and record delivery before releasing the remainder.122123<!-- dual-compat-end -->124125**This skill is self-contained.** Every command below is a standard mail126tool (`postfix`, `postqueue`, `postconf`, `swaks`, `openssl`, `dig`) present on127both Debian/Ubuntu and the RHEL family; body examples use Debian/Ubuntu128syntax, with RHEL-family differences in the **Distro support** matrix above.129The `sk-*` scripts in the **Optional fast path** section130are convenience wrappers — never required.131132This skill covers running and debugging mail on a Debian/Ubuntu or RHEL-family server:133Postfix (default), Exim (alternative), Dovecot for IMAP, and the three134pillars of email authentication — SPF, DKIM, DMARC.135136It does **not** own:137138- **Firewall rules for SMTP ports** — `linux-firewall-ssl`.139- **DNS records themselves** (MX, SPF, DKIM, DMARC live at the DNS host) —140 but this skill *validates* them.141- **Mail clients** — out of scope.142143Informed by *Linux Network Administrator's Guide* (Sendmail/Exim chapters,144translated to Postfix) and modern email authentication practice.145146---147148## When to use149150- Setting up a server to send mail (transactional, notifications, relay).151- Diagnosing "my email goes to spam."152- Checking a mail queue for stuck messages.153- Testing SMTP from the command line (EHLO, STARTTLS, auth, RCPT).154- Validating SPF, DKIM, DMARC records for a domain.155- Inspecting a remote MX's reachability and TLS.156157## When NOT to use158159- Setting up cloud email (SES, SendGrid, Postmark) — those are API-based.160- Managing DNS records at a registrar — use the registrar's UI or API.161162---163164## Standing rules1651661. **Never run a mail server without SPF + DKIM + DMARC.** Unauthenticated167 mail is treated as spam by every modern receiver.1682. **Never relay mail for third parties without authentication.** Open169 relays are abuse vectors. `mynetworks` in `main.cf` must be170 `127.0.0.0/8` only by default.1713. **Always enable TLS for submission (port 587).** STARTTLS only, reject172 plain auth.1734. **Always validate config before reload.** `postfix check` for Postfix,174 `exim -bV` for Exim.1755. **The queue is the first thing to check on delivery problems.**1766. **Log everything to `/var/log/mail.log`** (syslog) *and*177 `journalctl -u postfix` — both exist on modern Ubuntu.1787. **Reverse DNS (PTR) of the sending IP must match the HELO name.**179 Mismatched PTR is the single biggest reason mail is flagged as spam.180181---182183## Quick reference — manual commands184185### Postfix config and status186187```bash188# Validate config — always run before reload189sudo postfix check190191# Show effective config (difference from default)192postconf -n193194# Reload195sudo postfix reload196197# Or full restart if service behavior is stuck:198sudo systemctl restart postfix199200# Service status201sudo systemctl status postfix --no-pager202sudo journalctl -u postfix -n 50 --no-pager203sudo tail -f /var/log/mail.log204```205206### Queue inspection207208```bash209# Show queue210sudo postqueue -p211sudo mailq # alias212213# Count by status214sudo postqueue -p | grep -c '^[A-F0-9]'215216# Inspect a specific message217sudo postcat -q <queue-id>218219# Force a flush (try delivery now)220sudo postqueue -f221222# Delete a specific stuck message223sudo postsuper -d <queue-id>224225# Delete everything (use with extreme care)226sudo postsuper -d ALL227```228229### SMTP testing from the command line230231```bash232# Install swaks if needed233sudo apt install swaks234235# Full SMTP conversation with TLS and auth236swaks --server mail.example.com \237 --port 587 \238 --from sender@example.com \239 --to recipient@example.org \240 --auth LOGIN \241 --auth-user sender@example.com \242 --tls \243 --header "Subject: test $(date)" \244 --body "test body"245246# Just the handshake (no auth, no send)247swaks --server mail.example.com --port 587 --quit-after STARTTLS248249# With openssl (lower level):250openssl s_client -starttls smtp -connect mail.example.com:587 -crlf251# Type: EHLO test.example.com252# Then: QUIT253```254255### Email authentication checks256257```bash258# SPF lookup259dig +short TXT example.com | grep spf1260261# DKIM selector (replace "default" with your actual selector)262dig +short TXT default._domainkey.example.com263264# DMARC265dig +short TXT _dmarc.example.com266267# MX record with priorities268dig +short MX example.com269270# Reverse DNS (PTR) — must match HELO271dig +short -x $(curl -s https://api.ipify.org)272273# Online checkers (for humans, but record the dig output yourself first):274# - https://mxtoolbox.com275# - Gmail Postmaster Tools276```277278Full email-auth deep dive (record syntax, DKIM key generation via279`opendkim-genkey`, DMARC reporting, example DNS zone snippet) — see280[`references/email-authentication.md`](references/email-authentication.md).281282---283284## Typical workflows285286### Workflow: "Our emails are going to spam"287288Walk [`references/debugging-delivery.md`](references/debugging-delivery.md).289Condensed:290291```bash292# 1. Queue health293sudo postqueue -p294295# 2. Reject reason on a deferred message296sudo postcat -q <queue-id> | tail -20297298# 3. SPF / DKIM / DMARC present?299dig +short TXT example.com | grep spf1300dig +short TXT default._domainkey.example.com301dig +short TXT _dmarc.example.com302303# 4. PTR matches HELO?304dig +short -x $(postconf -h inet_interfaces | awk '{print $1}')305postconf -h myhostname306307# 5. TLS working for submission?308swaks --server mail.example.com --port 587 --quit-after STARTTLS309```310311### Workflow: "Is port 587 submission working?"312313```bash314swaks --server mail.example.com \315 --port 587 \316 --auth LOGIN \317 --auth-user bot@example.com \318 --tls319```320321Reports each step (connection, STARTTLS, AUTH, MAIL FROM, RCPT TO, DATA).322323### Workflow: "The queue is growing"324325```bash326# 1. How bad?327sudo postqueue -p | tail -5 # last line says "Total requests"328329# 2. What's stuck and why?330sudo postqueue -p | head -30331332# 3. Pick a message and see the specific rejection:333sudo postcat -q <queue-id>334335# 4. Common fixes:336# - Greylist: just wait; Postfix will retry automatically337# - TLS handshake error: check recipient server's cert, your own338# - Auth required: fix relay credentials339# - Relay denied: check mynetworks, smtpd_recipient_restrictions340```341342### Workflow: "Add a new domain to an existing Postfix"343344```bash345# 1. Edit main.cf — add to mydestination or virtual_mailbox_domains346sudo nano /etc/postfix/main.cf347348# 2. If using virtual mailboxes, update the virtual maps:349sudo nano /etc/postfix/virtual_alias_maps350sudo postmap /etc/postfix/virtual_alias_maps351352# 3. Validate353sudo postfix check354355# 4. Reload356sudo postfix reload357358# 5. Test with swaks359```360361---362363## Troubleshooting / gotchas364365- **PTR record mismatch is the #1 spam trigger.** If your server's IP366 reverse-resolves to `vps-12345.provider.net` but Postfix HELOs as367 `mail.example.com`, receivers downgrade you immediately. Fix the PTR368 at the VPS provider.369- **`postfix reload` doesn't reload everything.** Changes to `master.cf`370 require `sudo systemctl restart postfix`. `postfix reload` only371 re-reads `main.cf`.372- **TLS fails on port 465 but works on 587.** Port 465 is implicit TLS373 (SMTPS), 587 is STARTTLS. They need separate service stanzas in374 `master.cf` — enable both.375- **DKIM signs but receivers fail DMARC.** Check alignment: the signing376 domain (`d=`) must match the `From:` header domain (relaxed alignment)377 or exactly (strict). A DKIM-signed bounce that uses the mail server's378 hostname as `d=` won't align with the sender's domain.379- **Postfix is silently deferring.** Look in `/var/log/mail.log` — the380 rejection reason is there. The queue only shows the summary.381- **Dovecot and Postfix disagree about a user.** Postfix's382 `virtual_mailbox_maps` must match Dovecot's `passdb` / `userdb`. Use383 a single source of truth (MySQL, LDAP, or a flat file) and point both384 at it.385386---387388## References389390- [`references/postfix-reference.md`](references/postfix-reference.md) —391 full Postfix reference: `main.cf` parameters, `master.cf`, queue392 management, 3 complete config examples.393- [`references/email-authentication.md`](references/email-authentication.md) —394 SPF, DKIM (with opendkim), DMARC deep dive with DNS record examples.395- [`references/debugging-delivery.md`](references/debugging-delivery.md) —396 decision tree for delivery problems.397- Book: *Linux Network Administrator's Guide* (Kirch & Dawson) — mail398 chapters (Sendmail/Exim, translated to Postfix).399- Book: *Ubuntu Server Guide* (Canonical) — Postfix and Dovecot.400- Man pages: `postfix(1)`, `postconf(5)`, `master(5)`, `postqueue(1)`,401 `postcat(1)`, `swaks(1)`.402403---404405## Optional fast path (when sk-* scripts are installed)406407Running `sudo install-skills-bin linux-mail-server` installs:408409| Task | Fast-path script |410|---|---|411| MX records for domain + reachability + TLS + PTR match | `sudo sk-mx-check --domain <d>` |412| Audit SPF, DKIM, DMARC records for a domain | `sudo sk-spf-dkim-dmarc --domain <d>` |413| Postfix/Exim queue inspection grouped by recipient | `sudo sk-mail-queue` |414| Full SMTP conversation tester (wraps swaks) | `sudo sk-smtp-test --host <h> --port 587 --tls` |415416These are optional wrappers around `dig`, `swaks`, `postqueue`, and417`openssl s_client`.418419## Scripts420421This skill installs the following scripts to `/usr/local/bin/`. To install:422423```bash424sudo install-skills-bin linux-mail-server425```426427| Script | Source | Core? | Purpose |428|---|---|---|---|429| sk-mx-check | scripts/sk-mx-check.sh | no | MX records for a domain, preference order, reachability, reverse DNS, TLS cert of each MX. |430| sk-spf-dkim-dmarc | scripts/sk-spf-dkim-dmarc.sh | no | Audit SPF, DKIM, and DMARC records for a domain; report missing or misaligned. |431| sk-mail-queue | scripts/sk-mail-queue.sh | no | Postfix/Exim queue inspection: depth, oldest, stuck, by recipient domain. |432| sk-smtp-test | scripts/sk-smtp-test.sh | no | Full SMTP handshake tester (EHLO / STARTTLS / AUTH / MAIL FROM / RCPT TO / DATA), reports each step. |