10 Mar 2011, 06:37

Postfix: partial relaying to Exchange


Recently I’ve tried to migrate an Exim4 mailserver to Postfix. This was pretty straightforward, however there was one issue that took me some time to figure out.

The exim mailserver handled several domains and one of those had mailboxes as well locally as remote on some remote Exchange mailserver. The exim did accept known mailboxes, performed recipient callout verification to the exchange and if it did accept this recipient the exim did so as well.

The friendly guys at the postfix.user mailing list tried to help with that, but either I did not make my problem clear or I missed some information. Hoever they couldn’t help me with this.

After reading some while in the (german) Postfix Buch, I’ve found a setup that led me to the solution in the end: Define the (partially) local domain as a relay_domain and let the transport map decide if the mail gets relayed to some remote host or a local transport.

That did work out pretty well and this is how I did it.

First I’ve included the domain in question, let’s say ‘domain.tld’ in my relay_domains:

relay_domains = domain.tld

Then I’ve added another transport map, pointing to some SQL file:

transport = mysql:/etc/postfix/virtual_transport_maps.cf

In this file I’ve defined a rather complex SQL query that would return my local transport (dovecot) for known mailboxes and default to the remote Exchange host for unknown mailboxes.

query = SELECT DISTINCT IFNULL((SELECT 'dovecot:' FROM domains AS d LEFT JOIN  mailboxes AS m ON m.domain_id = d.id WHERE d.name = '%d' AND  m.local_part = '%u' AND d.is_active AND  m.is_active),'smtp:[exchange.domain.tld]') FROM domains WHERE  'domain.tld' = '%d' AND NOT LOCATE('+','%u');

Then I’ve added the smtpd_recipient_restriction reject_unverified_recipient. This would reject any recipient which could not be verified at the Exchange server.

It also works with VBoxAdm.

Update: I’ve added the AND NOT LOCATE(‘+’,‘%u’) part at the end of the query to avoid getting false positives if recipient_delimiter=+ is set. You should set the ‘+’ in the query to whatever your recipient delimiter is set to or just drop this part of the where clause if you haven’t set recipient_delimiter.