Remove mail headers in Postfix outgoing mail

This post is intended for people who want to set up Postfix to remove specific headers within emails that pass through their systems. The most common use for this is to set up a relaying server that will remove any reference of where source emails originated and relevant information about the sender’s computer. Another useful application for this type of header_checks is to remove details about additional functions of your mail server that you do not want made available to the world.

This guide focuses on postfix’s header_checks capabilities, and although there are other ways to do so, we’ve found that this is by far the simplest.


Use these instructions at your own risk. Never test things out in a production environment!

In order for this to work, your file will have to have a reference to the header_checks file as follows:

header_checks = regexp:/etc/postfix/maps/header_checks

It is recomended that you keep all of your postfix map files in one directory along with any checks files. In this case, these will be kept in /etc/postfix/maps.


In addition to any spam filters (see our header_checks file for more information), the below lines should be added to your header_checks file to preserve privacy and remove headers for the internal operations of your mail server:

    # Sample For Dropping Headers: 	
    #/^Header: IfContains/ 	IGNORE
    /^Received: from 	IGNORE
    /^User-Agent:/ 	IGNORE
    /^X-Mailer:/ 	IGNORE
    /^X-Originating-IP:/ 	IGNORE

Each line above will search for headers tha have the content between the /^ and the / and will remove each line within the email headers that matches. As an example, the line “/^Received: from .*/ IGNORE” will erase any lines from the email headers that list previous handoffs from an internal mail process to another. This is most commonly used for antivirus or antispam functions on a mail server.

The following lines are related to Anomy Sanitizer and SpamAssassin – two very useful products. These three lines will remove references from the headers for the two software packages, making sure that the users of the system will not easily identify the software that is running on the back end.

    # Sample For Dropping Headers: 	
    #/^Header: IfContains/ 	IGNORE
    /^Received: from 	IGNORE
    /^X-Sanitizer:/ 	IGNORE
    /^X-Spam-Status:/ 	IGNORE
    /^X-Spam-Level:/ 	IGNORE

If one were to want to remove all headers relevant to personal information and previous hosts on which the email has passed, the following would be a possible configuration. Note that by removing all of this information, some mail servers will automatically identify emails passing through this system as spam. You will also be removing useful information for troubleshooting any problems that may arise with the mail server.

    # Sample For Dropping Headers: 	
    #/^Header: IfContains/ 	IGNORE
    /^Received:/ 	IGNORE
    /^User-Agent:/ 	IGNORE
    /^Message-ID:/ 	IGNORE
    /^X-Mailer:/ 	IGNORE
    /^X-MimeOLE:/ 	IGNORE
    /^X-MSMail-Priority:/ 	IGNORE
    /^X-Spam-Status:/ 	IGNORE
    /^X-Spam-Level:/ 	IGNORE
    /^X-Sanitizer:/ 	IGNORE
    /^X-Originating-IP:/ 	IGNORE

Hopefully this will help you clean your mail headers up! 🙂

Relay Exim mail to google mail in Debian Linux

Sometimes its necessary to relay your mail through a third party provider. If your server environment has a dedicated sendmail server (most do), then this scenario is applicable to you. It is ideal to centralize your outgoing mail to one server so that changes, policies and configuration is located in a single place.

In this scenario, outgoing mail is relayed to google’s domain mail in an Exim mail environment. These steps are fairly straightforward and will hopefully help you to utilize google’s free mail service to send your mail.

Note that google has queuing and mass mail restrictions so if you plan on sending alot of mail this way, you will just get blocked.

    Step 1

Run dpkg-reconfigure exim4-config

1. Choose mail sent by smarthost; received via SMTP or fetchmail

2. Type System Mail Name: e.g.

3. Type IP Adresses to listen on for incoming SMTP connections:

4. Leave Other destinations for which mail is accepted blank

5. Leave Machines to relay mail for: blank

6. Type Machine handling outgoing mail for this host (smarthost):

7. Choose NO, don’t hide local mail name in outgoing mail.

8. Chose NO, don’t keep number of DNS-queries minimal (Dial-on-Demand).

9. Choose mbox

10. Choose NO, split configuration into small files

11. Mail for postmaster. Leaving blank will not cause any problems though it is not recommended

    Step 2

1. Open the file /etc/exim4/exim4.conf.template
2. Find the line .ifdef DCconfig_smarthost DCconfig_satellite and add the following in that section

 driver = manualroute
 domains = ! +local_domains
 transport = gmail_smtp
 route_list = *

If you have any other smarthost defined with “domains = ! +local_domains” remove that smarthost.

3. Find the “begin authenticators”. In that section add the following

 driver = plaintext
 public_name = LOGIN
 client_send = : : YourGmailPassword

Make sure you have no other authenticators with the same public_name (LOGIN). Comment them out if needed (Thanks Jakub for reminding me)

4. Find the comment “transport/30_exim4-config_remote_smtp_smarthost”. In that section add

 driver = smtp
 port = 587
 hosts_require_auth = $host_address
 hosts_require_tls = $host_address
    Step 3

1. Run update-exim4.conf

2. Do /etc/init.d/exim4 restart

That should be it. You can test by using the command line mail client.

Test :

 echo "test" | mail -s "subject"

Setup Up Exim with ClamAV and Spamassassin

I decided to post this article on implementing a simple single mail server with anti-spam and anti-virus capabilities.

This guide hopefully will help you on your way to configuring a basic mail system on Linux (specifically Debian).

Installing and configuring Exim 4 on Debian

1. First, install all the necessary Debian packages are on the system as the root user. (The exim4 package will REPLACE the exim package.)

NOTE: If you are using the stable branch, it is suggested to use the debian volatile packages (along with the security packages) so that your system is using the most up-to-date critical packages (like ClamAV) for security purposes. For production servers, you may not want to run a mixed stable/testing/unstable system (though I know some of you do!). To use these packages, see for more information. For those of you who are impatient and don’t want to find the correct mirror, here’s is what I added to my /etc/apt/sources.list file:

deb sarge/volatile main contrib

I used aptitude to install these packages, but you could also use the old apt-get method:

apt-get install clamav-daemon 
clamav-freshclam exim4-daemon-heavy exim4 
courier-base courier-authdaemon courier-imap 
courier-pop spamassassin wget spamc sa-exim

When going through the exim4 config, be sure to select the multiple file configuration layout. If you didn’t (or weren’t prompted for it), simply set dc_use_split_config to true in the /etc/exim4/update-exim.conf.conf file. (Thanks Mike!)

2. Create your Maildir directory

maildirmake ~/Maildir/

3. Now we want to make exim4 use Maildir format mailboxes. Modify the file /etc/exim4/update-exim4.conf.conf so that it contains:


4. We need to Edit /etc/default/spamassassin to enable spamd.

5. Each user can set up their own filters by creating a .forward file in their home directory. If the first line of this file reads

# Exim filter then Exim4 will treat it as a filter.

Here is an example of an Exim filter that checks the headers that SpamAssassin adds and puts the mail in the appropriate Maildir folder:

      # Exim filter
      if $h_X-Spam-Status: CONTAINS "Yes"
        $h_X-Spam-Flag: CONTAINS "Yes"
        save $home/Maildir/.Spam/

Exim’s Interface To Mail Filtering (PDF format) – Local copy

6. Many system administrators like to set up the Maildir directories and .forward filter file in the /etc/skel directory so that when they make a new user on the system, everything is automatically copied over. I suggest that you do this as well as it makes things easier.

7. Before going live with the mail server, we will want to test it!

Testing the implementation

1. Generate the new configuration:


If you made it through this, then your config files don’t have any syntax errors.

exim4 -bV

If that works, then there are no config issues

2. Next, start exim by issuing:

/etc/init.d/exim4 start

Above assumes that you are running exim4 as a daemon, and not through inetd

3. Now, check a local address:

            exim4 -bt

4. Check sending an email:

            exim4 -v mailbox_you_can_check@dom.ain
               From: user@your.domain
               To: mailbox_you_can_check@dom.ain
               Subject: Testing exim
               Testing exim

You should now see some messages to let you know that the email was sent or information about what went wrong.

5. To test with full debug output using a specific config file, use something like:

            exim4 -C /etc/exim/exim_example.conf -d -bt

6. To test the config coming from a specified ip address, use:

            exim4 -bh

               MAIL FROM: 
               RCPT TO: 
               Subject: something
               your message here

8. Add the following to your /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs file:

      # This tells what virus scanner to use
      av_scanner = clamd:/var/run/clamav/clamd.ctl

9. Edit /etc/exim4/conf.d/acl/40_exim4-config_check_data to inlude the following before the “# accept otherwise” line:

      # Reject messages that have serious MIME errors.
         # This calls the demime condition again, but it
         # will return cached results.
         deny message = Serious MIME defect detected ($demime_reason)
         demime = *
         condition = ${if >{$demime_errorlevel}{2}{1}{0}}
         # Reject file extensions used by worms.
         # Note that the extension list may be incomplete.
         deny message = This domain has a policy of not accepting certain types of attachments 
                        in mail as they may contain a virus.  This mail has a file with a .$found_extension 
                        attachment and is not accepted.  If you have a legitimate need to send 
                        this particular attachment, send it in a compressed archive, and it will 
                        then be forwarded to the recipient.
         demime = exe:com:vbs:bat:pif:scr
         # Reject messages containing malware.
         deny message = This message contains a virus ($malware_name) and has been rejected
         malware = *

10. Then, you need to enable ClamAV.

a) Firstly, you will want to be sure that it is running against messages. In /etc/exim4/sa-exim.conf, search for SAEximRunCond:

SAEximRunCond: ${if and {{def:sender_host_address} {!eq {$sender_host_address}{}} {!eq {$h_X-SA-Do-Not-Run:}{Yes}} } {1}{0}}

That is simply skipping the scan on anything from the local machine or if the X-SA-Do-Not-Run header in the message is set to Yes. If you just want exim to run ClamAV on all messages, use this:

SAEximRunCond: 1

b) Before restarting ClamAV, we need to be sure that all of the access rights are in place so that the scans actually happen. The best way to handle this is to add the clamav user to the Debian-exim group. Either manually edit /etc/group, or simple run:

adduser clamav Debian-exim

c) Be sure that /etc/clamav/clamd.conf contains a line that reads:


d) Set the file permissions for the /var/run/clamav directory to allow for the correct user to use it:

            chown Debian-exim.Debian-exim /var/run/clamav
            chmod g+w /var/run/clamav

e) A restart of ClamAV is necessary for the changes to take effect:

/etc/init.d/clamav-daemon restart

11. You should now be able to get your mail via IMAP with a mail client like Mozilla.

Check your headers (View Source) and see that SpamAssassin has added its headers. SMTP-end virus scanning should also be taking place. Check your /var/log/clamav/clamav.log to monitor this.

Multiple Domain Alias Files

The steps below are used to enable support for having multiple virtual domains each with its own alias file.

1. Exim will need to have the alias files for each domain.

a) Create the /etc/exim4/virtual directory.
b) For each virtual domain, create a file that contains the aliases to be used named as the domain.

For example, if I was one of my domains, I’d do the following:

a) Create the /etc/exim4/virtual/ file.
b) If my system users were sys1, sys2, and sys3, and their email addresses were to be joe, john, jason, I’d put the following into the domain alias file:

                  joe:    sys1@localhost
                  john:   sys2@localhost
                  jason:  sys3@localhost

If john was also to get all mail addressed to, you would add this entry:

info:   sys2@localhost

If you wanted all mail to to go to another email account outside of this domain, you would enter:

user1:  a.user@some.domain

If you wanted all mail directed at any address other than what is defined in the alias file to go to joe, you’d enter:

*:      sys1@localhost

In the above examples, the “@localhost” suffix to the user names forces the delivery to a system user. I found that if you do not include this in the alias files and your machine’s host name is within one of the domains handled by exim, every system user would need an entry in the machine’s domain in order to be delivered corectly.

For instance, if your host name was and was handled by this server this would be needed. This would allow delivery to all the system user names at

The reason is simple, and I will try to illustrate it for you here:

a) exim receives a message delivered to
b) The alias file for this domain has joe.blow: jblow in it.
c) This would translate to jblow@domain-of-the-system
d) The process would be repeated using jblow@domain-of-the-system
e) If there was no entry in the domain-of-the-system alias file for jblow, the message would be undeliverable (or non-routable)

You could even have special redirects like the following:

script: "| /path/to/some/script"
prev:   :fail: $local_part left!
kill:   :blackhole:

2. Edit /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs by replacing the current local_domains line with:

domainlist local_domains = @:localhost:dsearch;/etc/exim4/virtual

3. Create /etc/exim4/conf.d/router/350_exim4-config_vdom_aliases with the following content:

            driver = redirect
            domains = dsearch;/etc/exim4/virtual
            data = ${expand:${lookup{$local_part}lsearch*@{/etc/exim4/virtual/$domain}}}
            pipe_transport   = address_pipe
            file_transport   = address_file

4. Now, regenerate your exim4 config:


5. If there were no errors, restart exim4:

/etc/init.d/exim4 restart

Domain Dependent Maximum Message Size

The next step for my server is to give each domain a configurable message size limit. Then, when the server get’s a message that is larger than the target domain’s size limit, I want to send a message back to the original sender telling them why the message was not delivered. However, I also want to have that message customized for each domain. That way, the domain owners can provide detailed instructions on how to send large messages to their domain if it is necessary. Of course, there will also need to be some kind of default size limit and message for domains that do not need the customization.

1. Create /etc/exim4/domain-size-limits to contain the list of domains and their maximum message size limits. You can also add a wildcard at the end entry if you want to set a default limit. The file may look something like the following: 20M 5M
      *: 15M

This provides you a quick way to edit the values. The values will also take effect as soon as the file is saved – no need to restart exim!

