Skip to main content

Scripted routing

Scripted routing is one of the most distinguished features of the Halon platform. It allows users to implement the best solution for any given challenge, instead of having to compromise. Since you have virtually unlimited possibilities with our product, we encourage you to contact support to discuss the best solution for you.

In most situations the routing information can be found by performing a lookup to an external system. It could be an HTTP lookup to a script that performs a database lookup, an LDAP lookup, or something entirely different. The HSL scripting language allows you to perform virtually any kind of external lookup.

Below is an example where an HTTP lookup is used. It's based on our api_call function from this article so you should either include or import it in your script as shown in the example.

RCPT TO context

RCPT TO context
import { api_call } from "modules/api.hsl";
import { ldap_lookup_rcpt } from "modules/ldap.hsl";

$transactionid = $transaction["id"];
$recipient = $arguments["recipient"];
$recipientdomain = $arguments["address"]["domain"];
$transportid = $arguments["transportid"];

// API call
$route = api_call("&type=route&recipientdomain=$1", [$recipientdomain]);

// Failed to lookup route in API
if (!is_array($route))
Defer("Temporary local error, try again later");

// No route found in API
if (!$route["server"])
Reject("We do not accept email for $recipientdomain");

// SMTP lookup recipient
$lookuptype = $route["type"];
$options["tls"] = "optional";
$options["server"] = $route["server"];
$options["port"] = $route["port"];
if ($route["saslusername"]) {
$options["saslusername"] = $route["saslusername"];
$options["saslpassword"] = $route["saslpassword"];
}

if ($lookuptype === "ldap") {
$result = cache ["ttl" => 300, "size" => 16384] ldap_lookup_rcpt([
"host" => "ldaps://host",
"bind_dn" => "cn=admin,dc=example,dc=org",
"bind_pw" => "adminpassword"
], [
"base_dn" => "dc=example,dc=org",
"filter" => "(mail=".LDAP::filter_escape($recipient).")",
// Active Directory
// "filter" => "(proxyAddresses=smtp:".LDAP::filter_escape($recipient).")",
"attributes" => []
], ["tls_default_ca" => true, "tls_verify_peer" => true, "timeout" => 10, "network_timeout" => 10]);
if ($result === -1)
Defer("Recipient lookup failed ($transactionid)");
else if ($result === 1)
Accept();
else
Reject("No such user here");
} else {
$result = cache [
"ttl_function" => function ($result) {
$code = $result["error_code"];
if ($code === -1)
return 60;
if ($code >= 200 and $code <= 299)
return 86400;
return 300;
},
"size"=> 16384
]
smtp_lookup_rcpt($options, "", $recipient, ["extended_result" => true]);
if ($result["error_code"] === -1)
Defer("Recipient lookup failed ($transactionid)");
else if ($result["error_code"] >= 200 and $result["error_code"] <= 299)
Accept(["reason" => $result["error_message"], "reply_codes" => ["code" => $result["error_code"]]]);
else if ($result["error_code"] >= 400 and $result["error_code"] <= 499)
Defer($result["error_message"], ["reply_codes" => ["code" => $result["error_code"]]]);
else if ($result["error_code"] >= 500)
Reject($result["error_message"], ["reply_codes" => ["code" => $result["error_code"]]]);
else
Defer("Recipient lookup failed ($transactionid)");
}

Pre-delivery context

Pre-delivery context
import { api_call } from "modules/api.hsl";

$transportid = $message["transportid"];
$recipientdomain = $message["recipientaddress"]["domain"];
$options = [];

// Inbound traffic
if ($transportid === "inbound") {
// API call
$route = api_call("&type=route&recipientdomain=$1", [$recipientdomain]);

// Failed to lookup route in API
if (!is_array($route) or !$route["server"]) {
Queue([
"delay" => 3600,
"reason" => "Failed to lookup route in API",
"increment_retry" => false
]);
}

$options["tls"] = "optional";
$options["server"] = $route["server"];
$options["port"] = $route["port"];
if ($route["saslusername"]) {
$options["saslusername"] = $route["saslusername"];
$options["saslpassword"] = $route["saslpassword"];
}
}

Try($options);

LDAP module

src/files/modules/ldap.hsl
function ldap_lookup_rcpt($config, $search, $ldap_options = []) {
$ldap = LDAP($config["host"]);
foreach($ldap_options as $name => $value) {
if (!$ldap->setoption($name, $value)) {
echo LDAP::err2string($ldap->errno());
return -1;
}
}
if ($ldap->bind($config["bind_dn"], $config["bind_pw"])) {
$result = $ldap->search($search["base_dn"], ["filter" => $search["filter"], "attributes" => $search["attributes"]]);
if ($result) {
$entry = $result->next();
return $entry ? 1 : 0;
} else {
echo LDAP::err2string($ldap->errno());
return -1;
}
} else {
echo LDAP::err2string($ldap->errno());
return -1;
}
}