Preventing outgoing spam

My server is sending spam. What do I do?

If your server is sending spam, most likely you've already ended up on an RBL blacklist.

The first thing you need to do is to find out who is spamming and stop them.

There are several ways they could be sending spam:

  • they've figured out an email password and are sending remotely
  • they are sending from a script on the server (insecure script)
  • they've created a cronjob to send emails in the background
  1. Make sure that you have a send limit enabled
echo 200 > /etc/virtual/limit

This will put a daily cap on the number of emails a DA user can send. This is the sum of all their email account's sends totaled together.

  1. Check /etc/virtual/usage to see which User has a higher-than-average bytes log. If any User stands out, then they're likely the culprit.

  2. Log into DA as that User, and go to: User Level -> E-Mail Accounts -> E-Mail Usage. This will give you a better breakdown of who is sending what, and to where.

  3. Go to DA Admin Level -> Mail Queue Admin .

If spam is being sent, there are usually going to be messages stuck in the Queue.

Click one of these messages (the ID) and check the contents (to ensure it's spam), and the headers of the messages to try and get info about who sent it (IP), where it's going, and if there are any X-PHP-Originating-Script headers, telling you wish script did the sending.

  1. Check to see if there are any repeated smtp-auth values:
cd /var/log/exim
grep 'A=login:' mainlog* | less

Though, step 3 above should tell you what login was used, if one was used.

  1. Check your exim logs for anything out of the ordinary.

  2. Although not related to the prevention of sending spam, if you use DKIM with your email, it will both lower your spam score on remote boxes as it will confirm that your emails are indeed from your server, and not spoofed from elsewhere. http://www.directadmin.com/features.php?id=1189open in new window

  3. Check the /home/username/.php/php-mail.log file, it contains PHP scripts that were involved to send messages out.

  4. If there is no trace of spam, yet you're still being blocked, there is a chance they're sending spam directly to remote servers. Ensure your port 25 outbound is blocked for all Users, except "mail" and "root".

My sent Emails are labeled as spam on remote mail servers

If you're sending from your DA box, outbound to other mail servers, and keep having your messages being flagged as spam, a good tool to use is AllAboutSpam.comopen in new window.

What you do, is send them an email from your server just like you would any other recipient. They'll then send you a bounce back telling you everything that's incorrectly set up.


Another popular resource is https://www.mail-tester.com/open in new window , where you send mail to them and then refresh the page in browser to get details and a score level per their tests.

Email Rate Limiting with Exim and the exim.pl

Spam is an ongoing issue, and any email account that has its password compromised can end up sending massive amounts of spam through your server. The following tips will help you limit the damage done should this happen.

  1. Update Exim to the latest version, which can support smtp-time blocking, so that if a limit is reached, the smtp-auth send will return an invalid password error.

  2. Ensure that you have a per-User limit set up. This will be a daily limit for the maximum number of total sends all accounts and scripts under this User can send from the server, combined. A typical value might be 200, e.g.,

echo 200 > /etc/virtual/limit
  1. Ensure the per-Email limit is set, meaning you can set up a daily limit on each of the email accounts, so that if any one account sends spam, it won't end up using the full per-User limit, blocking the rest of the accounts. It would instead only cap that one sending User, and leave all other accounts to be able to send emails. A typical global default per-Email limit here might be 50, e.g.,
echo 50 > /etc/virtual/user_limit
  1. DirectAdmin can set up the ability for the User to control the per-Email limit. To enable this feature, type:
cd /usr/local/directadmin/
./directadmin set user_can_set_email_limit 1 restart

These limits can be controlled by the User at User Level -> E-Mail Accounts.

Note that the default will not allow the User to specify a per-Email limit higher than the global limit in /etc/virtual/user_limit.

If you want to allow Users to set a higher per-Email limit than the global default, set the following in the directadmin.conf, and restart DirectAdmin:

cd /usr/local/directadmin/
./directadmin set max_per_email_send_limit 100
service directadmin restart

which, for example, will allow Users to set a maximum of 100 as the per-Email limit. The per-User limit (/etc/virtual/limit) is still enforced, regardless of what the per-Email limits are set to.


NOTE: The Per-User user.conf override max_per_email_send_limit can be used to override the limit set in the directadmin.conf for a single user by adding the value to the User's user.conf file. This can be done by editing the file directly, or via the DirectAdmin GUI when viewing the User's details (by clicking Show All Users, then clicking the desired user, and then editing their User details).

This is useful if you have one User you want to allow to set a high per-Email send limit, but not want to allow all DA Users the ability to set a high per-Email send limit.

Acceptable values for max_per_email_send_limit include:

  • blank/empty string: The default: relies on the same setting from the Admin Settings page.
  • -1: overrides to -1, meaning the max value a User can set will match /etc/virtual/user_limit
  • 0: Unlimited (not recommended). Although an E-Mail could have unlimited sends, the send limit cannot exceed the DA User's limit.
  • positive integer: The numerical limit a User would be allowed to set as the max send value for an E-Mail.

Relative CMD_* calls

To save data using CMD_MODIFY_USER:

method: POST
user=fred
action=single
max_per_email_send_limit=<any text>
max_per_email_send_limit_value=VALUE (blank or -1+)

To view data, use CMD_SHOW_USER:

user=emailuser
json=yes

Where the complete GET would be:

CMD_SHOW_USER?user=emailuser&json=yes

The output for this setting might look like this:

		"14": 
		{
			"setting": "max_per_email_send_limit",
			"usage": "48",
			"max_usage": "200"
		},

If a per-Email limit is reached, DA will notify that email account of their limit being reached: http://www.directadmin.com/features.php?id=1561open in new window

  1. Admins can modify the daily sent limit for a User by viewing that User's settings. By default, a Reseller cannot, but this can be enabled with reseller_can_set_email_limit=1.

Warning: 200 emails have just been sent by unknown

The "unknown" username will show up when the DA account cannot be determined from the sender address. Most of the time, this happens when a bounce email is being sent from your server outbound to an external location, as the sender in those cases is "<>".

This tends to result from local forwarders sending mail to external locations, but the external location refuses to accept the message (either full mailbox, doesn't exist, it thinks it's spam, etc.). Exim is then stuck with the message that cannot be sent, and thus sends the bounce message back to the external sender. This would be billed against the "unknown" case. Note that a bounce is not generated if an account doesn't exist locally, as the message would have never been accepted in the first place. They only happen when the message was already accepted by Exim (usually because the forwarder exists locally), but the final delivery fails.

Exim has the ability to limit on a per-user basis. With this feature, you can chose what you want these bounces to do. You have 3 options:

  1. Allow unlimited bounces to be sent outbound. To do this, set a higher limit for the unknown case:
echo 0 > /etc/virtual/limit_unknown
  1. Allow a higher limit for unknown. This still allows for bounces to be sent, but also helps prevents backscatter (adjust value as needed):
echo 1000 > /etc/virtual/limit_unknown

IMPORTANT: If you set a numerical limit for /etc/virtual/limit_unknown, a "sender_verify" in the exim.conf does get counted against this limit. So if you use the sender_verify option, make sure you leave this at 0, else all inbound emails will quickly eat up the 1000 message limit.

  1. Block all bounces from leaving your server.

Note that bounces are a normal part of the mail system (RFCs), but can also be a problem (backscatter). Each Admin will have a different opinion about what the action should be for these cases.

How to block User account from sending any messages

Starting from DirectAdmin version 1.60.0, a GUI via Administrator Settings > Email Settings is available to completely block user from sending any messages.

How to block outgoing port 25 to prevent direct-out spammers

If you're not running a firewall, or are using a default state for most firewalls, often times, they don't block Users from sending on port 25 directly to remote mail servers. This would bypass Exim, thus this wouldn't be desirable as you wouldn't have any way of tracking it.

Related change to to our block_ip.sh iptables scriptopen in new window

We recommend that you block port 25 out for all Users, with the exception of only allowing "mail" and "root". The "mail" user is what Exim uses to deliver outbound messages, and "root" is used for manual testing/debugging.

If you're running CSF, set the following value:

SMTP_BLOCK = "1"

Note that the block_ip iptables script will do this by default.


To manually test if this block is working, you'd see something like this when connecting to port 25 via telnet as admin and then as root:

# id
uid=0(root) gid=0(root) groups=0(root)
# su - admin
$ telnet directadmin.com 25
Trying 216.144.255.179...
telnet: connect to address 216.144.255.179: Connection refused
$ logout

# id
uid=0(root) gid=0(root) groups=0(root)
# telnet directadmin.com 25
Trying 216.144.255.179...
Connected to directadmin.com.
Escape character is '^]'.
220 jbmc-software.com ESMTP Exim 4.86.2 Fri, 08 Apr 2016 16:06:28 -0600
QUIT
221 jbmc-software.com closing connection
Connection closed by foreign host.
#

But if your admin" account can still connect to a remote server on port 25, then the block isn't working yet.

Limit SMTP functionality as much as possible if you cannot outright block it. Note that rather than disabling SMTP_BLOCK altogether when a single user requires SMTP, you can use SMTP_ALLOWUSER in CSF to whitelist the user that requires SMTP. You can add multiple users in a comma-delimited list to SMTP_ALLOWUSER if multiple users require SMTP functionality, but not all.

How to customize the daily User email limit based on a custom package item

With the addition of the custom package itemsopen in new window, you can now use these items to control other areas of your system. For this example, we'll have these items control the daily email limit of a User (/etc/virtual/limit_username).

  1. Add a custom package item. See this guideopen in new window on how to do that. For this example, use a 'text' value. Give the variable the name "user_email_limit".

  2. By default, the item is only stored in the user.conf file. To have it do something, create the script /usr/local/directadmin/scripts/custom/user_create_post.sh. Inside that file, add this code:

#!/bin/sh
if [ "$user_email_limit" != "" ] && [[ $user_email_limit =~ ^-?[0-9]+$ ]] && [ "$user_email_limit" -gt 0 ]; then
    echo -n "$user_email_limit" > /etc/virtual/limit_$username
fi
exit 0;
  1. Make it executable:
chmod 755 /usr/local/directadmin/scripts/custom/user_create_post.sh

Once the User is created, this package variable will no longer have any effect. Thus, changing the User from the package won't have any effect, though it can if you want by creating a similar user_modify_post.sh script.

The way to change the per-User email limit setting would normally be through: Reseller Level -> List Users -> Username -> E-Mail Limit .

Why forwarders to external mailservers can be dangerous for your server

It's not uncommon for clients to want to forward mail from their own domain to an external email address, say Gmail, for example.

The path of an email sent to the user@domain.com forwarder would be:

Sender -> DA box: user@domain.com -> External: user@gmail.com

This will work fine, until spam comes into the picture.

The issue with spam is that, if the proper blocks are not in place, your DA box will happily relay spam to Gmail, which could then cause Gmail to think that the spam is originating from your DA box, thus getting your IP blacklisted even though the spam came from somewhere else.

Another issue is that, if Gmail then determines that the message is spam, it may be denied at the Gmail server, thus returning it back to your DA box to figure out what to do with. Since the sender is not from the DA box, and the final recipient is Gmail (which was denied), Exim tries to send it back to the original "sender", which with spam, is almost always fake/spoofed (these headers can be spoofed).

This causes "backscatter", where Exim is trying to return a message to an address that was not the actual sender. This backscatter is also a potential hazard to getting your IP blacklisted.

Solutions:

  1. Avoid forwarders to external domains whenever possible (it is usually hard to convince users of this).

  2. For Gmail, as an example, have Gmail pull your POP emails to Gmail, rather than you pushing them via forwarders. See this guide for more infoopen in new window.

  3. Ensure SpamAssassin is enabled, and set it to drop spam or send to spambox (do not use "deliver to inbox"). At a minimum, use "drop high scoring spam".

  4. Block bounces from leaving.

  5. RBL Blocking is a robust way of blocking spam before Exim even sees the message (realtime IP based block). Some consider RBL blocking to sometimes be too strict in that it may often block entire ISP ranges (send on port 587 with smtp-auth, instead of port 25).

How to skip SpamBlocker, EasySpamFighter and BlockCracking checks for smtp-auth

If you're sending many emails with an smtp-auth account, you may want to skip several checks.

SB 4.4.x, ESF, and BC, all have skip lists which can be used for various things, including email addresses. If you have smtp-auth/From account, user@domain.com, sending from IP 1.2.3.4, type:

echo user@domain.com >> /etc/virtual/esf_skip_senders
echo user@domain.com >>  /etc/virtual/bc_skip_authenticated_users
echo 1.2.3.4 >> /etc/virtual/esf_skip_ips
echo 1.2.3.4 >> /etc/virtual/skip_rbl_hosts_ip

which should skip some of the checks for that account from that IP (these are different checks, so you don't need to skip the IP if you don't want to).

RBLs can also cause a slowdown, so adding the "To" / destination local domain to these files will speed up delivery to them:

/etc/virtual/skip_rbl_domains
/etc/virtual/skip_av_domains

These are not applicable if all of the destination emails are external to the server.

Note that there are files in /etc/virtual that contain the name "whitelist".

Do NOT add any domains, IPs or emails to these files, as they refer to an open relay whitelist, and they're not meant for production use, only for temporary testing. If you add any value to these files, any matches for them will no longer require smtp-auth, giving them open relay, which is a bad thing.


If you have as sender that is getting caught in an RBL block and you don't want a specific domain or email to be checked by the SpamBlocker RBLs, then you can use the /etc/virtual/whitelist_senders file to add "From" emails to the whitelist. Just be very careful when using the whitelist files in /etc/virtual, because, for many cases, it fully opens up any email with that value to do whatever they want, even relay openly in some cases.

Use very sparingly. The whitelist_senders file specifically does not create an open relay, so it's okay to use for certain cases where you do not want any checking done (skips everything, but still requires auth for relay).

To skip a hostname or group of hostnames from the ESF checks (usually to allow incoming from them for SPF or DKIM failures), you'd use /etc/virtual/esf_skip_hosts which supports wildcards, e.g.,

*.hostname.com
server.otherhostname.com

BlockCracking notices and unblocking

BlockCracking is where Exim keeps track of how many non-existent email addresses a sender tries to send to within a given period of time, and blocks the account from sending if the count is too high.

Requires exim.conf 4.2.3+ and exim.pl 19. Can be installed with CustomBuild.

These changes are only a small portion of the feature as the bulk of it is in the Exim module, to be installed via CustomBuild.


1. Unblocking for blocked smtp-auth Users

Once an account is blocked, they're likely going to want to be unblocked, but the account must be deemed "safe" first. The directadmin.conf variable below controls the process:

block_cracking_unblock=1|2|0
block_cracking_unblock=1

1 means the standard password change will unblock the account.

Note that the account itself is not allowed to do this so this password reset must be done via the next level up. Since the alleged spammer knows the password, we don't want them just resetting the password to spam more.

So if a user@email.com is blocked, the password must be changed from the User Level by a DirectAdmin User.

If a DirectAdmin User is blocked, then their creator or higher (a Reseller or Admin) must unblock them from the Reseller or Admin Levels.
However, the "Lost Password" tool on the 2222 Login Page will unblock the DA user upon password reset, as it's set to a new random value that the hacker (hopefully) cannot learn (assumes the email is not a local one).

Note that I say "change" password, which is what I expect you to do, as a compromised account is one where the smtp-auth password is known and thus must be changed. However, if you change it to unblock it, there is nothing stopping you from setting it back to the original value. This is not recommended, as it will allow the spammer to send more spam. Of course, if it's a false positive, then this should be fine (e.g., you set a BlockCracking limit too low, etc.).

block_cracking_unblock=2

2 means, all rules of 1 apply, but 2 adds the extra "automatic unblocking" to happen after a give amount of time. We really don't recommend you set this, but hopefully, Users will have changed their passwords on their own free will (we hope), so the option frees up your time by having it done automatically.

The following directadmin.conf variable represents the number of minutes before an account is unblocked:

block_cracking_unblock_minutes=120
block_cracking_unblock=0

0 doesn't do anything at this time, but we may reserve it to prevent unblocking, that is, if someone would ever want that (me thinks not).


2. Unblocking for blocked Paths

The same block_cracking_unblock variable is used to determine unblocking abilities for paths. For a User to unblock a path, they can go to:
User Level -> E-Mail Accounts -> E-Mail Usage
and it will show all paths below /home/user (inclusive), which they can select and unblock. Paths outside of /home/user, e.g., /tmp or /home/otheruser will not show up in this table and cannot be removed.


3. Notices.

When a limit is reached, the exim.pl adds the following to the /etc/virtual/mail_task.queue file:

action=block_cracking&type=smtp&authenticated_id=user@domain.com&sender_host_address=1.2.3.4&log_time=10423498
action=block_cracking&type=script&authenticated_id=admin&script_path=/home/admin/domains/domain.com/public_html&sender_host_address=&log_time=1409820955

DA then picks that up, and will send notices as applicable. Who get notified depends on these already existent variables:

notify_on_mass_emailing=0|1                        # Global on/off switch for all the other notify variables
notify_user_on_mass_emailing=0|1
notify_reseller_on_mass_emailing=0|1
notify_admins_on_per_email_mass_emailings=0|1

Once the "who" is figured out, assuming there are more than 0, the block_cracking_notice.txt template is used, and notices are delivered using the Message System.


How to block scripts by PATH

If you want to block scripts by PATH or by wildcard PATHes you would need to:

  1. Enable blockcracking first
  2. Add desired path into /var/spool/exim/blocked_script_paths file

Changes to DA allow the new BC type "denied_path" in the mail_task.queue. BlockCracking uses a new file: /etc/exim.blockcracking/script.denied_paths.txt which contains a list of exim nwildlsearch regex path values, for example:

^.*/wp-content/uploads.*

and compares the sending path against it.

If it matches, this path is dumped into the BC script block file:

/var/spool/exim/blocked_script_paths

just like bad sending scripts get for sending to too many bad recipients.

The regex doesn't use a trailing / after the final path, e.g., we cannot use:

^.*/wp-content/uploads/.*

(this won't work) because the cwd that exim sees doesn't end with "uploads/", it just ends in "uploads".

This will run the logical risk of blocking something like wp-contents/uploads-from-yesterday. Keep this in mind when selecting your regex.

DA is notified via the exim.pl, and a message is sent out to notify everyone, in the same manner as before (same rules for script unblocking).

Last Updated: