How to use Postfix as a frontend for MS Exchange

Last Updated on 2020-08-25 by Joop Beris

This article explains how to use Postfix as a frontend for MS Exchange, with integrated spam filter and virus scnning. The base for this setup is openSUSE Linux 11.3., but it should work for most other distributions out there. It assumes you already have a running installation of Linux. We’ll be using postfix, amavisd-new, clamav and spamassassin.

How to use Postfix as a frontend for MS Exchange

Postfix

Since this is going to be a front-end server and not a final destination for incoming mail, we’re going to have to tell postfix it needs to hand off mail to our MS Exchange server after it has received it. First, let’s set up postfix so it will handle mail for our domain(s) and deliver it to the Exchange machine. Then, we will add in spam and virus scanning. Though postfix is arguably easier to set up than for instance sendmail,  it does require a correct and safe configuration of the MTA. Of course, first we’ll have to install postfix through the package manager of the distribution of choice. On openSUSE 11.3 this is not necessary because it is already the default MTA, but in case it isn’t there, you can get it quickly as follows:

# zypper in postfix

This will also pull in all dependencies required for the correct operation of postfix. The main configuration of postfix is done through the file main.cf, which on openSUSE lives in /etc/postfix. On openSUSE it is possible to set up the MTA through Yast, but we’ll do it on the command line. Open the main.cf file and edit the following parameters to match your needs and circumstances:

mydomain = example.com
myhostname = mail.example.com
mydestination = $myhostname, localhost.$mydomain
mynetworks = 10.0.0.0/8
relay_domains = $mydestination, hash:/etc/postfix/relay
smtpd_recipient_restrictions = permit_mynetworks,reject_unauth_destination, 
reject_invalid_hostname,reject_unauth_pipelining,reject_non_fqdn_sender, 
reject_unknown_recipient_domain,reject_unknown_sender_domain
soft_bounce = yes unknown_local_recipient_reject_code = 450

This is enough to tell postfix that it is the MTA for our domain. The last two parameters in red are safety precautions, telling postfix not to refuse messages but instead telling the sender to try again later. In case we make a configuration mistake, the sender will be notified of a temporary failure. Once we get postfix et al up and running and everything seems okay, we will change these back to the default: to bounce mail definitively.
We need one additional but important step because our postfix server is not the final destination for our domain, it is a front-end. It will have to be instructed to hand mail over to our internal MS Exchange server. In order to do this, we need to edit the /etc/postfix/transport file. This file is used to build the /etc/postfix/transport.db file. Open the file with your favourite editor and add the following at the bottom of the file:

example.com  smtp:[192.168.1.1]

This line instructs postfix to hand off all email destined for the domain example.com, via the smtp protocol, to the server at 192.168.1.1. Of course you need to change this to match the IP address of your internal mail server. The brackets around the IP address make sure that no DNS lookups are performed for this address. This saves time. When you have added all the domains and transports that you require, save the file and execute the following command to build the transport.db file:

# postmap /etc/postfix/transport

Now, reload postfix so that it will pick up the new configuration. On openSUSE this is accomplished by the command:

# rcpostfix reload

If all is well, postfix will now be accepting email for your domain and then passing it on to your internal MS Exchange server. Next, we will add spam scanning and virus scanning.

Spamassassin

Spamassassin is available from the openSUSE repositories and comes configured, though you may wish to tweak it a bit. However, because spamassassin is called through amavisd-new, many settings (such as what to do with spam) will have to be configured in amavisd-new. You do not have to start spamassassin as a daemon in this set-up. However, you will probably want to update spamassassin detection rules and keep them up to date. This will help your detect spam, so it is pretty important to do. For updating spamassassin detection rules, you can use the tool sa-update. You can read all you want to know about that tool in spamassassin wiki on Apache.org. I have added the following rule in /etc/crontab to take care of the updates automatically once a day.

* 8 * * *         root   /usr/bin/sa-update -D >> /var/log/sa-update 2>&1

All output is logged in /var/log/sa-update and since I have switched on debug logging for the update command, you will want to incorporate this file in the logrotate scheme of your distribution. Or, if you do not want logging, you can redirect the output to /dev/null instead. I’m paranoid, so I want the logging.

Amavisd-new

Amavisd-new is best compared to glue, which glues your MTA (postfix in this case), your spam scanner (spamassassin) and your virus scanner together. How it works, is probably best explained by a diagram.

How to use Postfix as a frontend for MS Exchange

As you can see, each email that arrives, is handed over to amavisd-new which then disassembles the message into its different components and feeds these to the various virus scanners which it supports and to spamassassin. When neither virus scanners or spamassassin find anything wrong with the message, it is reassembled and handed back to postfix as clean. Postfix then takes care of further delivery. However, if any of the virus scanners or spamassassin find something wrong, the message is marked as not clean and actions are taken which can be configured in amavisd-new. Although an MTA should not lose mail, personally I think it is better to discard messages which appear infected by a virus. Spam can be rerouted to a special mailbox, which can be monitored for false positives. However, as spamassassin learns, you will get less and less false positives.

First, we must start amavisd-new so that it will listen on tcp port 10024 by default, though you may specify another port in the amavisd-new configuration file, which on openSUSE lives in /etc.

# rcamavis start

In order to get postfix to hand off messages to amavisd-new for scanning, we need to edit both the /etc/postfix/master.cf and /etc/postfix/main.cf files. We will define a new transport in master.cf for amavisd-new at tcp port 10024 and a we will tell postfix to also listen on tcp port 10025 so that amavisd-new can hand messages back to postfix for delivery. Before you do this, make sure to create a copy of both files as especially editing master.cf can be tricky. One mistake and you could end up with trouble.
To begin, open up master.cf and add the following lines:

smtp-amavis unix  -     -       y       -       -       smtp
 -o smtp_data_done_timeout=1200
 -o disable_dns_lookups=yes

This creates a transport for postfix, called smtp-amavis. In a moment, we will tell postfix in main.cf that this is the name of its content-filter. First, let’s finish editing master.cf though. We still need to instruct postfix to listen on tcp port 10025 as well. To do this, add the following to master.cf:

127.0.0.1:10025 inet    n      -        n       -      -        smtpd
 -o content_filter=
 -o local_recipient_maps=
 -o smtpd_helo_restrictions=
 -o smtpd_sender_restrictions=
 -o smtpd_recipient_restrictions=permit_mynetworks,reject_unauth_destination
 -o mynetworks=127.0.0.0/8

With the above definition, postfix will listen only on localhost on port 10025 and accept mail only from localhost sent to this listener. To finish up, we should tell postfix about the content filter, which is done by adding the following to main.cf:

content_filter = smtp-amavis:[127.0.0.1]:10024

Notice that the name here must match exactly the entry we created before in master.cf! Again, the block quotes tell postfix not to do DNS lookups for this address. It would only slow things down if it did. We need to restart postfix for the changes to take effect. On openSUSE, this is done as follows:

# rcpostfix restart

The restart should be almost instantaneous. To check if our changes worked we check if postfix and amavisd-new are listening on their respective ports.

# netstat -atpn

tcp    0   0 0.0.0.0:25           0.0.0.0:*       LISTEN      9374/smtpd
tcp    0   0 127.0.0.1:10024      0.0.0.0:*       LISTEN      9353/amavisd
tcp    0   0 127.0.0.1:10025      0.0.0.0:*       LISTEN      9305/smtpd

It seems that we have succeeded. Among the output of the netstat command, we find the lines above, indicating there is an smtp daemon listening on ports 25 and 10025 and also that amavisd is listening on port 10024. We can test this further by trying to telnet to the mentioned ports:

# telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.example.com ESMTP Postfix

----------------

# telnet localhost 10025
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.example.com ESMTP Postfix

----------------

# telnet localhost 10024
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 [127.0.0.1] ESMTP amavisd-new service ready

These tests have also succeeded. At this point, we may conclude that amavisd-new is running as expected and that postfix should be able to hand off any messages it receives to amavids-new and to get them back for further delivery.

By default, amavisd-new calls several virus scanners in its configuration file. Most of them you will not have installed on your system, so you may wish to comment them out so amavisd-new doesn’t complain about them in the log.

Clamav

Clamav is a free virus tool-kit which runs on Linux and Unix. It is specifically designed for email scanning on mail gateways, so it suits our purpose perfectly. It can run daemonized but in our case, it will be called by amavisd-new per email message. Clamav is packaged with openSUSE, so not much configuration is required. The amavisd-new configuration file supplied with openSUSE already points to the right location so out of the box, messages can be scanned for viruses.

# ### http://www.clamav.net/
 ['ClamAV-clamd',
 &ask_daemon, ["CONTSCAN {}n", "/var/lib/clamav/clamd-socket"],
 qr/bOK$/m, qr/bFOUND$/m,
 qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],

However, a virus scanner is only as good as its most recent update so it is important to keep our copy of Clamav up to date. Because new viruses and malware come out every day, I have chosen to let Clamav update itself every hour. For this, we can make use of the ‘freshclam’ utility. I call freshclam hourly from cron and for the rest, things just work.

59 * * * *      root    /usr/bin/freshclam >/dev/null 2>&1

The line above calls freshclam every 59 minutes past the hour. Any output from the command is directed to /dev/null, but Clamav logs messages about updates to the general mail log in /var/log/mail through syslog so we can keep track of updates succeeding or failing.

Finishing touches

If you’ve done the above steps, everything should work, but probably not exactly as you might like. You probably want to specify what you want to happen to spam messages, virus messages and when to mark messages as spam. Maybe you want to block certain attachments at the mail gateway. All of this is possible, so let’s see where and how we have to change settings.

Tweaking spamassassin

It’s important to remember that when spamassassin is called through amavisd-new, certain settings in its own configuration file are ignored. Mainly these are the settings for at which score to mark messages as spam and if and how to rewrite the subject header. These settings are handled by amavisd-new in its own configuration file. Other settings are configured in the spamassassin configuration file, which on openSUSE lives in /etc/mail/spamassassin. Here we find the file local.cf which holds the site-wide configuration. In my local.cf are the following settings:

use_bayes 1
bayes_auto_learn 1
bayes_auto_learn_threshold_nonspam 2.0
bayes_auto_learn_threshold_spam 5.0
skip_rbl_checks 0
report_safe 1

From top to bottom, these settings have the following effect:

  • Activate the Bayesian database, which allows spamassassin to learn about certain characteristics of messages that you receive, so that detection of spam is tailored to your situation over time.
  • Activate the Bayesian auto-learning system. This setting is tied in with the two settings below it and tells spamassassin to learn about messages automatically as they arrive. If you do not use auto-learning, you have to train the Bayesian filter by hand.
  • This setting sets the threshold below which spamassassin learns a message as non-spam (a.k.a. “ham”). It is important not to set this too high, otherwise spam messages may be learned as ham. If you set it too low, virtually no messages will get learned as ham, decreasing the effectiveness of your Bayesian filtering. Do not set this arbitrarily, but check how your mail scores on the whole and set your threshold accordingly.
  • The setting above which spamassassin learns  a message as spam. Like the previous setting, this should not be set arbitrarily, but checked against the mail you receive on general. Too low a setting may result in legitimate messages being learned as spam, too high and your filter will not be trained on low-scoring spam.
  • This setting instructs spamassassin not to skip tests which check if senders have been added to real-time blacklists. Be aware that these checks may cause mail delivery to slow down. Also, be aware that sometimes legitimate senders may be added to RBL’s under certain conditions, causing messages from them not being delivered to your users. So be careful enabling these tests.
  • This setting instructs spamassassin to generate a new message for a detected spam message, encapsulating the original message.

Acting on infected messages and spam messages

It’s probably safe to assume that you do not want your users to receive viruses on their client PC’s, hand-held device or what have you. Likewise, you most likely don’t want them bothered with messages peddling Viagra, fake Rolexes and university diplomas. Through amavisd-new we can act on these messages. This behaviour is configured in the amavisd-new configuration file in /etc/amavisd.conf. On openSUSE the default appears to be to quarantine all types of possibly unwanted messages. This is safe because you do not lose messages and should a message be a false positive, it can be retrieved from the quarantine. However, you may not want this for the long term, because it means having to review and delete messages from the quarantine manually or by some automatic process. But if you’re going to clean the quarantine using an automatic process, you may want certain messages not to be quarantined in the first place. Especially for messages which are infected with a virus it may be better to discard them completely. Below are the options to accomplish these things in the amavisd-new configuration file.

