Postfix : Anti-Spam Methods
From TroubleshootingWiki
| Official Page |
| Project Documentation |
| Download |
|
Contents |
[edit] Stopping Spam and Other Unwanted Messages
This tutorial will discuss the various methods Postfix provides to help stop unwanted messages. Spam, or unsolicited commercial e-mail, is perhaps the biggest problem that e‑mail server administrators face but there may also be other kinds of messages that one does not want to receive.
Postfix by itself will not stop all spam, but it can catch many spam messages. For some people this may be adequate, but if you need to fight large volumes of spam you additionally need a tool such as SpamAssassin. Even if you use SpamAssassin, Postfix's own lightweight methods can help reduce the load on the server by rejecting the messages before they even reach SpamAssassin.
[edit] Postfix's Anti-Spam Methods: An Overview
There is no silver bullet to stop all spam, but Postfix provides a number of methods that you can use to help the situation:
SMTP restrictions: SMTP restrictions let you define rules for which messages should be accepted. The rules cannot take into account the content of the message, just the envelope information. The SMTP restrictions are not merely a tool for stopping spam, but a general way of defining policies for the usage of the mail system.
DNS blocklists: DNS blocklists are globally published blocklists containing IP addresses of known spammers and other likely sources of junk mail. Postfix lets you use this information to reject messages.
Matching header expressions: The header fields and message bodies can be matched against regular expressions, allowing you to reject certain types of e-mail.
Additionally, Postfix provides the following methods for filtering spam:
- After-queue content filtering: After Postfix has accepted a message, it will not be delivered to the destination right away. Instead, it will be fed to a content filter that can do anything with the message; delete it, scan it for viruses, strip unwanted attachments, and so on.
- Before-queue content filtering: The drawback with after-queue content filtering is that Postfix always accepts the message before the message is sent to the content filter. This means that Postfix cannot reject a message based on the verdict of the content filter. Before-queue content filters receive the messages during the SMTP session and can choose to reject them. Notice that one before-queue content filter connection is required for each open SMTP session, so this type of content filter does not scale and is not suitable for high-traffic sites. This feature requires Postfix 2.1 or later.
- Access policy delegation: If the SMTP restrictions are not sufficiently expressive, you can construct your own access policy server that Postfix can contact during each SMTP session. Using this tool, you can enforce just about any specialized policy you want. Postfix comes with a very simple policy daemon for use to implement greylisting, but several other policy daemons have been made by other people. Links to these daemons and other Postfix add-on software can be found at http://www.postfix.org/addon.html.
[edit] Understanding SMTP Restrictions
Postfix has a simple but still pretty expressive notation for defining rules that will be applied to messages that arrive via SMTP. For example, you can express a policy to reject messages sent from certain networks, clients who say HELO with certain hostnames, or clients that have no reverse records in DNS unless they are one of your own clients.
Postfix defines a number of parameters that contain lists of restrictions. Each restriction list may contain zero or more restrictions, and each restriction may or may not return something when evaluated. As in a few other places in Postfix, the "first match wins" principle reigns here too. This means that the restrictions are evaluated in the order they are specified, and the first restriction that returns something terminates the evaluation of the current restriction list.
The restriction lists get evaluated during the SMTP session. The following table contains the restriction lists that Postfix uses, and shows at what stage in an SMTP session they are evaluated:
| Parameter | Point of evaluation |
|---|---|
smtpd_client_restrictions
| Directly upon connection. |
smtpd_data_restrictions
| When the client has sent the DATA command.
|
smtpd_end_of_data_restrictions
| When the client has sent the complete message. This restriction list is available in Postfix 2.2 and later. |
smtpd_etrn_restrictions
| When the client has sent the ETRN command. This command is not used in a normal SMTP session.
|
smtpd_helo_restrictions
| When the client has sent its greeting with HELO or EHLO.
|
smtpd_recipient_restrictions
| When the client has sent a recipient address with RCPT TO.
|
smtpd_sender_restrictions
| When the client has sent the sender address with MAIL FROM.
|
Having said that, the default value of the smtpd_delay_reject parameter is yes. This means that all rejections will be postponed until after RCPT TO. The reason for this is that some client software do not like being rejected before RCPT TO, so it will disconnect and try again. A common misunderstanding is believing that, say, only restrictions on the recipient address can be placed in smtpd_recipient_restrictions. The name of the restriction list only tells at what stage in the SMTP session the listed restrictions will be applied, but because of smtpd_delay_reject that is not strictly true.
Let us dig in by using the postconf command to inspect the default values of the most commonly used restriction lists:
$ postconf d smtpd_client_restrictions smtpd_helo_restrictions \ smtpd_sender_restrictions smtpd_recipient_restrictions smtpd_client_restrictions = smtpd_helo_restrictions = smtpd_sender_restrictions = smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination
This tells us that Postfix by default does not have any client, HELO, or sender restrictions. It does, however, have two recipient restrictions. The first one, permit_mynetworks, permits the current recipient if the connecting client is within the networks specified by mynetworks. It is this restriction that gives your own clients relay access. If the connecting client is not within mynetworks, the next item in the restriction list will be evaluated. reject_unauth_destination will reject recipients whose domain is not one of the domains that Postfix will accept mail for. In other words, reject_unauth_destination rejects relay attempts. If no rejection takes place here, the end of the restriction list has been reached. If that happens, Postfix accepts the message.
A permit result in one restriction list will not cause the message as a whole to be accepted. Only the remaining restrictions in the same list will be bypassed. This is not true for restrictions that return reject that result is always terminal and stops the evaluation of all restriction lists.
There are more than 50 standard SMTP restrictions to choose from, and there is no room to cover them all here. This table will present a little smorgasbord with useful restrictions.
| Restriction | Description |
|---|---|
permit_mynetworks
| Permit if the connecting client is listed in mynetworks.
|
permit_sasl_authenticated
| Permit if connecting client has authenticated itself. |
reject
| Reject the request, unconditionally. |
reject_invalid_hostname
| Reject if the syntax of the HELO/EHLO hostname given by the client is incorrect.
|
reject_non_fqdn_hostname
| Reject if the HELO/EHLO hostname given by the client is not a fully qualified domain name.
|
reject_non_fqdn_recipient
| Reject if the domain part of the recipient address is not a fully qualified domain name. |
reject_non_fqdn_sender
| Reject if the domain part of the sender address is not a fully qualified domain name. |
reject_unauth_destination
| Reject the request unless the recipient domain is one of the domains that the Postfix server hosts, or for some reason, will accept mail for. |
reject_unknown_recipient_domain
| Reject if the domain part of the recipient address has no A or MX record in DNS. |
reject_unknown_sender_domain
| Reject if the domain part of the sender address has no A or MX record in DNS. |
reject_unlisted_recipient
| Reject if the domain part of the recipient address is a domain hosted by Postfix and the complete address is not a valid recipient address. By default, this restriction is implicitly evaluated at the end of smtpd_recipient_restrictions. This behavior is controlled by the smtpd_reject_unlisted_recipient parameter. By using reject_unlisted_recipient, you can put the restriction into effect earlier on. This restriction is available in Postfix 2.1 and later. Previous versions of Postfix can use the check_recipient_maps parameter.
|
reject_unlisted_sender
| Reject if the domain part of the sender address is a domain hosted by Postfix and the complete address would not be acceptable as a recipient address. The idea behind this feature is that there is no reason to accept messages with sender addresses known to be incorrect. This restriction is available in Postfix 2.1 and later. See also the smtpd_reject_unlisted_sender parameter.
|
[edit] Access Maps
In addition to the restrictions already discussed, Postfix defines a number of restrictions that look up information in a'ccess' maps. An access map is a lookup table with contents that affects whether a message will be accepted. The name of the restriction controls what information is used as the lookup key.
For example, the check_client_access restriction looks up the client IP address and hostname in a lookup table, allowing you to, say, ban certain clients that are known to send spam. Together with the restriction name you also state the type and name of the lookup table:
smtpd_client_restrictions = check_client_access hash:/etc/postfix/client_access
Although not an exhaustive list, the following are the most important restrictions that use access maps:
| Restriction name | Lookup key |
|---|---|
check_client_access
| Client IP address and hostname. |
check_sender_access
| The message sender address. Just like check_recipient_address, the parts of the address are looked up separately.
|
check_recipient_access
| A recipient address. The whole address, the domain part, and the part before the @ (the local part) are looked up separately.
|
check_helo_access
| The HELO/EHLO hostname.
|
The following results are recognized for a given lookup key (this is again not an exhaustive list):
| Result | Description |
|---|---|
OK
| Permit the request. |
REJECT [optional text]
| Reject the request with a permanent error code and either the specified error message or a generic message. |
DISCARD [optional text]
| If the message eventually gets accepted, it will be discarded and not delivered. |
HOLD [optional text]
| Place the message in the hold queue. Messages that are held will not be delivered and can be inspected with the postcat program and subsequently released for delivery or deleted. This can be used as a simple way of quarantining messages that might be unwanted. |
WARN [optional text]
| Places a warning message in the log file. Only available in Postfix 2.1 and later. |
restriction, restriction,
| Apply one or more restrictions and use their result. Only simple restrictions that do not refer to any lookup tables are allowed here unless you use restriction classes. Those are not covered in this book, but you can read about them in RESTRICTION_CLASS_README (RESTRICTION_CLASS_README.html http://www.postfix.org/ RESTRICTION_CLASS_README.html).
|
Full details about the lookup keys and possible results can be found in the access(5) manual page.
[edit] Examples
We will now use a series of examples with access maps to discuss how they can be used, both alone and along with other restrictions in order to form pretty expressive policies:
smtpd_client_restrictions = check_client_access hash:/etc/postfix/client_access
In this first example, the lookups will be made against the hash-type lookup table /etc/postfix/client_access. This file is not created by Postfix, and you may give it any name. From the Lookup Tables section we recall that 'hash'-type lookup tables are just text files from which binary files (in this case with the file extension .db) should be built with the postmap command whenever the source file changes:
postmap hash:/etc/postfix/client_access
Let us take a look at the client_access file:
# Block RFC 1918 networks 10 REJECT RFC 1918 address not allowed here 192.168 REJECT RFC 1918 address not allowed here # Known spammers 12.34.56.78 REJECT evil-spammer.example.com REJECT
What does all this mean? The first two non-comment lines are used to reject clients that appear to connect from the networks 10.0.0.0/8 and 192.168.0.0/16. These are not valid Internet addresses, so no legitimate client will connect from any of these addresses. The rejection will be made with the error message RFC 1918 address not allowed here. If your own clients have such RFC 1918 address you need to place a permit_mynetworks restriction before the check_client_access. Otherwise you will reject your own clients.
Indexed access maps support network block matching on even octet boundaries, but CIDR notation (as in 10.0.0.0/8) is not supported. If you need to specify network blocks with CIDR notation, consider the CIDR lookup table type available in Postfix 2.1 and later. Earlier releases can use a script such as cidr2access by Rahul Dhesi (http://www.rahul.net/dhesi/software/cidr2access) that expands CIDR blocks to a notation that is acceptable for indexed access maps.
Note how comments are used to explain why and when entries were added. This can be valuable if more than one person is maintaining the files.
The last lines are used to match a couple of notorious spammers (fictional, of course) and demonstrate that both complete IP addresses and hostnames are acceptable here. These rejections will be made with a generic error message.
Let us continue with another example:
smtpd_sender_restrictions = check_sender_access hash:/etc/postfix/sender_access
Contents of /etc/postfix/sender_access:
hotmail.com reject_unknown_client example.com permit_mynetworks, reject
If someone attempts to send a message with a hotmail.com sender address, the client attempting to deliver the message will be subject to the reject_unknown_client restriction which, as you might recall, rejects client that do not have a valid mapping between IP address and hostname.
The second line exemplifies a useful policy that only allows clients from your networks to use your domain in the sender address.
Finally, if you only use Postfix internally within your network and you have no need to allow anyone else to connect, the following two restrictions enforce this policy:
smtpd_recipient_restrictions = permit_mynetworks, reject
[edit] Implementing New Policies
Be careful when you implement new policies. Some of Postfix's restrictions are far too strict for general use and may reject significant amounts of legitimate e-mail. For each new restriction you plan to implement, examine the conditions under which messages are rejected and try to come up with cases where legitimate messages fulfill these conditions. To help you determine whether a restriction is safe to use, the warn_if_reject restriction can be used. This restriction affects the restriction that immediately follows it in the restriction list, and if the following restriction should have resulted in a rejection, it will be converted to a rejection warning. A rejection warning places a line in the mail log, but does not reject the message.
For example, you may want to evaluate the reject_unknown_client restriction because you have noticed that many spam messages are received from clients that do not have a reverse pointer in DNS, that is, there is no mapping from their IP address to a name that maps back to the IP address in question.
Here is one way of doing it:
smtpd_client_restrictions = warn_if_reject reject_unknown_client
This will result in log messages like this one:
Dec 31 16:39:31 jeeves postfix/smtpd[28478]: NOQUEUE: reject_warning: RCPT from unknown[222.101.15.127]: 450 Client host rejected: cannot find your hostname, [222.101.15.127]; from=<jdoe@example.com> to=<me@example.com> proto=SMTP helo=<222.101.15.127>
This log messages contains all known information about the envelope of the message, and this should hopefully be enough for you to decide whether a message was legitimate or not. After a few days, inspect your mail logs and try to determine whether the ratio between would-be rejected unwanted messages and would-be rejected legitimate messages is acceptable.
[edit] Using DNS Blacklists
Since 1997, the Domain Name System (DNS) has been used to thwart spam. The method, DNS-based Blackhole List (DNSBL) or Real-time Blackhole List (RBL), also known as blacklist or blocklist, uses the DNS to publish information about certain clients or sender domains. When a mail server such as your own is contacted by a client, your server can combine the client's IP address or the given sender address with the domain of one or more DNSBLs and perform a DNS lookup. If the address is listed by the DNSBL the lookup succeeds, and your server may choose to for example reject the client.
For example, let us say that you have configured Postfix to use the widely used relays.ordb.org blacklist. If a client with the address 1.2.3.4 connects, Postfix will look in DNS for an A record for the address 4.3.2.1.relays.ordb.org. If such a record exists, Postfix will not accept a message from the client.
Postfix supports three types of DNSBL lookups; client host address, client hostname, and sender domain. Each lookup type has a restriction of its own, and they all require that you specify the name of the DNSBL domain after the restriction name:
| DNSBL type | Syntax | Description |
|---|---|---|
| Client host address | reject_rbl_client rbl_domain
| The IP address of the connecting client is looked up. This is the original and by far most common DNSBL type. |
| Client hostname | reject_rhsbl_client rbl_domain
| The hostname of the connecting client is looked up. |
| Sender address domain | reject_rhsbl_sender rbl_domain
| The domain of the given sender address is looked up. |
Feel free to list multiple DNSBL restrictions. Make sure you use the restriction that corresponds to the DNSBL type using reject_rbl_client with a sender address domain DNSBL does not make sense.
The following code shows one way of configuring Postfix to use the relays.ordb.org standard-type DNSBL and the dsn.rfc-ignorant.org sender domain-DNSBL:
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination, reject_rbl_client relays.ordb.org, reject_rhsbl_sender dsn.rfc-ignorant.org
Notice how these restrictions are listed after both permit_mynetworks and reject_unauth_destination. This is because DNSBL lookups are comparatively expensive, and there is no use in wasting time on such lookups for your own clients or for clients that might get rejected anyway. To avoid unnecessary delays, be sure to list the DNSBLs that block the most messages first among your DNSBL restrictions.
[edit] Choosing DNS Blacklists
In the beginning, the DNSBLs only listed open relays, that is, SMTP servers that accept all messages from all clients to all destinations. Open relays once were the primary source of spam, but this has changed in recent years. Today, a lot of spam is sent from hijacked home computers of innocent and unknowing people.
Different block lists have different policies for listing hosts and removing listed hosts. Naturally, the bigger the blacklist, the more legitimate messages are you likely to reject. Before starting to use a particular DNSBL to reject messages, you should examine these policies carefully and preferably also try them out for a while without actually rejecting any messages. The warn_if_reject restriction can help you with this.
There is no single authoritative list of the best DNSBLs. The blocklists that work great for some people and reject huge amounts of spam but no legitimate messages may have little value for other people and may actually reject more legitimate messages than spam. Do not blindly copy allegedly good sets of DNSBLs from other sites.
Still, some general advice on a few useful client address DNSBLs (reject_rbl_client) is in order.
| Client Addresses | Description |
|---|---|
relays.ordb.org
| Lists only open relays. Will not block that much spam nowadays, but will not block many legitimate messages either. Currently blocks about 225,000 addresses. |
list.dsbl.org
| Lists open relays and open proxies. More aggressive than relays.ordb.org, but should be OK for most people. Currently blocks about 700,000 addresses.
|
sbl.spamhaus.org
| Does not list open relays or open proxies, but does list known spam sources. This includes IP addresses used by known spammers, or Internet Providers that are known to support spammers. |
xbl.spamhaus.org
| Lists open proxies, spam-sending worms on hijacked machines, and hosts that are in other ways exploited by spammers. This blocklist contains all entries in the cbl.abuseat.org and opm.blitzed.org DNSBLs, so you should not use xbl.spamhaus.org in conjunction with either of those two.
|
sbl-xbl.spamhaus.org
| This DNSBL combines the contents of the sbl.spamhaus.org and xbl.spamhaus.org zones. If you want to use both blocklists, using just this one will save you DNS lookups.
|
Before implementing any DNSBL at all, make sure you know how to exempt certain clients or domains from rejections. Sooner or later and no matter which DNSBL you choose to use you will have cases with legitimate messages being blocked. When that happens, it is too late to start digging in the documentation trying to find out what you can do about it.
The solution to the problem is to have whitelisting access maps before your DNSBL restrictions. Which type of access map you should use depends on the DNSBL type, but in most cases check_client_access will be suitable, although check_sender_access is more appropriate if you use reject_rhsbl_sender.
Continuing our previous example, this is what you can do to exempt certain clients and sender addresses from rejection by any following restrictions:
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination, check_client_access hash:/etc/postfix/rbl_client_exceptions, check_sender_access hash:/etc/postfix/rhsbl_sender_exceptions, reject_rbl_client relays.ordb.org, reject_rhsbl_sender dsn.rfc-ignorant.org
In /etc/postfix/rbl_client_exceptions:
# Added 2005-01-10 to avoid blocking legitimate mail. /jdoe 1.2.3.4 OK example.net OK
In /etc/postfix/rhsbl_client_exceptions:
mybusinesspartner.com OK
[edit] Stopping Messages Based on Contents
Sometimes, unwanted messages cannot be spotted without looking at their contents. Postfix provides some unsophisticated but still very useful tools for this purpose. The idea is that the lines in a message are matched against a set of regular expressions that you supply, and if there is a match an action will be carried out. Most often you use header and body checks to reject messages, but they can also be discarded or redirected to another recipient. Header and body checks can help you solve the following problems, all of which will be discussed in the following sections:
- Reacting to messages containing attachments with forbidden filenames
- Quickly stopping big virus outbreaks
- Custom logging of certain header fields
- Removing certain message headers
An introduction to regular expressions is beyond the scope of this book. If you do not have that knowledge already, there are many regular expression resources and tutorials on the net. If you are looking for a book on the topic, Jeffrey E. F. Friedl's Mastering Regular Expressions (O'Reilly, 2002) is quite comprehensive.
[edit] Configuring Header and Body Checks
The main.cf parameters body_checks, header_checks, mime_header_checks, and nested_header_checks can contain references to regular expression lookup tables (regexp or pcre), which will be considered when a message is being received. These parameters are used for different parts of the message:
| Parameter | Part of message it applies to |
|---|---|
body_checks
| The body of each message part. |
header_checks
| All non-MIME top-level headers. |
mime_header_checks
| All MIME headers found in any message part. The following headers are considered to be MIME headers: Content-Description Content-Disposition Content-ID Content-Transfer-Encoding Content-Type MIME-Version |
nested_header_checks
| All non-MIME message headers in messages that are attached to the received message. |
This means that for each header line, a lookup will be made against the lookup tables specified in header_checks, each line in the message body will cause a lookup against the lookup tables in body_checks, and so on.
As we will see soon, the format of regular expression lookup tables is very similar to ordinary indexed ones. One big difference is that these are not indexed and should not be run through the postmap program. Postfix will reread regular expression lookup tables when the daemons are restarted, which in many cases is often enough. If you want an immediate update, you must reload Postfix.
Regular expression lookup tables are not exclusively for header and body checks. They can be used wherever Postfix expects a lookup table.
The right-hand side of lookup tables used for header and body checks can contain many of the previously described actions allowed in access maps, but one action, IGNORE, is only available here. The IGNORE action simply removes the matched line from the message.
Message headers like the ones in the following example that are wrapped to form multiple physical lines will be joined together before being used as a lookup key.
Received: by jeeves.example.com (Postfix, from userid 100) id 2BB044302; Sat, 1 Jan 2005 20:29:43 +0100 (CET)
If possible, make sure your Postfix has support for the PCRE lookup table type. Regular expressions of the PCRE (Perl-Compatible Regular Expression) flavor have a richer syntax that allows some shortcuts. Another reason to use PCRE is that the PCRE library generally is faster than the standard regular expression library that the operating system provides. To check whether your Postfix supports the PCRE lookup table type, use the postconf command:
$ postconf -m static cidr nis regexp environ proxy btree unix hash pcre ldap sdbm
Great! This Postfix supports PCRE tables.
Most pre-built packages have PCRE support built in, but if you build Postfix yourself you will have to make sure you have the PCRE library installed before you build Postfix. Read http://www.postfix.org/PCRE_README.html for details.
[edit] Examples
Now, let us get concrete and take a look at how header and body checks can be used. Unless otherwise noted, these examples all work with both the regexp and the PCRE lookup table type. Many computer viruses spread by e-mail, and most of them through programs or scripts attached to the messages. Although reacting to messages containing attachments with forbidden filenames is a blunt and inexact tool, it is a simple way to take care of these unwanted messages even before they reach any antivirus scanner. By avoiding large-overhead scanning, your server can cope with much larger virus outbreaks. There is no complete list of the filenames that can be banned, but just blocking .exe, .scr, .pif, .bat, and a few more will probably suffice for most people. To implement this in Postfix, we need to recognize that the filename of an attachment is found in Content-Disposition or Content-Type headers. These are MIME headers, so the expression needs to go in mime_header_checks. In this example, the message is rejected with a message that indicates the offending filename. If a legitimate mail is rejected the sender will hopefully be able to interpret the error message and resend the message.
/^Content-(Disposition|Type).*name\s*=\s*"?(.*\.( ade|adp|bas|bat|chm|cmd|com|cpl|crt|dll|exe|hlp|hta| inf|ins|isp|js|jse|lnk|mdb|mde|mdt|mdw|ms[cipt]|nws| ops|pcd|pif|prf|reg|sc[frt]|sh[bsm]|swf| vb[esx]?|vxd|ws[cfh]))(\?=)?"?\s*(;|$)/x REJECT Attachment not allowed. Filename "$2" may not end with ".$3".
Note the indentation on all but the first line. It is needed to have the lines be treated as a single line. Lookup tables work in the same way as the main.cf and master.cf configuration files in this respect. The /x modifier will cause all whitespace to be ignored. This expression, originally constructed by Russell Mosemann and further refined by Noel Jones, requires a PCRE lookup table, but it is possible to rewrite the expression to use regexp.
body_checks can be a useful tool in quickly stopping big virus outbreaks. A number of the previous virus outbreaks have had messages with certain characteristics that made them pretty easy to block. If filename blocking is not an option, you can try to find lines that are unique to these messages and construct suitable expressions.
/^Hi! How are you=3F$/ REJECT SirCam virus detected. /^ I don't bite, weah!$/ REJECT Bagle.H virus detected.
If you are unsure whether an expression will be too broad and catch legitimate messages, you can use HOLD or WARN instead of REJECT. HOLD will put the messages on hold,
allowing you to examine them and either release the messages or delete them. WARN will accept the message but log the incident.
This method of blocking viruses can also be useful when a new virus is just starting to spread and the antivirus software you are using has not yet been updated to catch it.
The WARN action can also be used to get custom logging of certain header fields:
/^Subject: / WARN
Having this expression in header_checks will result in all subject headers being logged as a warning message similar to this:
Jan 2 00:59:51 jeeves postfix/cleanup[6715]: 6F8184302: warning: header Subject: Re: Lunch? from local; from=<jack@example.com> to=<jill@example.com>
Sometimes it can be useful to remove certain message headers. For example, some programming libraries that provide SMTP clients add an X-Library header to all messages sent. Apparently, many spammers use these libraries and therefore SpamAssassin gives a pretty high score for messages that contain this header. If you need to use such a library and you cannot or will not modify the source code to avoid having the header added in the first place, Postfix can help you remove it. This header_checks expression will remove all X-Library headers in messages passing through Postfix:
/^X-Library: / IGNORE
[edit] Caveats
Header and body checks are simple and blunt tools for inspecting message contents. They are useful for a number of things, but do not attempt to use them for general-purpose spam fighting. Many people try to use these tools incorrectly, and I will try to straighten out some common misconceptions.
Header and body checks will only inspect one line at a time, and no state is kept between different lines. This means that you cannot reject messages that contain one bad word on one line and another bad word elsewhere in the message. Do not be fooled by the if...endif construct allowed in regular expression lookup tables! You cannot use them in this way:
if /^From: spammer@example.com/ /^Subject: Best mortgage rates/ REJECT endif
Remember, lookups are made one line at a time. Obviously, a line that starts with From cannot possibly start with Subject.
Many spam messages have the mail body in Base64 encoding. Because of how Base64 works, a word has many possible Base64 representations. Postfix does not perform any decoding before the message contents is fed to the header and body checks.
This means that using body_checks to block messages containing bad words doesn't work universally. If body_checks is your only tool to fight spam, you will spend a couple of hours every day maintaining your regular expressions so they will catch the spam of the day, but you will still not reach a very high accuracy.
Header and body checks apply to all messages. You cannot whitelist a certain sender or a certain client. If you host multiple domains you have the option of using different header and body checks for your hosted domains by running multiple cleanup daemons and multiple smtpd daemons listening on different IP addresses.
You cannot use header and body checks to check for the nonexistence of something, so you cannot reject messages that have an empty body or messages that do not contain a secret password.
Having a large number of regular expressions in body_checks is not only a maintenance nightmare but may also seriously degrade the performance of your server. A reasonable configuration should not need more than, say, 10 20 expressions. If you have too many expressions, Postfix's cleanup processes will use a lot of CPU.
[edit] Additional References
- For instructions on Installing Postfix, click here.
- For instructions on Troubleshooting Postfix, click here
[edit] Source
The source of this content is Chapter 2: Setting Up Postfix of [1] by Patrick Ben Koetter, Carl Taylor, Magnus Back, Ralf Hildebrandt, David Rusenko, Alistair McDonald (Packt Publishing, 2005).

