Set Up SpamAssassin on CentOS/RHEL to Block Email Spam

Previously we discussed 7 effective methods for blocking email spam with Postfix on CentOS/RHEL. In this tutorial, we are going to learn how to use SpamAssassin (SA) to detect spam on CentOS/RHEL mail server. SpamAssassin is a free, open-source, flexible and powerful spam-fighting tool.

SpamAssassin is a score-based system. It will check email message against a large set of rules. Each rule adds or removes points in the message’s score. If the score is high enough (by default 5.0), the message is considered spam.

Set Up SpamAssassin on CentOS RHEL to Block Email Spam

Install SpamAssassin on CentOS/RHEL

Run the following command to install SpamAssassin from the default CentOS/RHEL software repository.

sudo dnf install spamassassin

The server binary installed by the spamassassin package is called spamd, which will be listening on TCP port 783 on localhost. Spamc is the client for SpamAssassin spam filtering daemon. By default, the spamassassin systemd service is disabled, you can enable auto start at boot time with:

sudo systemctl enable spamassassin

Then start SpamAssassin.

sudo systemctl start spamassassin

Integrate SpamAssassin with Postfix SMTP Server as a Milter

There are several ways you can use to integrate SpamAssassin with Postfix. I prefer to use SpamAssassin via the sendmail milter interface, because it allows me to reject an email when it gets a very high score such as 8, so it will never be seen by the recipient.

Install the spamass-filter packages on CentOS/RHEL from the EPEL software repository.

sudo dnf install epel-release
sudo dnf install spamass-milter

Start the service.

sudo systemctl start spamass-milter

Enable auto-start at boot time.

sudo systemctl enable spamass-milter

Next, edit /etc/postfix/ file and add the following lines at the end of the file.

# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:/run/spamass-milter/spamass-milter.sock
non_smtpd_milters = $smtpd_milters

If you have configured OpenDKIM and OpenDMARC on CentOS/RHEL, then these lines should look like below. The milter order matters.

# Milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:,inet:,unix:/run/spamass-milter/spamass-milter.sock
non_smtpd_milters = $smtpd_milters

If you haven’t configured OpenDMARC, then you should remove local:opendmarc/opendmarc.sock, from smtpd_milters.

Save and close the file. Now open the /etc/sysconfig/spamass-milter file and find the following line.

#EXTRA_FLAGS="-m -r 15"

Uncomment this line and change 15 to your preferred reject score such as 8.

EXTRA_FLAGS="-m -r 8"

If the score of a particular email is over 8, Spamassassin would reject it and you would find a message like below in the /var/log/maillog file, indicating it’s rejected.

milter-reject: END-OF-MESSAGE  5.7.1 Blocked by SpamAssassin

If you want the sender to see a different reject text, then add the -R (reject text) option like below.


It’s a good practice to ignore emails originating from localhost by adding the -i option.


We also need to add the -g sa-milt option to make the spamass-milter socket writable by the sa-milt group.

EXTRA_FLAGS="-m -r 8 -R SPAM_ARE_NOT_ALLOWED_HERE -i -g sa-milt"

Save and close the file. Then add postfix user to the sa-milt group, so that Postfix will be able to communicate with spamass-milter.

sudo gpasswd -a postfix sa-milt

Restart Postfix and Spamass Milter for the changes to take effect.

sudo systemctl restart postfix spamass-milter

Check the status and make sure they are running.

sudo systemctl status postfix spamass-milter

Checking Email Header and Body with SpamAssassin

SpamAssassin ships with many spam detection rules in /usr/share/spamassassin/ directory. Allow me to explain some of the rules.

In the /usr/share/spamassassin/ file, you can find the following two lines.

header MISSING_HEADERS       eval:check_for_missing_to_header()
describe MISSING_HEADERS     Missing To: header

The first line tests if the To: header exists in an email message. The second line, which is optional, explains what the first line does. The uppercase letters is the name of this test.

The following 3 lines are for testing if there’s a Date: header in the email message.

header __HAS_DATE            exists:Date
meta MISSING_DATE            !__HAS_DATE
describe MISSING_DATE        Missing Date: header

And these 3 lines are for testing if there’s a From: header in the email message.

header __HAS_FROM            exists:From
meta MISSING_FROM            !__HAS_FROM
describe MISSING_FROM        Missing From: header

Set Custom Score for Existing Rules

In the and file, you can see the default scores for various tests. If you think the default score is too low or too high for a certain test, you can set custom score in /etc/mail/spamassassin/ file.

sudo nano /etc/mail/spamassassin/