$final_virus_destiny      = D_DISCARD;
$final_banned_destiny     = D_BOUNCE;
$final_spam_destiny       = D_BOUNCE;
$final_bad_header_destiny = D_PASS;

The above settings are the default settings, you can alter them as you like. Your options for that are D_DISCARD, D_BOUNCE, D_REJECT and D_PASS.
Virus infected messages: The top setting tells amavisd-new to discard virus infected messages without delivering them. For viruses, this seems like a sane option because your users will never see these messages and thus can not become infected. The messages will be discarded silently.
Banned messages: The setting final_banned_destiny controls what to do with messages that violate certain policies, for instance messages with executable attachments. By default they are bounced, meaning that the recipient does not get the message but the sender receives a notification that his/her message was not delivered.
Spam messages: The default setting for spam messages (final_spam_destiny) is also set to bounce, but this seems a bit optimistic. The sender address of most spam messages is faked so it is not likely that the original sender gets the bounce message. It may be better to quarantine low scoring messages (to prevent false positives from being lost) and to discard high scoring messages altogether. Here’s how to do that:

# $final_spam_destiny       = D_BOUNCE;
$sa_tag_level_deflt  = 2.0; # spam info headers are inserted (no action taken)
$sa_tag2_level_deflt = 5.0; # subject of message is altered
$sa_kill_level_deflt = 5.5; # mail is not delivered
$sa_dsn_cutoff_level = 5.5; # bounce message not sent
$sa_crediblefrom_dsn_cutoff_level = 10; # bounce sent if sender credible

What the above does is to disable the general bouncing of spam, instead looking at the score of each individual message and acting according to the score. A score of 2 or more means that spam headers are inserted into the message, but taking no other action. If the message scores 5 or more points, the subject header is prefaced with  a custom text, usually something like “*** SPAM ***”. This text can be set in the configuration file. At score 5.5 and higher, the message is no longer delivered to the recipient. A dsn (=delivery status notification)message is also not sent at this score, unless (see final option) the sender address looks credible to spamassassin, which may indicate that the message may be a false positive. In this case the sender will be notified but the message not delivered. Notice that these settings are fairly strict and you should adapt them for your situation, not just copy them from me.
Messages with bad headers: This is a tricky category. Bad headers can indicate a lot of things, but they are often caused by poorly designed mail software, mailing lists that do not adhere to standards, etc.. The default is to let them pass and this seems to be the best choice to me as well.

Blocking messages with certain attachments

It’s very easy to block messages with various kinds of attachments using amavisd-new. There are plenty of examples of this in the configuration file. For our site, we have the following settings, which can of course be altered:

### BLOCKED ANYWHERE ###
qr'^MAIL-UNDECIPHERABLE$', # recheck full mail if it contains undecipherables
qr'^(ASCII(?! cpio)|text|uuencoded|xxencoded|binhex)'i,
qr'.[^./]*.(exe|vbs|pif|scr|bat|cmd|com|cpl|dll).?$'i,
qr'{[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}}?$'i, # Windows Class ID CLSID, strict
qr'^application/x-msdownload$'i, # block these MIME types
qr'^application/x-msdos-program$'i,
qr'^application/hta$'i,

This prevents people from receiving and sending out the following file types: exe, com, bat, dll, pif, scr, double extensions, animated cursors and most other nasty things. Of course it is also possible to disable receiving of video clips and audio clips and the like. For more information, see the amavisd-new configuration file.

Cleaning amavisd-new quarantine

Over time (if you use quarantine), your amavisd-new quarantine may fill up with old messages, never looked at and probably no longer needed. It is safe to delete these. You can do this manually, but it is better to automate this process so it will not be forgotten. We’ll do that by creating a simple cron job that will remove any file older than 31 days from the cache. If no one has missed the email in question in a month, it will probably never be missed at all. First, we need to find out where amavisd-new keeps its cache. We can find that by looking at the configuration file (/etc/amavisd.conf).

