From Halon, SMTP software for hosting providers
Revision as of 14:09, 13 April 2015 by Anders (talk | contribs) (Created page with "Successfully delivering email (measured as "deliverability") to external parties (email servers on the Internet) is important in many cases, such as outbound email services, f...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Successfully delivering email (measured as "deliverability") to external parties (email servers on the Internet) is important in many cases, such as outbound email services, forwarding and even VPS (cloud) providers. Halon's scripting language HSL let’s you design and tailor the logic to handle compromised accounts and abusive users; in order to avoid blacklisting without bothering legitimate users.

Source address

In addition to warming up IPs, we recommend having multiple IPs per cluster node in order to do

  • Source hashing different customers (domains)
  • Sending suspect spam out though a bulk IP

Since each node have different IPs, it's convenient to address the IPs using their ID (netaddr:X). The example pre-delivery script below uses IP 1-3 for normal traffic, and IP 4 for suspect spam. The metadata "spam" variable should be set in the DATA script.

if (GetMetaData()["spam"] == "yes") {
} else {
$addrs = [123];
$sourcehash number("0x".md5($senderdomain)[0:6]) % count($addrs);

Anti-spam and rate limits

With the right tools, outbound anti-spam can be extremely effective because you know who the sender is; their $saslusername if authenticated directly with the Halon system, $sender address (if enforced by the email server), $senderip (in the case of a VPS provider), a header in the message (enforced by PHP), etc. Therefore, we recommend that you create a deferring, rate-limit based script such as this:

// Identify the sender as accurately as possible 
$customer $senderdomain;
if (
$customer GetHeader("X-PHP-Originating-Script");
if (
$customer $saslusername;

if ((
ScanRPD() == 50 or ScanSA() > 4) and rate("outbound-bulk"$customer30028800) == false)
Defer("You are only allowed to send 300 bulk messages per 8 hours, try later $messageid");
if ((
ScanRPD() == 100 or ScanSA() > 6) and rate("outbound-spam"$customer10028800) == false)
Defer("You are only allowed to send 100 spam messages per 8 hours, try later $messageid");
if (
ScanRPD() > or ScanSA() > 3)
SetMetaData(["spam" => "yes"]); // For the pre-delivery script 

which should be accompanied with a upper limit in for example the RCPT TO script

// Max messages per hour
if (rate("outbound"$senderdomain2503600) == false)
Defer("You may only send 250 messages per hour, try later"); 

Act on deliverability

Reacting to automatically measured deliverability is a powerful way to avoid blacklisting. By counting the delivery failure rate in the post-delivery script

// Counts up to a rate of 1000 failures per hour, you can use another ID than $senderdomain
if ($errorcode >= 400)

which is read in for example the the RCPT TO or DATA script

if (rate("delivery-failures"$senderdomain03600) > 999)
Defer("$senderdomain has more than 1000 failed deliveries during the last hour");
if (
GetMailQueueMetric(["filter" => [ "senderdomain" => $senderdomain ]]) > 500)
Defer("$senderdomain has exeeded the max queue limit of 100 messages"); 

Connection concurrency

Transparent proxy