Postfix and Domain Aliases

If you run Postfix, you probably know that it is the best SMTP server on the planet.  I bet it does everything you want plus more, and you know that it has very few shortcomings.  If so, I agree with you.

However, there is one Postfix shortcoming that has been on our radar to solve for quite some time.  Postfix cannot reject unknown users within domains that are an alias for another domain (i.e. domain aliases).  Postfix stubbornly accepts mail for any random email address within a domain alias, and only after it has incorrectly accepted the bogus email, does it bounce it back to the sender.  This is because Postfix’s smtpd address validation occurs prior to address  rewrites, and thus it is only an approximation.  This is a problem because a directory harvest attack on a domain alias can fill up your mail queues with bounces.

Here is how Korey solved this problem last week:

Our Postfix MySQL database structure is very simple.  It contains valid addresses, aliases, domains and domain aliases, mapped to their real address.  Here is a simplified example:

+——————–+——————–+
| email              | virtual            |
+——————–+——————–+
| support@webmail.us | support@webmail.us |
+——————–+——————–+
| @webmailus.com     | @webmail.us        |
+——————–+——————–+

In the past, this would cause our system to accept mail for junk addresses at our domain alias such as "asdf@webmailus.com".  By modifying the virtual_alias_maps query as follows, our system now rejects these invalid addresses as it should.  Maybe one day Postfix will do address rewrites prior to address validation, which would allow us to remove this complex SQL query.  Until then, this hack works great for us.  It may help you too…

/etc/postfix/main.cf:
  virtual_alias_maps =
    proxy:mysql:/etc/postfix/mysql_virtual_gate.cf,

/etc/postfix/mysql_virtual_gate.cf:
  query = select virtual from users where email = ‘%s’
      and left(virtual,1) <> ‘@’
    union
    select virtual from users where email = (
      select concat(left(‘%s’,locate(‘@’,’%s’)-1), virtual) as rewritten
      from users where email = ‘@%d’ and left(virtual,1) = ‘@’
    ) and left(virtual,1) <> ‘@’
    limit 1

Leave a Reply

Your email address will not be published.