$MYHOME = '/var/spool/amavis';
$TEMPBASE = "$MYHOME/tmp";   # working directory, needs to exist, -T
$ENV{TMPDIR} = $TEMPBASE;    # environment variable TMPDIR, used by SA, etc.
$QUARANTINEDIR = '/var/spool/amavis/virusmails';  # -Q

The above shows us that the quarantine is at /var/spool/amavis/virusmails and that there is a directory for temporary files in /var/spool/amavis/tmp. We will clean both out via cron.

# Cleanup amavis quarantine automatically, throw out everything older > 31 days
* 3 * * *       root    find /var/spool/amavis/virusmails/ -mtime +31 -exec rm {} ;
30 3 * * *      root    find /var/spool/amavis/tmp/ -mtime +31 -exec rm {} ;

That should take care of things and keep our quarantine to a manageable size.

Now, there is only one thing left to do. At the very beginning of this document, we instructed postfix to soft bounce messages. If you are certain your front-end mail server is working the way you want it, you can now alter this setting back to the default, to bounce messages permanently. Go back to /etc/postfix/main.cf and alter the following settings:

soft_bounce = yes
unknown_local_recipient_reject_code = 450

They should read:

soft_bounce = no
unknown_local_recipient_reject_code = 550

Issue an rcpostfix restart at the command line and the new settings should be effective right away. We’re all done now and should have a safe, fast and reliable front-end mail server protecting our Exchange machine from spam, viruses and other internet nasties.

That concludes the explanation of how to use Postfix as a frontend for MS Exchange. If you have comments, additions or corrections for this document, please leave them via the comment form below. The post shall be updated as necessary.

0 0 votes
Rate this article

If you liked this article, you might enjoy these too:


Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

13 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Anders Winther
Guest
Anders Winther
2019-03-08 10:25

Yes – reason for not making a specific connector and only accept internal connections, is, (in my head), that if for some reason the frontend is going down og needs to be taken down, I can just make one change on my router, and mail still received. 🙂
I don´t think i max out the limitations in Spamhaus.

Anders Winther
Guest
Anders Winther
2019-03-07 09:45

Hi Joop.

Well – it works fine now using SLES15.
I had to pick some of your instructions and alter them a bit, but essential you are still ok with your doings. 🙂
If you already have a running Exchange – no modifications needed. It just uses the same SMTP connector, which is nice – since – if anything goes wrong on your Linux, you only need to change the routing/NAT point at your router, and mail comes directly to your Exchange.
Only annoying thing is zen.spamhaus.org not picking anything up – don´t know why – it used to work on my old Postfix MTA before I switched to Exchange (and got flooded with SPAM).

Anders
Guest
Anders
2019-03-05 10:38

Hi Joop.

Don´t know if this still is THE way to do it, but if it is – as I understand it, no modifications are needed for the Exchange server, right?
Only a modification on the router I guess so port 25 is NAT´ed through the Postfix server?

trackback

[…] or hosts that we have not seen before. Before diving into this post, you may wish to examine an older post I’ve done, that explains in some detail how to set up a Postfix MTA with amavisd-ne…. It’s a bit outdated now, but the concept is still valid. That post was written for openSUSE, […]

sakaio
Guest
2014-09-03 05:09

Joop, many thanks for the excellent tutorial, it was just the solution I was looking for as a front end for my exchange 2013. Now just a question, where do you put this centos machine? outside of your Internal network or within your internal network?

cheers

sakaio

Mohsen ghaffari
Guest
Mohsen ghaffari
2012-04-25 11:15

Thanks Joop for such a comprehensive tutorial.I have read a couple of other articles with regard to this scenario but yours was the best.i was wondering if you would let me translate it to Persian.
Mohsen

Mohsen ghaffari
Guest
Mohsen ghaffari
2012-04-30 23:10
Reply to  Joop Beris

Thanks Joop. 🙂

Ngugi Njoroge
Guest
Ngugi Njoroge
2011-06-21 08:12

this is very informative.It worked very nicely with my mdaemon PC.Kundos

13
0
Let me know your thoughts on this post. Leave a comment, please!x
()
x