For example, RFC 5322 requires that every email message must have From: and Date: header fields, so I can set a very high score if either of them is missing in an email message by appending the following two lines in file.

score MISSING_FROM   5.0
score MISSING_DATE   5.0

Although the To: header field is not mandatory in RFC 5322, I prefer to set a high score if it’s missing in an email message because I have never seen a legitimate email missing this header field.


Some spammers uses two email addresses in the From: header field like below.

From: "[email protected]" <[email protected]>

I think the default score for this kind of email is low, I prefer to set it to 3.0.

score PDS_FROM_2_EMAILS 3.0

There are spammers who send empty message with no subject and no textual parts in the body. I set the score for this kind of email to 5.0, so it will be placed to spam folder. Why read it if it’s empty?


And other spammers often ask you to send a read receipt, I set the score to 2.0 for this kind of email.


There are some spammers use different domain names in the From: and Reply-To: header, I give them a 3.5 score.


I also have seen some spammers using non-existent domain name in the From: header field. I set a 5.0 score for this type of email.


Last but not least, many spammers spoof the domain in the From: header field. I set a 2.5 score this kind of email.


Adding Your Own Rules

You can add custom SpamAssassin rules in /etc/mail/spamassassin/ file.

sudo nano /etc/mail/spamassassin/

Header Rules

For example, some spammers use the same email address in the From: and To: header. you can add the following lines at the end of the file to add scores to such emails.

header   FROM_SAME_AS_TO   ALL=~/\nFrom: ([^\n]+)\nTo: \1/sm
describe FROM_SAME_AS_TO   From address is the same as To address.
score    FROM_SAME_AS_TO   2.0

Some spammers use an empty address for the Envelope From address (aka the Return Path header). Although this is legitimate for sending bounce messages, I prefer to give this kind of email a score.

header    EMPTY_RETURN_PATH    ALL =~ /<>/i
describe  EMPTY_RETURN_PATH    empty address in the Return Path header.
score     EMPTY_RETURN_PATH    3.0

If you have configured OpenDMARC on your mail server, you can now add the following lines to add scores to emails that fail DMARC check.

header    CUSTOM_DMARC_FAIL   Authentication-Results =~ /dmarc=fail/
describe  CUSTOM_DMARC_FAIL   This email failed DMARC check
score     CUSTOM_DMARC_FAIL   3.0

The above code tells SpamAssassin to check if the Authentication-Results header contains the string “dmarc=fail”. If found, increase the score by 3.0.

Body Rules

You can tell SpamAssassin to increase the score of an email if a certain phrase is found in the body. For example, many spammers use the recipient’s email address in the first body line like below.

Hi [email protected]
Hello [email protected]
Dear [email protected]

I don’t want to talk with people who doesn’t bother writing my name in the first line of email. So I created a rule in SpamAssassin to filter this kind of email.

body      BE_POLITE       /(hi|hello|dear) xiao\@linuxbabe\.com/i
describe  BE_POLITE       This email doesn't use a proper name for the recipient
score     BE_POLITE       5.0

Regular expression in SpamAssassin is case-sensitive by default, you can add the i option at the end to make it case-insensitive.

Add Negative Scores

You can also add negative score to good emails, so there will be less false positives. For example, many of my blog readers ask me Linux questions and I don’t think spammers would include words like Debian, Ubuntu, Linux Mint in the email body, so I created the following rule.

body      GOOD_EMAIL    /(debian|ubuntu|linux mint|centos|red hat|RHEL|OpenSUSE|Fedora|Arch Linux|Raspberry Pi|Kali Linux)/i
describe  GOOD_EMAIL    I don't think spammer would include these words in the email body.
score     GOOD_EMAIL    -4.0

If the email body contains a Linux distro’s name, then add a negative score (-4.0).

There are some common phrases that is included in legitimate bounce messages, so I can add negatives scores to these email messages.

body      BOUNCE_MSG    /(Undelivered Mail Returned to Sender|Undeliverable|Auto-Reply|Automatic reply)/i
describe  BOUNCE_MSG    Undelivered mail notifications or auto-reply messages
score     BOUNCE_MSG    -1.5

Note that body rules also include the Subject as the first line of the body content.

Meta Rules

In addition to header and body rules, there’s also meta rules. Meta rules are combinations of other rules. You can create a meta rule that fires off when two or more other rules are true. For example, I occasionally receive emails saying that the sender wants to apply for a job and a resume is attached. I have never said on my website that I need to hire people. The attachment is used to spread virus. I created the following meta rule to filter this kind of email.

body      __RESUME        /(C.V|Resume)/i
meta      RESUME_VIRUS    (__RESUME && __MIME_BASE64)
describe  RESUME_VIRUS    The attachment contains virus.
score     RESUME_VIRUS    5.5

The first sub rule __RESUME tests if the email body contains the word C.V. or resume. The second sub rule __MIME_BASE64 is already defined in /usr/share/spamassassin/ file, as follows, so I don’t need to define it again in file. This rule tests if the email message includes a base64 attachment.

rawbody   __MIME_BASE64  eval:check_for_mime('mime_base64_count')
describe  __MIME_BASE64  Includes a base64 attachment

My meta rule RESUME_VIRUS will fire off when both of the sub rules are true, adding a 5.5 score to the email message. Note that sub rule often starts with double underscore, so it has no score in its own right.

Now you learned how to add score if a string is found. What if you want to add score when a string doesn’t exist in the email headers? Well, you can use the ! operator. For example, I have seen spammers using a single word in the From: address.  I added the following lines to score this kind of email.

header __AT_IN_FROM   From =~ /\@/
score NO_AT_IN_FROM   4.0

The first line checks if the @ sign exists in the From: header. The second line defines a meta rule, which fires off when !__AT_IN_FROM is true. !__AT_IN_FROM rule is the opposite of the first header rule, which means when there’s no @ sign in the From: address, the meta rule fires off.

You can also add the following lines to check if a dot exists in the From: address.

header __DOT_IN_FROM   From =~ /\./
score  NO_DOT_IN_FROM  4.0


You can use the whitelist_from parameter to add a particular email address or domain to your Spamassassin whitelist. For example, add the following two lines at the end of file.

whitelist_from [email protected]
whitelist_from *

A whitelisted sender has a -100 default score. They will still be tested by SpamAssassin rules, but it’s super hard for them to reach a 5.0 score.


To blacklist a sender, use the blacklist_from parameter, which has the same format as whitelist_from.

blacklist_from [email protected]
blacklist_from *

Checking Syntax and Restart

After saving the file. You should run the spamassassin command in lint mode to check if there’s any syntax errors.

sudo spamassassin --lint

Then restart SpamAssassin for the changes to take effect.

sudo systemctl restart spamassassin

SpamAssassin’s Builtin Whitelist

It’s worth mentioning that SpamAssassin ships with its own whitelist. There are several files under /usr/share/spamassassin/ directory that includes 60_whitelist in the filename. These files contain SpamAssassin’s builtin whitelist. For example, the file contains a list of addresses which send mail that is often tagged (incorrectly) as spam.

Move Spam into the Junk Folder

I’m going to show you how to move spam to Junk folder with the Dovecot IMAP server and the sieve plugin. This method requires that inbound emails are delivered to the message store via the Dovecot “deliver” LDA (local delivery agent). If you can find the following text in /var/log/maillog file, then this requirement is satisfied.



delivered via dovecot service

Run the following command install dovecot-pigeonhole package from CentOS/RHEL software repository.

sudo dnf install dovecot-pigeonhole

This package installs two configuration files under /etc/dovecot/conf.d/ directory: 90-sieve.conf and 90-sieve-extprograms.conf. Open the 15-lda.conf file.

sudo nano /etc/dovecot/conf.d/15-lda.conf

Add the sieve plugin to local delivery agent (LDA).

protocol lda {
    # Space separated list of plugins to load (default is global mail_plugins).
    mail_plugins = $mail_plugins sieve

Save and close the file. If you can find the 20-lmtp.conf file under /etc/dovecot/conf.d/ directory, then you should also enable the sieve plugin in that file like below.

protocol lmtp {
      mail_plugins = quota sieve

Then open the 90-sieve.conf file.

sudo nano /etc/dovecot/conf.d/90-sieve.conf

Go to line 79 and add the following line, which tells Sieve to always execute the SpamToJunk.sieve script before any user specific scripts.

sieve_before = /var/mail/SpamToJunk.sieve

Save and close the file. Then create the sieve script.

sudo nano /var/mail/SpamToJunk.sieve

Add the following lines, which tells Dovecot to move any email messages with the X-Spam-Flag: YES header into Junk folder.

require "fileinto";

if header :contains "X-Spam-Flag" "YES"
   fileinto "Junk";

Save and close the file. We can compile this script, so it will run faster.

sudo sievec /var/mail/SpamToJunk.sieve

Now there is a binary file saved as /var/mail/SpamToJunk.svbin. Edit the 10-mail.conf file.


Add the following line in the file, so that individual user’s sieve scripts can be stored in his/her home directory.

mail_home = /var/vmail/%d/%n

Finally, restart dovecot for the changes to take effect.

sudo systemctl restart dovecot

Set Message Maximum Size

By default, SpamAssassin does not check messages with attachments larger than 500KB, as indicated by the following line in the /var/log/mail.log file.

spamc[18922]: skipped message, greater than max message size (512000 bytes)

The default max-size is set to 512000 (bytes). A high value could increase server load, but I think the default size is a little bit small. To increase the max-size, edit /etc/sysconfig/spamass-milter file and find the following line.

EXTRA_FLAGS="-m -r 8 -R SPAM_ARE_NOT_ALLOWED_HERE -i -g sa-milt"

Add the -- --max-size=5120000 option at the end.

EXTRA_FLAGS="-m -r 8 -R SPAM_ARE_NOT_ALLOWED_HERE -i -g sa-milt -- --max-size=5120000"

The empty -- option tells spamass-milter to pass all remaining options to spamc, which understands the --max-size option. I increased the size to 5000KB. Save and close the file. Then restart spamass-milter.

sudo systemctl restart spamass-milter

How to Configure Individual User Preferences

You may want to set custom rules for emails sent to a specific address on the mail server. I like this feature very much. I have a contact email address for this blog, which is only used for keeping contact with readers. I don’t use the contact email address elsewhere, so I can create special spam-filtering rules that apply only to this contact email address.

First, edit the SpamAssassin main configuration file.

sudo nano /etc/mail/spamassassin/

Add the following line to allow user rules.

allow_user_rules 1

Save and close the file. Next, edit the SpamAssassin environment file.

sudo nano /etc/sysconfig/spamassassin

Find the following line.

SPAMDOPTIONS="-c -m5 -H --razor-home-dir='/var/lib/razor/' --razor-log-file='sys-syslog'"

We need to add several extra options.

SPAMDOPTIONS="-c -m5 -H --razor-home-dir='/var/lib/razor/' --razor-log-file='sys-syslog' --nouser-config --virtual-config-dir=/var/vmail/%d/%l/spamassassin --username=vmail"


  • --nouser-config: disable per-user configuration file for local Unix users.
  • --virtual-config-dir: specify the per-user configuration directory for virtual users. The %d placeholder represents the domain part of email address and %l represents the local part of email address.
  • --username: run spamd as the vmail user.

Save and close the file. Then restart SpamAssassin.

sudo systemctl restart spamassassin

By default, spamass-milter doesn’t pass the recipient address to SpamAssassin. We need to make it send the full email address to SpamAssassin. Edit the spamass-milter configuration file.

sudo nano /etc/sysconfig/spamass-milter

Add the following option.

-e -u sa-milt

Like this:

EXTRA_FLAGS="-e -u sa-milt -m -r 8 -R SPAM_ARE_NOT_ALLOWED_HERE -i -g sa-milt -- --max-size=5120000"

The -e option will make spamass-milter pass the full email address to SpamAssassin. Replace with your real domain name. Save and close the file. Then restart spamass-milter.

sudo systemctl restart spamass-milter

Now send an email from Gmail, Hotmail, etc. to your domain email address. You will find the spamassassin directory is automatically created under /var/vmail/ directory.

cd /var/vmail/

You can use a command-line text editor to create the per-user preference file here. This file must be named as user_prefs.

sudo nano user_prefs

You can add custom rules in this file just as you would do in the /etc/spamassassin/ file.

For instance, I found many spammers end their email body with an unsubscribe link to let you remove future contact. I didn’t subscribe to their spam and I don’t think the unsubscribe link will remove my email address from their contact database. So I use SpamAssassin to score this kind of email.  The following rule adds 3.0 score to emails containing the word “unsubscribe” or its variations in the body. (I don’t use the contact email address of this blog to subscribe to anything online.)

body      SUBSCRIPTION_SPAM   /(unsubscribe|u n s u b s c r i b e|Un-subscribe)/i
describe  SUBSCRIPTION_SPAM   I didn't subscribe to your spam.
score     SUBSCRIPTION_SPAM   3.0

Sometimes the email body doesn’t contain the word “unsubscribe”, but the there’s a List-Unsubscribe header, which means the spammer added my contact email address to their mailing list without my consent. I can score this type of email too, with the following rule.

header    LIST_UNSUBSCRIBE   ALL =~ /List-Unsubscribe/i
describe  LIST_UNSUBSCRIBE   I didn't join your mailing list.
score     LIST_UNSUBSCRIBE   2.0

I created a Mailjet account with a different email address. Some spammers assume that I used my contact email address to create Mailjet account, so they try to impersonate Mailjet customer service to lure me into typing my password at a fake Mailjet login page. I can score this kind of email like below.

header    MAILJET_IMPOSTER   From =~ /mailjet/i
describe  MAILJET_IMPOSTER   I don't have a mailjet account for this email address.
score     MAILJET_IMPOSTER   2.5

The above lines check if the From: header contains the word mailjet. If found, give it a 2.5 score.

I occasionally receive emails from Chinese spammers whose From: domain name has no vowel letters (a, e, i, o, u). The spammer used the domain name. It is nearly impossible for a normal person/entity to use domain names without vowel letters, considering that many top level domains have already included vowel letters (.com, .net, .org, .co, .io, .shop, .dev, etc), so I give this kind of email a very high score like below. The default score is 0.5.


Some spam emails use many images in the body but contains very little text. The default score for this kind of email is 1.9, but I prefer to set a high score for my contact email address.

score HTML_IMAGE_RATIO_02 4.0

I also received a spam email with my email address in the subject, so I can add a high score to it.

header    SUBJECT_SPAM   Subject =~ /xiao\
describe  SUBJECT_SPAM   Subject contains my email address.
score     SUBJECT_SPAM   4.0

Some spammers use BCC (Blind Carbon Copy) to hide other recipients. I don’t want to receive such email. So I made the following rule. If my domain name is not in the To: header, add 3.0 to the email.

header __DOMAIN_IN_TO     To =~ /
score  DOMAIN_NOT_IN_TO   3.0

After adding custom rules, close the file and run the following command to check syntax. Silent output means there’s no syntax error.

sudo spamassassin --lint

Finally, restart SpamAssassin for the changes to take effect.

sudo systemctl restart spamassassin

Now you can test the user preferences by sending test emails from other email services to your own domain email address.

Reject or Bounce

If a receiving SMTP server determines during the SMTP conversation that it will not accept the message, it rejects the message. Sometimes the SMTP server accepts a message and later discovers that it cannot be delivered, perhaps the intended recipient doesn’t exist or there is a problem in the final delivery. In this case, the SMTP server that has accepted the message bounces it back to the original sender by sending an error report, usually including the reason the original message could not be delivered.

You should not bounce spam, because the email address in the Return-path: header or From: header probably doesn’t exist or is an innocent person’s email address, so the bounce message will probably go to an innocent person’s email address, creating the backscatter problem. Instead of bouncing the spam, you should reject spam during the SMTP dialog, before the email is accepted. This article didn’t show you bouncing a spam message. You should remember this rule in case you are going to create spam-filter rules by yourself. If in doubt, test your spam-filtering rules to see if it’s going to create bounce messages.


By default, SpamAssassin enables URIBL rule, which checks if an email message contains links that are identified as spam by URIBL. This is a very effective anti-spam measurement. However, you might be blocked from querying URIBL. Check the raw email headers of an inbound email message, find the X-Spam-Status header.

X-Spam-Status: No, score=-92.2 required=5.0 tests=DATING_SPAM,DKIM_SIGNED,
	autolearn=no autolearn_force=no version=3.4.2

If you can find URIBL_BLOCKED in this header, that means you are blocked from querying URIBL. Most of the time it’s because you are not using your own local DNS resolver. You can run the following command on your mail server to test which DNS server you are using to query URIBL.

host -tTXT

Sample output: descriptive text " -> Query Refused. See for more information [Your DNS IP: xx.xx.xx.xx]"

To fix this error, you need to run your own local DNS resolver on your mail server.

Once your local DNS resolver is up and running, test URIBL again.

host -tTXT

If you see the following output, it means you are now allowed to query URIBL. descriptive text "permanent testpoint"

From here on out, inbound email messages won’t have the URIBL_BLOCKED tag in the X-Spam-Status header.

Other Tidbits

SpamAssassin 4.0 includes a HashBL plugin, which can check if a Bitcoin address in the email body has been used by scammers. And there’s also a new plugin called “Ole Macro” that can check if an email contains an Office attachment with a macro. This plugin would try to detect if the attched macro is malicious or not.

Wrapping Up

I hope this tutorial helped you use Postifix and SpamAssassin to filter spam. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂

Rate this tutorial
[Total: 6 Average: 5]

40 Responses to “Set Up SpamAssassin on CentOS/RHEL to Block Email Spam

  • Hi Xiao,

    Nice post. You have a type: “If you see the following output, it means you are now allowed to query URIBL.”, should be “you are allowed”.

    • Xiao Guoan (Admin)
      4 years ago

      I think “you are now allowed” isn’t very different from “you are allowed”. 🙂

