Software & Configuration

Postfix SMTP Relay

Configure Postfix as an SMTP relay on Linux to send emails from scripts and applications via external providers (Mailgun, SendGrid, Gmail)

An SMTP relay forwards emails through an external provider instead of managing a full mail server. This guide covers configuring Postfix to relay through Mailgun, SendGrid, or Gmail.


When to Use SMTP Relay

Use SMTP relay when:

  • You need to send transactional emails from applications
  • You don't want to manage a full mail server (Mailcow, Postfix + Dovecot)
  • You use managed providers with SMTP API support
  • You want reputation management through a dedicated email service

SMTP relay is lightweight, scalable, and handled by professional email providers.


Installation

Ubuntu / Debian

apt update
apt install postfix -y

During installation, select "Internet Site" or "Satellite system". If you miss this, reconfigure:

dpkg-reconfigure postfix

Choose "Satellite system" to relay through an external provider.

CentOS / AlmaLinux

dnf install postfix -y
systemctl start postfix
systemctl enable postfix

Mailgun Relay Configuration

/etc/postfix/main.cf

Edit or add these settings:

# Relay through Mailgun
relayhost = [smtp.mailgun.org]:587

# SASL authentication
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_tls_security_level = encrypt
smtp_tls_note_cipher_log = yes

# Default sender domain
myorigin = /etc/mailname
# or specify directly:
# myorigin = example.com

# Bind only to localhost for local relay
inet_interfaces = loopback-only

Credentials File

Create /etc/postfix/sasl_passwd:

[smtp.mailgun.org]:587 postmaster@example.mailgun.org:your-api-key

Secure the file:

chmod 600 /etc/postfix/sasl_passwd

Hash the password file:

postmap /etc/postfix/sasl_passwd

Verify the hashed file is created:

ls -la /etc/postfix/sasl_passwd*

Reload Postfix:

systemctl reload postfix

SendGrid Relay Configuration

/etc/postfix/main.cf

Replace the relayhost with SendGrid:

relayhost = [smtp.sendgrid.net]:587

smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_tls_security_level = encrypt

inet_interfaces = loopback-only
myorigin = example.com

/etc/postfix/sasl_passwd

[smtp.sendgrid.net]:587 apiuser:SG.your-api-key-here

Process:

chmod 600 /etc/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd
systemctl reload postfix

Gmail Relay Configuration

Gmail requires an App Password (not your regular password).

  1. Enable 2-factor authentication on your Google account
  2. Generate an App Password at https://myaccount.google.com/apppasswords
  3. Select "Mail" and "Linux"
  4. Copy the generated password

/etc/postfix/main.cf

relayhost = [smtp.gmail.com]:587

smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_tls_security_level = encrypt

inet_interfaces = loopback-only
myorigin = example.com

/etc/postfix/sasl_passwd

[smtp.gmail.com]:587 your-email@gmail.com:your-app-password

Process:

chmod 600 /etc/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd
systemctl reload postfix

Testing

Basic Email Test

echo "Test message body" | mail -s "Test Subject" recipient@example.com

Using sendmail Command

(
  echo "From: sender@example.com"
  echo "To: recipient@example.com"
  echo "Subject: Test Email"
  echo ""
  echo "This is a test email."
) | sendmail recipient@example.com

Using telnet (Manual SMTP)

telnet localhost 25

At the prompt:

EHLO localhost
MAIL FROM: <sender@example.com>
RCPT TO: <recipient@example.com>
DATA
Subject: Test
Test email body.
.
QUIT

Email Aliases

Set up aliases for root and other system users in /etc/aliases:

root: admin@example.com
www-data: admin@example.com
ubuntu: admin@example.com

Rebuild aliases:

newaliases

Now cron jobs and system emails will forward to your email address.


Monitoring and Logs

Mail Queue Status

Check pending emails:

mailq

Or:

postqueue -p

View Logs

Real-time logs:

tail -f /var/log/mail.log

Recent activity:

grep "from=<sender" /var/log/mail.log | tail -20

Bounce Messages

Check for failed delivery:

grep "delivery failed" /var/log/mail.log
grep "Returned mail" /var/log/mail.log

Postfix Control Commands

# Reload configuration without stopping
systemctl reload postfix

# Restart Postfix
systemctl restart postfix

# Check status
systemctl status postfix

# View configuration
postconf | grep relayhost
postconf | grep smtp_sasl

# Force queue processing
postqueue -f

# Delete a queued message (get ID from mailq)
postsuper -d ID

# Test DNS/MX records
dig example.com MX

Configuration Verification

Verify your configuration is correct:

postconf relayhost smtp_sasl_auth_enable smtp_tls_security_level inet_interfaces

Should output something like:

relayhost = [smtp.sendgrid.net]:587
smtp_sasl_auth_enable = yes
smtp_tls_security_level = encrypt
inet_interfaces = loopback-only

Never expose Postfix to the internet without authentication. An open relay allows spammers to use your server. Always:

  • Set inet_interfaces = loopback-only to accept only local connections
  • Enable smtp_sasl_auth_enable = yes with proper credentials
  • Use TLS encryption (smtp_tls_security_level = encrypt)
  • Keep sasl_passwd permissions restricted (600)

Troubleshooting

Connection Refused

Verify Postfix is running:

systemctl status postfix
netstat -tlnp | grep postfix

Authentication Failed

Check credentials in /etc/postfix/sasl_passwd:

postmap -q [smtp.sendgrid.net]:587 /etc/postfix/sasl_passwd

Should return the username:password.

TLS Certificate Issues

If TLS fails, check provider's certificate:

openssl s_client -connect smtp.sendgrid.net:587 -starttls smtp

Emails Not Sent

Check the queue:

mailq
tail -f /var/log/mail.log

Remove stuck messages:

postsuper -d ALL
postqueue -f

Common Patterns

Send Email from Application

From PHP:

$to = 'user@example.com';
$subject = 'Test';
$message = 'Hello';
mail($to, $subject, $message);

From Python:

import smtplib
from email.mime.text import MIMEText

msg = MIMEText('Message body')
msg['Subject'] = 'Subject'
msg['From'] = 'sender@example.com'
msg['To'] = 'recipient@example.com'

s = smtplib.SMTP('localhost', 25)
s.send_message(msg)
s.quit()

From Node.js:

const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: 'localhost',
  port: 25,
  secure: false
});

transporter.sendMail({
  from: 'sender@example.com',
  to: 'recipient@example.com',
  subject: 'Test',
  text: 'Message body'
});

All applications connect to localhost:25 without authentication.

On this page