DEV Community

Cover image for Stop using Postfix for transactional email
Qasim Muhammad
Qasim Muhammad

Posted on

Stop using Postfix for transactional email

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:

  1. Accepts mail from sendmail -t or mail
  2. Queues it
  3. Hands it to a smart relay (SES, SendGrid, Mailgun, or your provider of choice)
  4. 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."
Enter fullscreen mode Exit fullscreen mode

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 }}"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

The Python program does not need an SMTP library. It calls a CLI.

When you actually do need Postfix

Three cases:

  1. 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 with nylas email list or webhook with nylas webhook create --triggers message.created.
  2. Air-gapped networks with no outbound HTTPS — Postfix to a DMZ relay still wins.
  3. 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
Enter fullscreen mode Exit fullscreen mode

The last command will feel like cheating.

Next steps

Top comments (0)