  • Hi,

    Keep getting error:

    connect to Milter service unix:/run/spamass-milter/spamass-milter.sock: No such file or directory

    File is there, group is ok and even 777 the file just in case.

    ¿Any suggestions?

    OS: CentOS 8

    • Same problem here as well. Centos 8.

      connect to Milter service unix:/run/spamass-milter/spamass-milter.sock: No such file or directory

      All look normal to me. The sock file is there. Could it be postfix is trying to access it before spamass-milter is ready?

    • Also keep getting this error:
      CentOS 8

      connect to Milter service unix:/run/spamass-milter/spamass-milter.sock: No such file or directory

      Any ideas what could be causing this.

      • Y. Uchida
        4 years ago

        In my case, it was the chroot of the “submission” and “smtps” services.
        (No problem with simple smtp)

        Of course, when chrooted, these processes can not find the socket file.

        I changed chroot flag to ‘n’ in
        and restarted postfix.

          submission inet n       -       n       -       -       smtpd
          smtps     inet  n       -       n       -       -       smtpd

        Then that warning message disappeared.

        Hope this may help you.

        • Timmo
          2 years ago

          This worked for me, thanks for posting this! Maido!

  • Erick Coronell
    4 years ago

    I have followed every post about configuring the email server on Cento 8 from scratch, but I have some issues with SpamAssasing, I haven’t found any SpamAssassin folder on /var/vmail/

    Another issue I have is how to configure POP3 on Dovecot?

    • Xiao Guoan (Admin)
      4 years ago

      Maybe you should receive some emails from outside, then the spamassassin folder will be automatically created?

      To enable POP3 in Dovecot. First, edit main config file.

      sudo nano /etc/dovecot/dovecot.conf

      add the POP3 protocol.

      protocols = imap pop3 lmtp

      Save and close the file. Then restart Dovecot.

      sudo systemctl restart dovecot

      Next, add the pop3 and pop3s services in firewalld.

      sudo firewall-cmd --permanent --add-service={pop3,pop3s}

      Reload firewalld for the change to take effect.

      sudo systemctl reload firewalld
  • Hi Xiao,

    Great mail server articles, been following most of them and even though I have most of the things set, I still learn something useful. Keep up the good work!

    I noticed that you do not have a separate article for ClamAV or other AV on mail servers. Do you use such software or you do not generally recommend it (considered the amount of RAM used).

    Thanks in advance!

    • Xiao Guoan (Admin)
      4 years ago

      I don’t use ClamAV on my personal email server, because

      1.) Many emails containing viruses are being blocked by the spam filters in my articles. If I receive an email with an executable file in the attachment, it’s very easy for me to spot if it contains viruses.

