How to Disable Outbound SMTP in Postfix While Allowing Local Mail Delivery


4 views

When configuring Postfix as a local-only mail server, it's crucial to understand how mail routing works. By default, Postfix will attempt to deliver messages to external domains through DNS MX records. Here's the mail flow we want to modify:


local user → Postfix → local delivery (allowed)
local user → Postfix → external SMTP (block)
PHP app → External SMTP (allowed)

Edit your main.cf file with these essential directives:


# Restrict delivery to local domains only
mydestination = localhost, localhost.localdomain
local_recipient_maps = unix:passwd.byname $alias_maps

# Disable relaying completely
default_transport = error
relay_transport = error

# Prevent outbound delivery
smtpd_recipient_restrictions = 
    permit_mynetworks,
    reject_unauth_destination,
    check_recipient_access hash:/etc/postfix/local_recipients,
    reject

Create /etc/postfix/local_recipients with allowed local users:


# Format: address ACTION
user1@localhost OK
user2@localhost OK
@localhost.localdomain OK

Compile the map file:

postmap /etc/postfix/local_recipients

For applications needing external mail delivery, configure PHPMailer to bypass local Postfix:


<?php
use PHPMailer\PHPMailer\PHPMailer;
require 'vendor/autoload.php';

$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->SMTPAuth = true;
$mail->Username = 'your_external_account@example.com';
$mail->Password = 'yourpassword';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
// ... rest of your email code

Test your setup with these commands:


# Test local delivery (should work)
echo "Test" | mail -s "Local test" user1@localhost

# Test external delivery (should fail)
echo "Test" | mail -s "External test" someone@gmail.com

# Check mail logs
tail -f /var/log/mail.log

If you encounter problems, check these areas:

  • Verify mydestination includes all local domains
  • Ensure local_recipient_maps points to valid maps
  • Check for cached Postfix maps (run postfix reload)
  • Inspect mail headers for routing information

When setting up a local development environment or internal mail server, you often need Postfix to handle local mail delivery while preventing accidental outbound SMTP traffic. This configuration serves two key purposes:

  1. Preventing your server from being used as an open relay
  2. Allowing applications to still send mail via authenticated external SMTP

Edit your main Postfix configuration file (typically /etc/postfix/main.cf) with these critical directives:

# Only accept connections from localhost
inet_interfaces = loopback-only

# Reject mail to non-local domains
mydestination = $myhostname, localhost.$mydomain, localhost

# Explicitly disable relaying
default_transport = error
relay_transport = error

# Important for local delivery only
mynetworks = 127.0.0.0/8 [::1]/128

Create a transport map to block all external delivery attempts:

# Create /etc/postfix/transport with:
*   error:No outbound mail allowed from this server

# Then compile and activate:
sudo postmap /etc/postfix/transport

Add to main.cf:

transport_maps = hash:/etc/postfix/transport

Here's how to configure PHPMailer to bypass the local restriction:

use PHPMailer\PHPMailer\PHPMailer;
require 'vendor/autoload.php';

$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = 'your@gmail.com';
$mail->Password = 'yourpassword';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;

$mail->setFrom('local@dev.example', 'Local Dev');
$mail->addAddress('external@example.com');
$mail->Subject = 'Test via External SMTP';
$mail->Body = 'This bypasses local Postfix restrictions';

$mail->send();

Verify your setup with these commands:

# Test local delivery
echo "Test body" | mail -s "Local test" someuser@localhost

# Attempt external delivery (should fail)
echo "Test body" | mail -s "External test" someone@gmail.com

# Check mail logs
tail -f /var/log/mail.log

Additional hardening measures:

  • Set smtpd_relay_restrictions = permit_mynetworks,reject
  • Consider enabling SMTP AUTH for local submissions
  • Regularly audit your mail queue (mailq)

If you encounter problems:

# Reload Postfix after changes
sudo systemctl reload postfix

# Check configuration
sudo postfix check

# Test SMTP connectivity
telnet localhost 25