2. OK, now we know what domains we want to customize the size for. Now it’s time to create a message to send for those domains. Create /etc/exim4/domain-size-limit-messages with content similar to: The largest acceptable message size for is
                   Your message was $message_size. If you feel that $local_part@$domain
                   should really get your message, then visit
                   where you can upload any large files. If you select $local_part@$domain
                   from the "notify" list, they will receive a message with a link directly
                   to your file.
      *:           The largest acceptable message size for $domain is
                   Your message size was $message_size. Please revise your message so it
                   does not exceed this maximum file size and resend. If this is not
                   possible, contact the recipient in another way.

As you see, we have one domain that has a custom message sent out, and have defined a default message for all other domains. These messages can be edited at any time and do not need an exim restart to take effect.

3. Now for the fun part! We need a way to catch the messages that are too large for the domain! First, create /etc/exim4/conf.d/router/325_exim4-config_large_messages with the following:

          driver = accept
          domains = dsearch;/etc/exim4/virtual
          condition = ${if >{$message_size}{${expand:${lookup{$domain}lsearch*@{/etc/exim4/domain-size-limits}}}} {yes}{no}}
          transport = bounce_large_messages

This router dynamically checks which domains are available and what their limits are set to.

4. Now create /etc/exim4/conf.d/transport/40_exim4-config_bounce_large_messages with the following content:

      # This bounces a message to people who send files too large for that domain
        driver = autoreply
        from = $local_part@$domain
        to = $sender_address
        subject = Re: ${escape:$h_subject:}
        text = ${expand:${lookup{$domain}lsearch*@{/etc/exim4/domain-size-limit-messages}}}

This transport then sends the original sender a message using the text looked up from the domain-size-limit-messages file for that domain. The From: field is filled in with the intended recipient of the message – appearing to be a reply.

This was actually very simple to put together once I realized what I needed to do. The above is based on what I found in the Exim FAQ

Configuration Tips

Maybe this is something I should have said in the beginning, but at the time or writing this document, I had never set up an exim4 server, and the only exim3 server I had was used with the default debconf install. Therefore, if you see something on this page that could be done in a more elegant, more efficient or just plain better way, please send me a note.

Troubleshooting Mail : Basic Tips

In a shared or managed hosting environment, many people would agree that one of the most commonly reported issue with our helpdesk is email.

It has become a best practice to perform basic email troubleshooting , depending on the error / bounce back reported. These steps could be performed before or after the issue has been fixed — either to confirm it is working or to reproduce a particular problem.

The purpose of this document is to describe how mail gets from one users email client to another users mailbox. Each action that takes place can be tested and verified by an some level of admin with a few exceptions. After going through this document you should understand what takes place when a user sends email or has email sent to them.

Test SMTP Authentication

SMTP users BASE64 encoding to transmit usernames and passwords. You will need to take the username of the client ( ) and the password and convert them to BASE64. Links provided below to do this:


telnet 25
helo mailserver
auth login
BASE64 Encoding of
BASe64 Encoding of PASSWORD

Test Sucessful if: 235 Authentication successful

Testing if user is local or remote

Our mailserver will only accept email for a remote host if you authenticate first. Without authentication it will only accept email for local domains.

telnet 25
helo mailserver
mail from:
rcpt to:

Local Domain if: 250 ok
Remote Domain if: 553 sorry, that domain isn’t in my list of allowed rcpthosts

Looking up an MX record

Two or three lookups should be done off of various DNS servers., a public recursive NS server (, and the NS server specified in the WHOIS of the domain. Ideally these will all match, if they don’t then connections to the incorrect mailserver may be made.


set type=mx

Testing to see if remote server will accept a message

Similar to the test we use to see if our mail server will take the message as a local delivery you can do the same test on the remote server to see if it will take the message.

telnet 25
helo mailserver
mail from:

Test Sucessful if: 250 ok

Send an entire message to a mailserver

telnet 25
helo mailserver
auth login
BASE64 Encoding of USERNAME
BASe64 Encoding of PASSWORD
mail from:
rcpt to:
To:     StarDot Sales
Subject: This is a test email
Dear SDH,
This is the body of your email.

Test Sucessful if: 250 ok

Check to see if a remote server is in an RBL

You will need to find out what the IP address of the machine that is actually sending the email out to the internet. There are many tools out there to check you rdomain / IP address againts many RBL lists :


RBL’s Checked Against:


SpamAssassin Troubleshooting

Via the webmail (Squirrel Mail) place the address that is trying to email the customer in the whitelist. When the email arrives check the email headers which will show any SpamAssassin checks that applied points to the message. Details on the SA tests and how to check email headers is available on the links below:

* Headers:
* SA Tests: