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:
- Preventing your server from being used as an open relay
- 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