Background
This article is based on the server running cPanel/WHM, the website CMS is WordPress with Divi as it's template, but the logic will most likely apply to a lot of other platforms.
Issue
I have a contact form that will not send the emails when the submitted details contain a free email address even though the contact form says the message was sent.
The failed emails do not appear in "Track Delivery" in cPanel so I have nothing to inspect and figure out what is going on.
If you do not manage your emails locally then an emails that are sent but are bounced will be returned to the server defined in the MX entry.
Cause
- Outbound emails are being scanned for SPAM by SpamAssassan (spamd).
- The email in the `Email Address` field on a Divi contact form is used by default for the
<reply-to>
header. - Emails with freemail addresses present in the header score extra SPAM points.
- Because of the extra points caused by having freemail addresses present, the emails are scored just above the SPAM score threshold and they become flagged as SPAM.
- Flagged emails are modified and then delivered to the
system
mailbox in cPanel, they are never passed to the MTA (Exim).
- The modification and redirects are performed by
spamd
. - cPanel "Track Delivery" shows transactions by Exim, but because the email never gets to Exim, there will be no record of the delivery or transport of the email.
- A modified email in the
system
mailbox might look something similar to this:
### Title ### Mail failure - rejected by local scanning code ### Message Body ### A message that you sent was rejected by the local scanning code that checks incoming messages on this system. The following error was given: This message was classified as SPAM and may not be delivered ------ This is a copy of your message, including all the headers. ------ .....
- The modification and redirects are performed by
Solutions
These are some solutions an workarounds, pick which ever best suits your needs, which ever you pick you should monitor the situation for a while to make sure the changes you implement are working as expected.
Use SMTP plugin for WordPress
- Using this method reduces the outbound SPAM score massively
- Requires you to setup an email account for every website. Do not use the cPanel system account for emails as this is a security risk.
- Your server does not need to handle email for the domain for you to be able to create an email account locally and send from it as normal, however I do recommend you make sure the SPF record is correctly set and that DKIM is not going to be an issue.
- My recommended plugin is: FluentSMTP | WordPress.org
Remove the Freemail address from the email header
- When using Divi, the email address on a contact form is used by default as the reply address Moving the client's email address to the content only would most likely reduce the SPAM score below 5 and therefore all the email to be sent.
- In Divi you would use Message Patterns to alter the content of the email.
Increase the outbound SPAM score threshold
- This change would be global
- WHM --> Exim Configuration Manager --> Basic Editor --> Apache SpamAssassin Options -->
- Scan outgoing messages for spam and reject based on the Apache SpamAssassin™ internal spam_score setting: Off
- Scan outgoing messages for spam and reject based on defined Apache SpamAssassin™ score: 8.5
- Do not forward mail to external recipients if it matches the Apache SpamAssassin™ internal spam_score setting: Off
- Do not forward mail to external recipients based on the defined Apache SpamAssassin™ score: 8.5
NB: 8.5 = Default Threshold + PHP_SCRIPT + KAM_COUK
Disable outbound SPAM scanning
- This change would be global.
- This is not the preferred method as there is not outbound SPAM checking which can allow abuse.
- WHM --> Exim Configuration Manager --> Basic Editor --> Apache SpamAssassin Options -->
- Scan outgoing messages for spam and reject based on the Apache SpamAssassin™ internal spam_score setting: Off
- Scan outgoing messages for spam and reject based on defined Apache SpamAssassin™ score: Disabled
- Do not forward mail to external recipients if it matches the Apache SpamAssassin™ internal spam_score setting: Off
- Do not forward mail to external recipients based on the defined Apache SpamAssassin™ score: Disabled
Disable certain SpamAssassin tests
You can reduce the SPAM score by disabling or cancelling out certain tests, but this requires a lot more time to setup.
Notes
WordPress - Email subsystem
- mail()
- The
mail()
function on returns True or False. - An Essential Guide to PHP mail() Function By Examples - This tutorial shows you how to use the PHP mail() function to send email messages in plain text and HTML formats.
- The
- Email Logging
- A Simple Guide to WordPress Email Logging - MailPoet - Wondering what emails WordPress sends and how to log them? In this guide, we'll take you through how to set up WordPress email logging.
- How to Fix Could Not Instantiate Mail Function in WordPress - In this guide, we’ll show you how to fix could not instantiate mail function error in WordPress, ensuring your emails fly out without a hitch!
- Code Walk through
## wordpress/wp-includes/PHPMailer/PHPMailer.php 'instantiate' => 'Could not instantiate mail function.', --> mailPassthru($to, $subject, $body, $header, $params) --> $result = @mail($to, $subject, $body, $header, $params); --> mail() # This is a wrapper for sendmail --> sendmail # cpanel sendmail is blocking gmail addresses --> sendmail returns true or false
WHM - Settings
- General
- How to Adjust Spam Assassin Rule Scoring Serverwide – cPanel - Spam Assassin determines whether or not a message is spam based on the message's final calculated spam score. The overall score is calculated by testing the message against various rules, each assigning a sub-score, and then summing the sub-scores. If you find that specific Spam assassin rules are weighted too heavily or are not weighted enough, you may use the procedure in this guide to change them.
- Apache SpamAssassin™ Options - Exim Configuration Manager Basic Editor | cPanel & WHM Documentation
- Select the Basic Editor tab in the Exim Configuration Manager interface to modify your server's Exim configuration settings.
- This particular section explains all of the Apache options.
- Tutorial
- Spam Filtering on cPanel: Everything You Need To Know About SpamAssassin | cPanel - Spam is a huge challenge for anyone who hosts email, even though users only see a tiny fraction of the spam they’re sent. Most unwanted messages never reach inboxes, but an incredible 54 percent of all email traffic is spam, and that’s down from 70 percent a decade ago.
- cPanel / WHM | SPAMAssassin and cPanel | VPSBlocks Support - This tutorial describes how to use the SpamAssassin tool in cPanel to reduce the amount of unwanted e-mail.
- SpamAssassin’s internal spam_score
- Is calculated by summing the scores of various matched rules.
- This is not the SPAM threshold, but just the score that SpamAssassin assigns to the email after all of the tests.
- How to Configure SpamAssassin in cPanel – PhilmoreHost
- Configuring your internal SpamAssassin score threshold = Specify a score under Apache SpamAssassin bounce spam score threshold. ?
- cPanel Tutorial Series 6: using email - TransIP - This is the sixth part of our cPanel Tutorial Series.
- Apache SpamAssassin ™ reject spam score threshold
- Incoming messages that are designated as spam are stopped instead of subjects being rewritten (see Filters), or the mail is moved to your spam box. You will never see messages that meet these criteria in your mail. If you use this option, we advise you to use a fairly generous score so only messages that are definitely spam are stopped, for example with a score of 10-11.
- Apache SpamAssassin ™ bounce spam score threshold
- Sends a bounce email to the sender of spam when mail reaches the set score. This can work positively and negatively: a conscious spammer knows that you are using a filter and will try to find something to work around it, but someone with an infected computer / server will find out more quickly that he or she has an infected computer / server thanks to a bounce message.
- Scan outgoing messages for spam and reject based on the Apache SpamAssassin ™ internal spam_score setting
- Scans all outgoing messages from your VPS and stops all messages that reach the set spam score (default 5).
This is a very useful option that we highly recommend. For example, suppose you created cPanel accounts for your customers and they host their own sites but never update them, then there is a plausible chance that sooner or later a vulnerability will be found, and a domain will start sending spam. Thanks to this option, you get rid of that spam, so your VPS does not get a bad IP reputation.
- Scans all outgoing messages from your VPS and stops all messages that reach the set spam score (default 5).
- Scan outgoing messages for spam and reject based on defined Apache SpamAssassin ™ score
- This option does the same as the previous one, but this allows you to determine the spam score upon which SpamAssassin takes action when outgoing mail is recognized as spam.
- Do not forward mail to external recipients if it matches the Apache SpamAssassin ™ internal spam_score setting
- Mail that is addressed to your VPS and which is redirected is also scanned by SpamAssassin and stopped if it is marked as spam.
- Do not forward mail to external recipients based on the defined Apache SpamAssassin ™ score
- Same as the previous option but allows you to set a score yourself.
- Score
- By default, SpamAssassin marks mail as spam when it reaches a score of 5. This base value can only be adjusted via command line using the following commands:
sudo nano /etc/mail/spamassassin/local.cf
- The particular rule to alter is:
# Set the threshold at which a message is considered spam (default: 5.0) # # required_score 5.0
- By default, SpamAssassin marks mail as spam when it reaches a score of 5. This base value can only be adjusted via command line using the following commands:
- Apache SpamAssassin ™ reject spam score threshold
- acl_not_smtp and acl_smtp_data
- Both acl_not_smtp and acl_smtp_data can count towards the Apache SpamAssassin™ internal spam_score setting, depending on how your Exim configuration is set up.
- There is no proper documentation from cPanel for these options.
- Ypu can expose the underlying code in the GUI by using the 'Advanced Editor'.
- acl_not_smtp:
- outgoing_spam_scan (Scan outgoing messages for spam and reject based on the Apache SpamAssassin™ internal spam_score setting)
- This refers to Exim's Access Control Lists (ACLs) that apply to non-SMTP email submissions, such as mail sent from local scripts or PHP applications. This is often used to set rules for handling outbound mail generated by websites, contact forms, or local applications.
- Purpose: To control and filter outgoing email messages that are not sent via SMTP, such as web apps or local daemons.
- Advanced Settings (Under Advanced editor):
warn condition = ${if forany{<, $recipients}{!match_domain{${domain:$item}}{:+relay_domains}}} set acl_m_outbound_recipient = 1 warn condition = $acl_m_outbound_recipient condition = ${if <={$message_size}{1000K}} condition = ${if !eq{$originator_uid}{0}} condition = ${perl{spamd_is_available}} set acl_m_spam_scan_enabled = 1 deny condition = $acl_m_outbound_recipient condition = $acl_m_spam_scan_enabled spam = cpaneleximscanner/defer_ok message = This message was classified as SPAM and may not be delivered log_message = "SpamAssassin as cpaneleximscanner detected OUTGOING not smtp message as spam ($spam_score)" warn condition = $acl_m_outbound_recipient condition = $acl_m_spam_scan_enabled log_message = "S
- acl_smtp_data:
- outgoing_spam_scan (Scan outgoing messages for spam and reject based on the Apache SpamAssassin™ internal spam_score setting)
- Purpose: The acl_smtp_data ACL is used to inspect the content of the email before it's accepted for delivery. It is commonly employed for tasks such as:
- Spam Filtering: Checking the email content against spam filters (like SpamAssassin).
- Virus Scanning: Scanning the email for malware or viruses.
- Attachment Filtering: Restricting certain types of file attachments or scanning them.
- Rate Limiting or Message Size Checking: Ensuring that message sizes adhere to server limits.
- Custom Message Rejection: Applying custom rules to reject messages that contain specific content or violate policies.
- Advanced Settings (Under Advanced editor):
warn condition = $acl_m_outbound_recipient condition = ${if <={$message_size}{1000K}} condition = ${if !eq{$acl_c_authenticated_local_user}{root}} condition = ${if !match{$authenticated_id}{\N^__cpanel__service__auth__[^+%:@]+$\N}} condition = ${perl{spamd_is_available}} set acl_m_spam_scan_enabled = 1 deny condition = $acl_m_outbound_recipient condition = $acl_m_spam_scan_enabled spam = ${if eq{$acl_m1}{}{cpaneleximscanner}{$acl_m1}}/defer_ok message = This message was classified as SPAM and may not be delivered log_message = "SpamAssassin as ${if eq{$acl_m1}{}{cpaneleximscanner}{$acl_m1}} detected OUTGOING smtp message as spam ($spam_score)" warn condition = $acl_m_outbound_recipient condition = $acl_m_spam_scan_enabled log_message = "SpamAssassin as ${if eq{$acl_m1}{}{cpaneleximscanner}{$acl_m1}} detected OUTGOING smtp message as NOT spam ($spam_score)"
WHM - Outbound Filtering
- I am not sure if it uses the per user/cPanel custom rules (as appropriate) for calculating the spam_score when outbound filtering, I cant see why it doesn't though.
- When an email has been forwarded after being scanned for SPAM it will have an additional header with it's score.
- How to configure Spam Assassin to scan outgoing mail. – cPanel - This article covers configuring outgoing mail to be scanned by Spam Assassin.
- Enable Outgoing Spam Filtering Using SpamAssassin - eukhost - This guide explains how to enable Outgoing Spam Filtering Using SpamAssassin.
- Configure SpamAssassin to block outgoing form mail – cPanel
- There are actually two assigned spam scores, one when you receive the email locally and one that is assigned to it when it's scanned outbound.
- In this case Spam Score: X-Spam-Score: 100 refers to the score assigned on delivery to the server.
- The score that is being assigned to the server when it is sent is the Outgoing Spam Score which in this case is below the threshold of 2: X-Outgoing-Spam-Status: No, score=1.7 So with a spam score of 1.7 SpamAssassin isn't seeing this email as spam and sends it.
- How-To Prevent Exim From Forwarding Spam – cPanel - This article covers configuring Exim to not forward mail based on the message's Apache SpamAssassin™ Spam score.
SpamAssassin - Example rules that can be triggered
To find the rules, search for them in the following format: describe KAM_DMARC_STATUS
PHP_SCRIPT 2.5 - Sent by PHP script
- spamassassin/rulesrc/sandbox/jhardin/20_misc_testing.cf - line 2897 · apache/spamassassin · GitHub
- phpmailer - SpamAssassin flags our PHP Emailer for being a PHP_SCRIPT (-2.499) - Stack Overflow
- Every email that is sent to a server with SpamAssassin gets -2.499 score because of the PHP_SCRIPT flag which has the description of Sent by PHP script
- The interesting thing is emails sent with WP SMTP Mail plugin via WordPress do not get flagged for this SpamAssassin rule even though WP SMTP Mail also uses PhpMailer
FREEMAIL_FORGED_REPLYTO 0.1 - Freemail in Reply-To, but not From
KAM_COUK 0.85 - Scoring .co.uk emails higher due to poor registry security.
KAM_DMARC_STATUS 0.01 - Test Rule for DKIM or SPF Failure with Strict Alignment
T_SCC_BODY_TEXT_LINE
- = number of lines in email ?
- /var/lib/spamassassin/3.004006/updates_spamassassin_org/
- spamassassin - What is SCC_BODY_URI_ONLY rule in spam assassin? - Stack Overflow - I am facing this issue SCC_BODY_URI_ONLY with my email when checked with SPAM ASSASSIN,Does anybody know about this rule. There is no great deal of documentation around it.
- meta T_SCC_BODY_TEXT_LINE __SCC_BODY_TEXT_LINE_FULL - __SCC_SUBJECT_HAS_NON_SPACE (72_active.cf)
- This will be to do with the length of the mail
- T_SCC_BODY_TEXT_LINE | Apache Mail Archives
- What is the purpose of the rule named T_SCC_BODY_TEXT_LINE? On my servers, it hits nearly every spam and ham email.
URIBL_BLOCKED small - ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists\#dnsbl-block for more information.
SpamAssassin - Managing rules
- General
- WritingRules - SPAMASSASSIN - Apache Software Foundation
- This is a straightforward guide to writing your own add-on rules for SpamAssassin. This was originally written by MattKettler.
## Default rules, but these will be replaced upon upgrade /usr/share/spamassassin ## Rules seem to be here /etc/mail/spamassassin/
- This is a straightforward guide to writing your own add-on rules for SpamAssassin. This was originally written by MattKettler.
- CustomRulesets - SPAMASSASSIN - Apache Software Foundation - Listed below are several custom rulesets that are available as "drop in" .cf files. To use these rules, just place the file in
/etc/mail/spamassassin
(if you use spamD, be sure to restart). - SpamAssassin Score Explained | Mailtrap Blog - The SpamAssassin score is a great indication of the quality of your emails. We explain how to interpret its results and improve upon them.
- WritingRules - SPAMASSASSIN - Apache Software Foundation
- KAM Ruleset
- This is not part of the Spamassassin base code.
- The is a 3rd party ruleset that is included with cPanel/WHM and is on by default.
- In cPanel/WHM:
/etc/mail/spamassassin/KAM.cf
- KAM Ruleset | The McGrail Foundation
- The KAM Ruleset is a set of Apache SpamAssassin rules developed and used on our systems.
- This ruleset has been in active use and development since May 2004 and provides a significant boost to the performance and efficacy of a stock installation of Apache SpamAssassin.
- KAM Ruleset Channel | The McGrail Foundation - The McGrail Foundation Home Page
SpamAssassin - What rules caused an email to get flagged?
- Exim Mail Log - Example Entry
Sep 1 13:56:08 srv spamd[414141]: spamd: connection from localhost [127.0.0.1]:43490 to port 783, fd 6 Sep 1 13:56:08 srv spamd[414141]: spamd: setuid to cpaneleximscanner succeeded Sep 1 13:56:08 srv spamd[414141]: generic: trusted_networks doesn't contain internal_networks entry '0/0' Sep 1 13:56:08 srv spamd[414141]: spamd: checking message <XXXXXXXXXXXXXXXXZldVRrQX6dyBuRHk9yR9jnJNGRM@www.example.co.uk> for cpaneleximscanner:992 Sep 1 13:56:18 srv spamd[414141]: spamd: identified spam (5.9/5.0) for cpaneleximscanner:992 in 10.3 seconds, 3794 bytes. Sep 1 13:56:18 srv spamd[414141]: spamd: result: Y 5 - FREEMAIL_FORGED_REPLYTO,KAM_COUK,KAM_DMARC_STATUS,PHP_SCRIPT,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED scantime=10.3,size=3794,user=cpaneleximscanner,uid=992,required_score=5.0,rhost=localhost,raddr=127.0.0.1,rport=43490,mid=<XXXXXXXXXXXXXXXXZldVRrQX6dyBuRHk9yR9jnJNGRM@www.example.co.uk>,autolearn=no autolearn_force=no,shortcircuit=no
- spam - Where can i find explanation of a SpamAssasin scores like SPOOFED_FREEMAIL? - Server Fault
## This adds the score /var/lib/spamassassin/3.004006/updates_spamassassin_org/20_freemail.cf ## This is the list of the Freemail domains /var/lib/spamassassin/3.004006/updates_spamassassin_org/20_freemail_domains.cf ## An old list /var/lib/spamassassin/3.004006/updates_spamassassin_org/20_freemail_mailcom_domains.cf
- How to find the descriptions of SpamAssassin rules to help understand why a message was marked as spam – cPanel - If you find that SpamAssassin is marking messages as Spam when it should not be, or that SpamAssassin is not marking messages as spam when it should be, you can use the following procedure to find out what rules were applied to a message and review the description of the applied rules for additional context.
- How can I check why SpamAssassin applied a particular score? – cPanel - Some email messages are flagged or rejected as spam, but I'm not sure why. Can I check how SpamAssassin is applying this score?
- How to find SpamAssassin scan results – cPanel -When SpamAssassin scans an email the results are saved to the
/var/log/maillog
file. This can be used to determine what rules are being triggered by the message./usr/local/cpanel/logs/spamd_error_log
SpamAssassin - Here’s a breakdown of how this score is calculated:
I got this from my VPS provider:
SpamAssassin’s internal spam score is calculated by summing the scores of various matched rules.
- Rule-Based System
- SpamAssassin uses a large set of predefined rules to analyze various parts of an email, including:
- Email headers (e.g., suspicious sender domains, mismatched or forged headers).
- Message body content (e.g., words commonly associated with spam, HTML content, or embedded links).
- Attachments (e.g., dangerous file types, large attachment sizes).
- Blacklists (e.g., checking if the sender's IP address or domain is on a spam blacklist).
- Each rule is assigned a specific score, positive or negative, depending on how indicative it is of spam. These scores are predefined, but you can customize them in SpamAssassin’s configuration files.
- Positive score: Increases the likelihood that the message is spam.
- Negative score: Decreases the likelihood that the message is spam (e.g., messages from trusted sources might get a negative score).
- SpamAssassin uses a large set of predefined rules to analyze various parts of an email, including:
- Cumulative Scoring
- When SpamAssassin scans an email, it applies multiple rules. The total spam score is the sum of all the individual rule scores that match the email.
- Example:
Rule Description Score HTML_MESSAGE Email contains HTML 1.0 BAYES_99 Bayesian filter suggests 99% spam probability 3.5 RCVD_IN_SPAMHAUS Sender's IP is in the Spamhaus blacklist 2.0 DKIM_VALID Email has a valid DKIM signature -1.0 Total Score 5.5
- In this example, the email’s total spam score is 5.5.
- Spam Threshold
- The total score is compared to the spam threshold configured in cPanel/WHM. The default threshold is usually 5.0. If the total score exceeds this threshold, the message is flagged as spam.
- Spam Threshold of 5.0: If an email’s score exceeds 5.0, it is considered spam.
- Spam Threshold of 7.0: If the threshold is set to 7.0, only messages with a spam score higher than 7.0 will be flagged as spam.
- You can adjust the spam threshold score in the SpamAssassin configuration settings to make the filter more or less aggressive.
- The total score is compared to the spam threshold configured in cPanel/WHM. The default threshold is usually 5.0. If the total score exceeds this threshold, the message is flagged as spam.
- Bayesian Filtering (Adaptive Learning)
- SpamAssassin also uses a Bayesian filter, which is a machine-learning technique that adapts to the types of emails received over time. When trained with both spam and non-spam emails, this filter becomes more accurate in determining whether an email is spam by calculating the probability based on previously learned patterns.
- The Bayesian filter assigns probabilities to words or phrases, which contribute to the overall spam score.
- SpamAssassin rules like BAYES_50 (50% spam probability) or BAYES_99 (99% spam probability) are examples of how this filter impacts the overall score.
- SpamAssassin also uses a Bayesian filter, which is a machine-learning technique that adapts to the types of emails received over time. When trained with both spam and non-spam emails, this filter becomes more accurate in determining whether an email is spam by calculating the probability based on previously learned patterns.
- Custom Rules and Scoring
- You can also create custom rules and assign them specific scores. This allows you to adapt SpamAssassin to your organization’s needs by:
- Increasing the score of certain patterns (e.g., emails with specific attachments).
- Decreasing the score for emails from trusted domains or senders.
- You can also create custom rules and assign them specific scores. This allows you to adapt SpamAssassin to your organization’s needs by:
- Adjusting the Spam Score Multiplier
- In cPanel and WHM, the spam score is multiplied by 10 for internal use. For example, if you set a spam score threshold of 5.0 in WHM, it will show up as 50 in log files and email headers.
- For instance, if you see the following in an email header, It corresponds to a score of 4.0 (since 40 divided by 10 is 4.0), which is below the default spam threshold of 5.0, so the email wouldn’t be flagged as spam.
X-Spam-Score: 40