How to Configure Postfix to Relay External Domain Mail Instead of Local Delivery


4 views

When using PHP's mail() function with Postfix, you might encounter a situation where emails destined for domains hosted on your server (but externally handled) get rejected because Postfix attempts local delivery. Here's how to properly configure Postfix to relay these messages externally.

By default, Postfix treats domains listed in mydestination as local domains. For a domain like example.com where:

1. The domain is registered on your server
2. MX records point to external mail servers
3. You want to send mail to addresses@example.com

Postfix will attempt local delivery unless specifically configured otherwise.

Method 1: Disable Local Mail Service (Plesk Specific)

For Plesk servers, the cleanest solution is:

/usr/local/psa/bin/domain --update example.com -mail_service false

This tells Plesk to stop treating the domain as locally hosted for mail purposes.

Method 2: Postfix Configuration Adjustments

For non-Plesk servers or more control:

# Edit main.cf
sudo nano /etc/postfix/main.cf

# Remove domain from mydestination
mydestination = localhost, localhost.localdomain

# Add transport mapping
transport_maps = hash:/etc/postfix/transport

# Create/update transport file
sudo nano /etc/postfix/transport
example.com smtp:[external.mail.server]

Then compile and reload:

sudo postmap /etc/postfix/transport
sudo systemctl reload postfix

Verify with:

echo "Test email" | mail -s "Postfix Relay Test" user@example.com
tail -f /var/log/mail.log

You should see Postfix attempting to relay rather than deliver locally.

Your PHP code doesn't need modification, but ensure proper headers:

$to = 'user@example.com';
$subject = 'Test Email';
$message = 'This should relay externally';
$headers = 'From: webmaster@yourserver.com' . "\r\n" .
    'Reply-To: no-reply@yourserver.com' . "\r\n" .
    'X-Mailer: PHP/' . phpversion();

mail($to, $subject, $message, $headers);
  • Forgetting to postmap after transport file changes
  • DNS caching - changes might take time to propagate
  • Firewall blocking outbound SMTP (port 25)

Recently, I encountered an interesting mail routing issue where PHP's mail() function was failing to deliver messages to external domains properly. The specific case involved:

  • A PHP form sending to a domain registered on my server
  • Mail handling actually configured on a different mail server
  • Postfix attempting local delivery first
  • Message rejection when local delivery failed

By default, Postfix handles mail delivery in this order:

1. Check local domains (mydestination)
2. Check virtual alias domains
3. Check virtual mailbox domains
4. Relay to SMTP if none of above match

The key is to configure Postfix to recognize that this particular domain should be treated as external. Here are two methods:

Method 1: Disable Mail Service for the Domain

For Plesk systems (as in the original case):

/usr/local/psa/bin/domain --update example.com -mail_service false

This tells the control panel to exclude the domain from local mail handling.

Method 2: Postfix Configuration Adjustments

For direct Postfix configuration:

  1. Edit /etc/postfix/main.cf
  2. Modify the mydestination parameter
# Remove the problematic domain from mydestination
mydestination = $myhostname, localhost.$mydomain, localhost

# Alternatively, use relay_domains for more control
relay_domains = hash:/etc/postfix/relay_domains

Then create /etc/postfix/relay_domains:

example.com RELAY

When using PHP's mail function, ensure proper headers:

$to = 'user@external-domain.com';
$subject = 'Test Subject';
$message = 'Test message body';
$headers = 'From: webmaster@yourdomain.com' . "\r\n" .
    'Reply-To: webmaster@yourdomain.com' . "\r\n" .
    'X-Mailer: PHP/' . phpversion();

mail($to, $subject, $message, $headers);

After making changes, always:

sudo postfix reload
sudo tail -f /var/log/mail.log

Send a test message and verify it's being relayed externally rather than attempting local delivery.

For more control, consider bypassing Postfix's local delivery entirely and using SMTP directly from PHP:

$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'your.smtp.server';
$mail->SMTPAuth = true;
$mail->Username = 'username';
$mail->Password = 'password';
$mail->Port = 587;

$mail->setFrom('from@example.com');
$mail->addAddress('to@external.com');
$mail->Subject = 'Subject';
$mail->Body = 'Message body';

$mail->send();