Postfix has shipped 12 security advisories since 2020 (source). Each one needs a patch, a daemon restart, and a smoke test to confirm mail still flows. Twelve interruptions to ship, for a sub-system that exists to do one thing: hand a string to a smarter mail provider 50ms later.
If your only outbound need is "send a templated email from a script", you do not need an SMTP daemon. You need a function call.
What an "SMTP server" actually does in 2026
For most workloads, the local Postfix instance:
- Accepts mail from
sendmail -tormail - Queues it
- Hands it to a smart relay (SES, SendGrid, Mailgun, or your provider of choice)
- Logs the result
Steps 1, 2, 4 are infrastructure. Step 3 is the work. Removing 1, 2, 4 means you trade five files in /etc/postfix and a queue daemon for a single command:
nylas email send \
--to ops@yourcompany.com \
--subject "Build #4129 failed" \
--body "See https://ci.example.com/4129 for details."
That is it. No main.cf, no SASL, no relayhost tuning. The CLI handles the relay handshake.
The five things you stop maintaining
Switching off the local Postfix kills five operational concerns:
| Concern | Effort to keep healthy |
|---|---|
| MX or relay config | One file, frequent edits |
| SASL credentials in postmap | Rotated quarterly, manually |
| TLS certificates for outbound | Renewal scripts |
| Queue runner | OOM kills, mqueue corruption |
| Patch cycle | 12 CVEs in 5 years |
Every one of those is non-revenue work.
Real workloads, real one-liners
Build alerts from CI
# In .github/workflows/notify.yml
- run: |
nylas email send \
--to oncall@yourcompany.com \
--subject "🚨 main is red" \
--body "Run: ${{ github.run_id }}\nCommit: ${{ github.sha }}"
No "install Postfix on your runner" step. brew install nylas/nylas-cli/nylas (or curl install.sh | bash on Linux) is the entire prerequisite.
Cron job reports
# /etc/cron.daily/db-backup
#!/usr/bin/env bash
if pg_dump --quiet ourdb | gzip > /backups/$(date +%F).sql.gz; then
nylas email send --to ops@yourcompany.com \
--subject "DB backup OK" \
--body "$(date): backup complete. Size: $(du -h /backups/$(date +%F).sql.gz)"
else
nylas email send --to oncall@yourcompany.com \
--subject "🔴 DB backup FAILED" \
--body "Check /var/log/db-backup.log on $(hostname)"
fi
Application errors
import subprocess
try:
process_payments()
except CriticalError as e:
subprocess.run([
'nylas', 'email', 'send',
'--to', 'oncall@yourcompany.com',
'--subject', f'Payment processor down: {e.code}',
'--body', str(e)
], check=True)
The Python program does not need an SMTP library. It calls a CLI.
When you actually do need Postfix
Three cases:
-
Inbound mail to a custom domain — though even this is now better solved with a managed agent account:
nylas agent account create support@yourapp.nylas.email, then poll withnylas email listor webhook withnylas webhook create --triggers message.created. - Air-gapped networks with no outbound HTTPS — Postfix to a DMZ relay still wins.
- Compliance regimes that forbid third-party mail relays — a niche, but real.
If you are not in one of those three categories, the Postfix install is technical debt.
The mental model shift
Treat outbound mail like you treat outbound HTTP: a function call to a managed service. Your script does not run apache2 to make an HTTP request. It calls curl or a library. Same logic for mail. nylas email send is the curl of email.
Migration in five minutes
# 1. Install
brew install nylas/nylas-cli/nylas
# or: curl -fsSL https://cli.nylas.com/install.sh | bash
# 2. Auth (paste your API key)
nylas auth config --api-key YOUR_KEY
# 3. Send a test
nylas email send --to you@example.com --subject "test" --body "hi from the new world"
# 4. Replace every "sendmail -t" call with "nylas email send"
grep -r 'sendmail\|mailx' /etc /home /opt /var/scripts | wc -l
# That number is your migration scope.
# 5. systemctl disable postfix && systemctl stop postfix
The last command will feel like cheating.
Next steps
- Send email from the terminal — full reference for outbound CLI mail
- Best CLI email tools compared — mutt, mailx, msmtp head-to-head
- Receive email without an SMTP server — the inbound counterpart
- Full command reference
Top comments (0)