Postfix as a Null Client: Send-Only Mail Done Right
Introduction¶
Most servers don't need a full mail server — they need to send: cron output, monitoring alerts, "your export is ready" notifications. A null client is Postfix configured to relay everything through an authenticated smarthost (your provider, Gmail, SES, a company relay) and accept nothing. It's a handful of lines and it's the right amount of mail server for the job.
Concepts¶
A null client:
- Listens only on
127.0.0.1(or not at all as a network service). - Forwards all mail to a relayhost — it never does its own MX lookups or direct delivery.
- Authenticates to the relay with SASL over TLS.
- Rewrites the envelope/header From so
[email protected]becomes something the relay and recipients will accept.
Hands-on¶
Install and pick "Internet Site" or "No configuration" — you'll overwrite it.
/etc/postfix/main.cf¶
# Identity
myhostname = web01.example.com
myorigin = example.com
mydestination = # empty: accept mail for NO domain
inet_interfaces = loopback-only
inet_protocols = ipv4
# Relay everything through the smarthost
relayhost = [smtp.example-relay.com]:587
# SASL auth to the relay
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_mechanism_filter = plain, login
# TLS to the relay (required)
smtp_tls_security_level = encrypt
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtp_tls_loglevel = 1
# Rewrite sender addresses
sender_canonical_maps = regexp:/etc/postfix/sender_canonical
smtp_header_checks = regexp:/etc/postfix/header_checks
# Don't relay for anyone else
smtpd_relay_restrictions = permit_mynetworks, reject
Credentials — /etc/postfix/sasl_passwd¶
[smtp.example-relay.com]:587 apikey:s3cr3t-token
sudo postmap /etc/postfix/sasl_passwd
sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
Rewrite the From address¶
/etc/postfix/sender_canonical — turn every local sender into one address:
/.+/ [email protected]
/etc/postfix/header_checks — fix the visible From: header too:
/^From:.*/ REPLACE From: server alerts <[email protected]>
Apply¶
sudo systemctl restart postfix
Verification and troubleshooting¶
echo "test body" | mail -s "null client test" [email protected]
sudo tail -f /var/log/mail.log # watch the relay handshake
mailq # anything stuck?
sudo postqueue -f # flush the queue now
A healthy send in the log ends with status=sent (250 2.0.0 OK ...).
status=bounced ... Relay access denied— you're hitting the relay without auth, or SASL failed. Checksasl_passwdmaps the exactrelayhoststring (brackets and port included), andpostmapwas run.SASL authentication failed; server ... said: 535— wrong username/token, or the relay wantsLOGINnotPLAIN(smtp_sasl_mechanism_filter), or the token has expired.Cannot start TLS: handshake failure—smtp_tls_CAfilepath wrong, or the relay needssmtp_tls_security_level = mayon an internal relay with a self-signed cert (preferencrypt+ a proper CA).- Mail sent but lands in spam — the relay isn't authorised in your domain's
SPF, or the
From:you rewrote to isn't DKIM-signed by the relay. See SPF, DKIM, DMARC end to end. status=deferred ... Connection timed out— outbound 587 (or 465) blocked by a firewall/cloud security group. Many providers block 25; use 587.- Postfix accepting inbound connections —
inet_interfacesisn'tloopback-only, ormydestinationisn't empty.sudo ss -tlnp | grep :25should show127.0.0.1only. - App mail works,
cronmail doesn't — cron sends toroot@localhost; make suresender_canonicalcatches it and/etc/aliasesroutesrootsomewhere (newaliasesafter editing).
Related tools and reading¶
- On-site: SMTP Connection Tester, SPF Checker, Deliverability Test.
- Related posts: SPF, DKIM, DMARC end to end, Let's Encrypt with certbot and renewal.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Web & Mail Servers
Running BIND 9 as an Authoritative Server
BIND as an authoritative server: zone files, secured AXFR with TSIG, SOA serial rules, and DNSSEC inline-signing. Here's a working master/slave setup.
October 24, 2026Varnish Cache in Front of a Site
Varnish is a caching HTTP accelerator configured in VCL. Here's the request lifecycle, why you strip cookies, how bans work, and grace mode for serving stale during backend trouble.
October 24, 2026Let's Encrypt with Certbot, Including Renewal That Doesn't Break
Getting the first cert is easy; keeping renewal working for years is the part people get wrong. Webroot vs DNS-01, deploy hooks, and the failure modes.
October 24, 2026