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 -yDuring installation, select "Internet Site" or "Satellite system". If you miss this, reconfigure:
dpkg-reconfigure postfixChoose "Satellite system" to relay through an external provider.
CentOS / AlmaLinux
dnf install postfix -y
systemctl start postfix
systemctl enable postfixMailgun 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-onlyCredentials File
Create /etc/postfix/sasl_passwd:
[smtp.mailgun.org]:587 postmaster@example.mailgun.org:your-api-keySecure the file:
chmod 600 /etc/postfix/sasl_passwdHash the password file:
postmap /etc/postfix/sasl_passwdVerify the hashed file is created:
ls -la /etc/postfix/sasl_passwd*Reload Postfix:
systemctl reload postfixSendGrid 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-hereProcess:
chmod 600 /etc/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd
systemctl reload postfixGmail Relay Configuration
Gmail requires an App Password (not your regular password).
- Enable 2-factor authentication on your Google account
- Generate an App Password at https://myaccount.google.com/apppasswords
- Select "Mail" and "Linux"
- 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-passwordProcess:
chmod 600 /etc/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd
systemctl reload postfixTesting
Basic Email Test
echo "Test message body" | mail -s "Test Subject" recipient@example.comUsing 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.comUsing telnet (Manual SMTP)
telnet localhost 25At the prompt:
EHLO localhost
MAIL FROM: <sender@example.com>
RCPT TO: <recipient@example.com>
DATA
Subject: Test
Test email body.
.
QUITEmail 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.comRebuild aliases:
newaliasesNow cron jobs and system emails will forward to your email address.
Monitoring and Logs
Mail Queue Status
Check pending emails:
mailqOr:
postqueue -pView Logs
Real-time logs:
tail -f /var/log/mail.logRecent activity:
grep "from=<sender" /var/log/mail.log | tail -20Bounce Messages
Check for failed delivery:
grep "delivery failed" /var/log/mail.log
grep "Returned mail" /var/log/mail.logPostfix 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 MXConfiguration Verification
Verify your configuration is correct:
postconf relayhost smtp_sasl_auth_enable smtp_tls_security_level inet_interfacesShould output something like:
relayhost = [smtp.sendgrid.net]:587
smtp_sasl_auth_enable = yes
smtp_tls_security_level = encrypt
inet_interfaces = loopback-onlyNever expose Postfix to the internet without authentication. An open relay allows spammers to use your server. Always:
- Set
inet_interfaces = loopback-onlyto accept only local connections - Enable
smtp_sasl_auth_enable = yeswith 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 postfixAuthentication Failed
Check credentials in /etc/postfix/sasl_passwd:
postmap -q [smtp.sendgrid.net]:587 /etc/postfix/sasl_passwdShould return the username:password.
TLS Certificate Issues
If TLS fails, check provider's certificate:
openssl s_client -connect smtp.sendgrid.net:587 -starttls smtpEmails Not Sent
Check the queue:
mailq
tail -f /var/log/mail.logRemove stuck messages:
postsuper -d ALL
postqueue -fCommon 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.