      2.) ClamAV uses a fair amount of RAM (about 800MB). Some folks can’t access the mail server after installing ClamAV, because RAM is running out.

      However, if you set up a mail server for a company/organization, you can’t expect every user to be tech-savvy, so it’s a good practice to install a virus filter.

      I think I will publish an article for ClamAV in the near future.

    4 years ago


    I have followed your article, but i have one confusion that when I am checking status of spamass-milter service it showing as follows “spamass-milter 0.4.0 starting” in red colour, so i was wondering it is actually started or if i configured something wrong, thanks

    • Xiao Guoan (Admin)
      4 years ago

      It’s not an error.

      • Abhijit Roy
        4 years ago

        Hi, thanks for your response, I was just wondering that it should appear like normal messages like that milter service is started rather “starting”, as milter is new for me, can u please tell me that what is the actual advantages of milter instead of spamassasin, in addition with that i am facing following two errors:

        1. when i am checking with mailq commands it is showing message like “[private/dovecot-lmtp] said: 451 4.3.0 Invalid user settings. Refer to server log for more information. (in reply to RCPT TO command))”, and my mailq is filling up with unnecessary messages, and it generating automatically, what is the reason, is it due to some misconfigured settings in dovecot/lmtp, though i have followed as per your article, can u please help??

        I am also getting message in my maillog as “lmtp(16607): Disconnect from local: Connection closed (in RSET)”

        2. Automatic Spam to Junk is also not working, it was working initially for some time, but automatically stopped working, is there any way way to diagnose this error.

        Thanks for your cooperation.

        • ABHIJIT ROY
          4 years ago

          Hi, I urjently require your opinion regarding this, please response

    • Xiao Guoan (Admin)
      4 years ago

      The spamass-milter package is not a replacement for spamassassin. It’s a way to integrate Postfix with SpamAssassin.

      If you don’t know what’s wrong in your Dovecot configuration, you can add the following line in the /etc/dovecot/dovecot.conf file,


      then restart dovecot, so dovecot will produce more verbose debugging message in the /var/log/maillog file.

        4 years ago

        I have already enabled debugging in dovecot, but still there is no trace why this spam to Junk is not working, is there any permission require to run that .sieve script or can u please highlight what may be the possible cause

        • Abhijit Roy
          4 years ago

          Hi Xiao,

          But I have to say overall it is very helpful article, though I do not understand why spam to junk is not consistent, i checked in log in detail that sieve scrip is running in back end, but why spam to junk is not working do not understand, please help if u can.

  • Edward Burr
    4 years ago

    Hello, I’ve been using your articles in configuring my new Centos 8 server and have found them incredibly helpful.

    I am getting an error when starting spamassassin:
    spamd[3763146]: razor2: razor2 check failed: No such file or directory razor2: Can’t read: /var/lib/razor/ at /usr/share/perl5/vendor_perl/Mail/SpamAssassin/Plugin/ line 331.

    And the only reference I’ve found to the non-existant /var/lib/razor/ directory is in the default /etc/sysconfig/spamassassin which you modify above. Can you tell me what provides /var/lib/razor/ on your system?

    A dnf search gives me only perl-Razor-Agent.x86_64 which is already installed and does not seem to provide what is needed.


    • I ran into the same issue, same error with razor.
      No definite answer available anywhere, but with the bits and pieces I found, I managed to get rid of the error message. Not sure whether it actually works now, but that’s for later.
      Locate razor on your system (maybe update your db first)

      sudo updatedb
      locate razor

      On my system it showed:


      Next, I changed /etc/sysconfig/spamassassin:

      SPAMDOPTIONS="-c -m5 -H --razor-home-dir='/var/spool/amavisd/.razor/' --razor-log-file='sys-syslog'"

      When restarting spamassassin, the error is gone.

    • someguy
      3 years ago

      razor-admin -home /var/lib/razor -create
      razor-admin -home /var/lib/razor -discover
      razor-admin -home /var/lib/razor -register

  • GumShoeNoir
    4 years ago

    FWIW – I noticed this in maillog

    Could not retrieve sendmail macro "_"!.  Please add it to confMILTER_MACROS_CONNECT for better spamassassin results

    I fixed it with this in;

    milter_connect_macros = j {daemon_name} v {if_name} _ 

    restart postfix

  • When I add the parameter –razor-home-dir=’/var/lib/razor/’ –razor-log-file=’sys-syslog’ under the /etc/sysconfig/spamassassin file, my spamassassin program It won’t start up. What is the reason?

    • Xiao Guoan (Admin)
      3 years ago

      Check spamassassin journal to debug.

      sudo journalctl -eu spamassassin
      • any hint, how to fix this?

        razor2: razor2 check failed: No such file or directory razor2: Can’t read: /var/lib/razor/ at /usr/share/perl5/vendor_perl/Mail/SpamAssassin/Plugin/ line 331, line 2245.

        really awesome tutorials !!!

  • Hi,

    May I know is the settings for spamassassin in this articles work for one setup with amavisd? Any difference between the two?

    Thank you.

    • Xiao Guoan (Admin)
      3 years ago

      Yes. It works with Amavisd. SpamAssassin is the spam detection software. Amavis (A Mail Virus Scanner) is the interface between Postfix and content filters (such as SpamAssassin and ClamAV). Amavis is not spam detection software.

  • sf linux
    3 years ago

    you may want to fix snytax .

    “-R is invalid”

    very good post i have ot say.

  • Linux Dan
    3 years ago

    “Move Spam into the Junk Folder – I’m going to show you how to move spam to Junk folder with the Dovecot IMAP server”

    What about for a server without Dovecot that is a relay only ?

    • Xiao Guoan (Admin)
      3 years ago

      Since a relay-only SMTP server doesn’t have a message store in the first place, there’s no point in moving spam into the junk folder, because there’s no junk folder.

      • Linux Dan
        3 years ago

        I understand that, but what about saving it for analysis ?

        I am still learning Postfix. How might I redirect relected messages into the hold_queue ?

  • Linux Dan
    3 years ago

    About the configuration:

    SPAMDOPTIONS="-c -m5 -H --razor-home-dir='/var/lib/razor/' --razor-log-file='sys-syslog'"

    I am working behind firewalls and proxys.
    “Razor” wants to connect to Something Out There.
    How essential is it, or am I OK disabling it ?

  • Nicholas
    3 years ago


    i have such warnings.

    warning: connect to Milter service inet: Connection refused
    warning: connect to Milter service unix:/run/spamass-milter/spamass-milter.sock: No such file or directory

    So i removed inet: and restart postfix. Will this cause anything to break?

    • Xiao Guoan (Admin)
      3 years ago

      Port 8893 is for OpenDMARC.

      If you have set up OpenDMARC, then you need to add inet: If you didn’t, then you can remove it.

  • Nicholas
    3 years ago

    Thanks. So i installed OpemDMARC and getting a new error:-

    Could not retrieve sendmail macro “i”!. Please add it to confMILTER_MACROS_ENVFROM for better spamassassin results

  • Thanks for your articles on setting up the email server. I’ve followed them all to this point and I love the way you explain how/why rather than just giving the commands.

    I did run into an issue on the part where it says to add:
    SPAMDOPTIONS=”-c -m5 -H –razor-home-dir=’/var/lib/razor/’ –razor-log-file=’sys-syslog’ –nouser-config –virtual-config-dir=/var/vmail/%d/%l/spamassassin –username=vmail”

    Spamassassin won’t start after adding this to the config. I checked the journalctl and it says:

     Unknown option: razor-home-dir Unknown option: razor-log-file 

    Then has a list of Options that are available, but neither of these options show in the list. If I take those options out, it starts, but it doesn’t create the spamassassin folder in my users mail directories.

  • Wolfgang
    1 year ago


    congratulations for this howto. It is amazing.

    there are still some things I cannot get fixed. E.g. I get this warning

    warning: connect to Milter service inet: Connection refused
    warning: connect to Milter service unix:/run/spamass-milter/spamass-milter.sock: No such file or directory

    The file seems to exist though

    ls -al /run/spamass-milter/spamass-milter.sock
    srw-rw—-. 1 sa-milt sa-milt 0 Feb 8 20:07 /run/spamass-milter/spamass-milter.sock

    Further up you state that port for opendkim is 8893. I believe that is cont correct. The port for opendkim is 8891.
    Is 8893 really required?

    Thanks for your insight.


    • Check etc/postfix/

      You probably have chroot enabled

  • Hasanuzzaman Sattar
    1 year ago

    Hello Xiao,

    Thank you very much writing incredible tutorial. Everything I configured and running exactly according to this tutorial. But moving spam emails to Junk folder is not working. I am getting spam mails with header like below but still shwoing in the Inbox.

    X-Spam-Flag: YES
    X-Spam-Status: Yes, score=4.6 required=2.0 tests=CUSTOM_DMARC_FAIL,DKIM_SIGNED,
        UNPARSEABLE_RELAY autolearn=no autolearn_force=no version=3.4.0
        * -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at, no
        * trust
        * [ listed in]
        * 3.0 CUSTOM_DMARC_FAIL This email failed DMARC check
        * 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail
        * domains are different
        * -0.0 SPF_PASS SPF: sender matches SPF record
        * 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record
        * 1.5 MPART_ALT_DIFF_COUNT BODY: HTML and text parts are different
        * 0.0 HTML_IMAGE_RATIO_02 BODY: HTML has a low ratio of text to image area
        * 0.0 HTML_MESSAGE BODY: HTML included in message
        * -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's
        * domain
        * -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
        * 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily
        * valid
        * 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines
    X-Spam-Level: ****
    X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on 

    I don’t know why the mail is not moved in the Junk folder. I can’t see any of the following in my /var/log/maillog file.

    delivered via dovecot service

    Please help me.

  • To anybody getting this warning…

    warning: connect to Milter service inet: Connection refused

    Check if the port is being listened on…

    netstat -ntlp | grep 8893

    If it shows nothing open


    and look for the Socket line

    ##  Socket socketspec
    ##      default (none)
    ##  Specifies the socket that should be established by the filter to receive
    ##  connections from sendmail(8) in order to provide service.  socketspec is
    ##  in one of two forms: local:path, which creates a UNIX domain socket at
    ##  the specified path, or inet:port[@host] or inet6:port[@host] which creates
    ##  a TCP socket on the specified port for the appropriate protocol family.
    ##  If the host is not given as either a hostname or an IP address, the
    ##  socket will be listening on all interfaces.  This option is mandatory
    ##  either in the configuration file or on the command line.  If an IP
    ##  address is used, it must be enclosed in square brackets.
    Socket local:/run/opendmarc/opendmarc.sock

    Change Socket line to…

    Socket inet:8893@localhost
    systemctl restart opendmarc

    This fixed it for me on Rocky 8.

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community ( for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.

The maximum upload file size: 2 MB. You can upload: image. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here