Tag: releases

Halon 5.6 with native plugins and Linux admin

Spring is approaching, and we’re getting ready to ship the next quarterly Halon MTA release, 5.6 “pingy”. For the first time, we’re shipping the web administration interface as separate Linux packages, making it more convenient to setup Halon clusters on Ubuntu and CentOS. This is great news for example if you’re using containers to build an elastic cluster for cost or scalability reasons.

The biggest news however is the new native plugin system, which complements Halon script and FFI. It allows you to add functions to the MTA written in any language compatible with the C library ABI (such as C++ and Go). In addition to adding your own HSL functions, it also enables you to work with the queue and delivery subsystems. Queue plugins can implement things like specific delivery times and customised IP warmup. Delivery plugins can be used to implement for example HTTP delivery to an object storage. Modules should employ the suspend/schedule pattern to avoid blocking, since the Halon MTA is event-based (uses asynchronous IO). This will be described in great detail in an upcoming blog post.

To give you an idea of how it works, consider the example below. It implements a simple sleep function in Go. The Halon_hsl_register function registers a sleep function in HSL. The sleep function itself dispatches a sleepTask, and immediately returns (suspends the script execution). Finally, sleepTask first sleeps, and then wakes the script up again (schedule).

// go build -buildmode c-shared -o sleep.go
package main

// #cgo CFLAGS: -I/opt/halon/include
// #cgo LDFLAGS: -Wl,--unresolved-symbols=ignore-all
// #include <HalonMTA.h>
import "C"
import "unsafe"
import "time"

func main() {}
func Halon_version() {
func sleepTask(hhc *C.HalonHSLContext, ret *C.HalonHSLValue, sec float64) {
    time.Sleep(time.Duration(sec * 1000.0) * time.Millisecond);
func sleep(hhc *C.HalonHSLContext, args *C.HalonHSLArguments, ret *C.HalonHSLValue) {
    var t C.double = 0;
    var arg0 = C.HalonMTA_hsl_argument_list(args, 0);
    if (arg0 != nil)
        C.HalonMTA_hsl_value_get(arg0, C.HALONMTA_HSL_TYPE_NUMBER, unsafe.Pointer(&t), nil);
    go sleepTask(hhc, ret, float64(t));
    C.HalonMTA_hsl_suspend_return(ptr); // go can’t use HalonMTA_hsl_suspend()
func Halon_hsl_register(hhrc *C.HalonHSLRegisterContext) C.bool {
    C.HalonMTA_hsl_register_function(hhrc, C.CString("sleep"), nil); // go can’t easily get the C function point of an exported method. “Nil” will make the HalonMTA_hsl_register_function use dlsym()
    return true;

As usual, the release is packed with other various improvements such as;

  • The FFI now provides the email body (MIME) and other File classes as a C-compatible FILE natively, making it easier to access to the modified email body when integrating with C libraries.
  • The integrated (virtual machine) package now includes Spamhaus DQS which provides additional functionality such as HBL.
  • Support for CSV schemas when using import so that imported CSV files get correctly typed out of the box.
  • Added In-Reply-To header to DSNs to support threaded bounces, which makes it easier and quicker to know which message is associated with what bounce.

See the release notes and detailed changelog for a full list of changes. We hope that you will enjoy this new quarterly release! If you have any questions, or are new to Halon, don’t hesitate to reach out!

Halon 5.5 with DSN extension support

Winter is here, and so is our next quarterly Halon MTA release: 5.5 codename “mappy”. It’s slang for happy on a Monday, which is quite fitting! It comes packed with new features, functions and improvements which opens up even greater possibilities for building differentiated, efficient services.

Our large-scale senders will appreciate additional tools for IP warmup, ensuring deliverability by complying with receiver guidelines. You can now choose the order by which source IPs in a pool are chosen, as opposed to load balancing between all IPs. It allows you to use one IP primarily until it exceeds the threshold for daily warmup for a certain destination. Another feature which is especially useful for senders looking at migrating their email infrastructure to cloud environments (such as AWS) is outbound PROXY support. It enables you to use the powerful HAProxy load balancer rather than NAT, when sharing IPs between MTA instances.

Do you want to leverage the DSN extension to better track email delivery? If so, you’ll appreciate our fully-scriptable RFC 3461 implementation. It allows you to quickly and easily tailor the DSN behaviour exactly to your liking.

The Halon scripting language has been extended with new data storage classes, generator functions with yield, and several new functions for encoding. The strongly-typed Map() and Set() storage classes are performance-optimised alternatives to the more generic array type. Take our revamped DMARC implementation‘s public suffix list lookup for example. It parses a data file, then storing and caching the results in a Set() for efficient lookup of the slightly complex rules:

$rules = memory_fetch("public_suffix_list.dat", function ($k) {
		$rules = Set("string");
		$file = File("file://public_suffix_list.dat");
		if (!$file)
			return false;
		while (is_string($line = $file->readline()))
			$line = str_strip($line);
			if ($line[0] == "/" or $line == "")
		memory_store("public_suffix_list.dat", $rules);
			return $rules;

The integrated (VM) package has received several requested features. First of all, the built-in web server which hosts the web administration and JSON API can now be used to also host custom PHP scripts. It allows you to create additional API endpoints, which can write files used by the Halon script during email processing. One possible use case for this is to receive requests from legal interception systems. Secondly, it is now possible to add local DNS records to the built-in Unbound DNS resolver from the web administration. It can be useful when split-horizon DNS is unavailable, and you need to override some specific DNS record. Finally, it allows you to sort the built-in history on both finished and received time. As usual, the package is based on the latest version of FreeBSD (12.2, which was released a few weeks ago) and comes with updated third-party components.

We hope that you will enjoy this new quarterly release. Please see the release notes for more information, and don’t hesitate to reach out if you have any questions!

Halon 5.4 with tailored bounces

Image by Dean Hochman

Sometimes you want to customise the bounce generation. It could be anything from translating bounces into another language or making them more user-friendly, to implementing standards such as SRS. In order to do so, you’ve had to override Halon’s default bounce generation. In our new release Halon 5.4 “bouncy”, we’ve added many options to the built-in bounce generator. This enables you to quickly tailor the way bounces look and work, without having to reimplement the default generator.

  "delay" => 3600,
  "dsn_delayed" => true,
  "dsn" => [
    "readable_mimepart" => MIME()
      ->setBody("<em>choo choo train is delayed</em>")
    "original_headers" => false,
    "subject_prepend" => "Not making it in time: ",
    "headers" => [
      "Foo: Bar"

As usual, the release comes with many other improvements. The foreign function interface (FFI), which is used for loading external libraries into the MTA executable, can now export File classes as a C++ std::istream and X.509 resources as OpenSSL pointers. This powerful feature enables you to access the (potentially modified) email body as a virtual file. We’ve also added chunking (BDAT) for both sending and receiving, a zero-fill right shift bitwise operator, a data callback to the http() function, FFI function callbacks, and much more. Please see the release notes for a complete list of changes. We hope that you will enjoy this release. If you are new to Halon, don’t hesitate to contact us if you have any questions.

Halon 5.3 with new powerful queue API

Soap drop by Breic

Since the first Halon MTA release in 2008, we’ve had a text-based queue query syntax called HQL (a play on SQL) as part of our SOAP API. While it has served us well during all those years, it was time to move on to something more modern. The new 5.3 release (codename “buffy”) comes with a Protocol Buffers and JSON API which introduces a programmatic approach to queue operations.

The request and response body schemas are available on our Github page. For your convenience, the QueueList, QueueGroupByQueueUnload and QueueUpdate requests all have the same Condition argument. Those API calls can operate on both the active and defer queues, as well as messages on hold. That is why the condition argument both contains things like retry count, as well as resolved remote MX and IP. You can specify as many conditions as you like, and create logic-or expressions by specifying multiple conditions of the same type. There are exact matching, regular expressions, and intervals for integers and date/time. Needless to say; incredibly powerful.

The QueueGroupBy call returns the distribution based on the grouping parameters and intervals you choose; such as number of messages in various age buckets, grouped by recipient domain. This is useful for getting an overview of a large queue. Queries are blazingly fast, even with very large queues. All queue metadata (essentially the fields available as conditions) is loaded into memory, in order for the virtual sub-queues to work.

Halon 5.3 also comes with a new CLI called halonctl. It happens to be very useful when working with our API, as it can output the API request and response bodies for the command you run in JSON format. As you can se in the example below, the request body is printed first: 

$ halonctl queue update --bounce --state DEFER --jobid foobar --json-request --json
    "conditions": {
        "queues": [
                "queue": "DEFER"

The CLI covers all the functionality of the product, and is a great complement to the web administration. Its configuration management sub-commands are useful for integrating Halon MTA instances into provisioning, deployment and CI/CD toolchains such as Puppet or Chef, where running commands is easier than making API calls.

Halon 5.3 comes with many other great improvements; such as connection pooling, a more efficient queue quota function, a new on-disk queue format and an Iconv() class for internationalisation conversion. Please see the release notes for a complete list of changes. We hope that you will enjoy this release as much as we do! If you are new to Halon, don’t hesitate to contact us, or dig into all our documentation that is available publicly on our website.

Halon 5.2 with ultra-flexible queuing

Photo by Karen Roe

We’re very proud to announce the upcoming 5.2 release “polly” which introduces a powerful queue policy engine. First and foremost, the queue and SMTP client’s network layer is now asynchronous. This allows an instance to handle tens of thousands of parallel connections. In combination with the reworked connection concurrency limits, this allows dynamic creation of a virtually unlimited number of independent sub-queues. This is useful for senders that need to separate email streams so that those that move slowly or get stuck don’t block others.

As usual, we made it flexible enough to fit any email service provider’s needs. Rather than having a fixed set of parameters and rollup/grouping options for establishing the sub-queues (with their respective thresholds), we allow you to define what constitutes a unique entry. You can choose any combination of fields, and group/rollup entries using regular expressions or wildcard. In the example below, we limit the concurrent per source IP and remote MX, and also rollup all Google’s MX entries into the same entry. The default concurrency is 5, except Google that gets 10.

- fields:
  - localip
  - remotemx:
        - '*'
        - '*'
        - '*'
  - if:
      remotemx: '#gsuite'
      concurrency: 10
      rate: 50
    concurrency: 5
    rate: 10

Sometimes rollup per MX doesn’t cut it. There are several Microsoft Office365 locations (clusters), but the customer MX doesn’t reveal which they are on. To set a certain threshold for Office365 locations, we can rollup and match per MX, but limit per IP, as per the example below. Note that there’s no default threshold; it only affects Office365.

- fields:
  - localip
  - remotemx:
       - '*'
  - remoteip
  - if:
      remotemx: '#o365'
      concurrency: 10
      rate: 30

Thresholds and suspensions can be modified on the fly without reloading the configuration via
API, CLI, web administration or the MTA itself through this Halon script:

// If we have more than 10 failures per minute, lower rate for 5 minutes
$mx = $arguments["attempt"]["connection"]["remotemx"];
$code = $arguments["attempt"]["result"]["code"];
if ($mx and $code >= 400 and !rate("mx-fail", $mx, 10, 60, ["sync" => false]))
    cache ["ttl" => 300]
            ["localip", "remotemx"],
            ["remotemx" => $mx],
            ["rate" => [10, 60]], 300);

The reworked queue naturally comes with many new tools and APIs for interacting with the new functionality. This includes more subtle improvements, like the ability to view the queue’s shape by message age. By pressing an interval, you can dig into the specific messages, which are grouped by fields of your choice.

The new shared memory script functions and API opens up several possibilities. You can script statistic counters, which can then be read periodically over the API. Another use case is pre-loading data into the MTA over the API, rather than fetching and caching from within the script.

Finally, we now offer the ability to call methods in external shared libraries using our foreign function interface (FFI) class.

Check out the full changelog on GitHub for more information, and familiarise yourself with the important changes outlined in the release notes document before upgrading.

Implementing SMTP LANG with proxy script

The upcoming Halon 5.1 release introduces a new SMTP server proxy script. It’s configured to be executed before specific (or all) SMTP commands, even command which isn’t recognised by the SMTP server. In this blog we’ll describe how to implement our proposed SMTP LANG extension using this new script hook. First of all, we announce the LANG extension and the languages supported in the HELO script:

$announce =  [...$arguments["extensions"], "LANG SE"];
Accept(["extensions" => $announce]);

Next, we configure to proxy script to hook onto the new “BREV”, “INNEHÅLL” and “HEJDÅ” commands:

Finally, we setup the proxy script to translate the international (Swedish, in this case) commands with their standard SMTP respective:

$cmd = str_upper($arguments["command"]);
if ($cmd[0:11] == "BREV FRÅN:") { // MAIL FROM
    $realcmd = "MAIL FROM:" + $arguments["command"][11:];
    Pass(["command" => $realcmd]);
if ($cmd == "HEJDÅ") { // QUIT
    $codes = ["code" => 221, "enhanced" => [2, 0, 0]];
    Reply("Ha det bra", ["reply_codes" => $codes, "disconnect" => true]);
// etc...

The proxy script and the corresponding xtext functions can be used for many other things, like custom XCLIENT implementations. More information on the 5.1 will be released later this month.

Halon 5.0 “tidy” with new REST API

Photo by Steve Hodgson

We celebrate the new year with news on the upcoming release, which bundles many exciting features.

First and foremost, the new RESTful API with an OpenAPI specification makes integration into various development and deployment toolchains much more enjoyable. Since most of our customers already integrate Halon into their directories and control panels by making REST queries from Halon, it makes perfect sense that Halon can be provisioned in the same way.

$ curl https://halon1/api/1.0.0/email/queue
   -d '{"filter": "ip=", "fields": {"transport": "srv2"}}'
   -u username:password
    "affected": 10

Secondly, we’re introducing a new end-of-DATA script that’s executed once per message, as opposed to the per-recipient DATA script. Whereas the per-recipient version is convenient when you want to treat each recipient individually and let the Halon software take care of queueing and consolidating the respective actions into an SMTP response, the per-message version gives you maximum flexibility and control over execution. The $transaction variable is populated gradually during the SMTP conversation with sender information, and an array with recipients accepted by each RCPT TO command. To then relay a message to its recipients, you call Queue() for each $transaction["recipients"] and then Accept(). Making per-recipient message modifications using the MIME() class is now easier thanks to the new snapshot() and restore() methods.

The code editor’s built-in CSV editor now supports custom form controls, defined like a “schema” on a per-file basis using a JSON format. You can use checkboxes for booleans, select controllers for enumerated types, and input fields with validation for things like dates, email addresses or any regular expression you like. It makes it much more convenient and safe to create and edit lists and settings that you want to have in your Halon configuration file.

There’s a new LDAP() class that replaces the previous ldap_ functions and LDAP settings in the configuration. It provides greater flexibility, and an improved usage pattern using an iterable LDAP result object.

Finally, there are massive under-the-hood improvements. There’s a new on-disk YAML configurations with JSON schemas and Protobuf control sockets, which is used by the componentised Linux package’s new Visual Studio Code plugin and command line tools. The integrated package is built on FreeBSD 12, which ships with OpenSSL 1.1 and thus TLS 1.3 support. It was published as a standard by IETF in August last year, and is much anticipated as it contains many security improvements over previous TLS versions. The queue database is now using the latest and greatest PostgreSQL version 11.1, and the queue is automatically migrated on boot as usual.

We have that you’ll like this new release as much as we do! Check out the full changelog on GitHub for more information, and familiarise yourself with the important changes outlined in the release notes document before upgrading.

Halon 4.7 “ahoy” and 4.8 “truly” with live debugging and HELO script

Halon 4.0 introduced a feature we call “live staging” where you can deploy multiple running configurations at the same time, with per-connection conditions. It allows you to reliably rollout changes or new features to a production system for only a few testing IPs, or a select percentage of the traffic. With Halon 4.7, we proudly present “live debugging” using which you can add logpoints to your scripts. It enables you to inspect the full context of SMTP transactions in real-time, using the live staging conditions as connection selector.

Those points are added directly to the Monaco-based IDE, and results are inspected on a per-connection basis. You can create multiple points, triggered by multiple messages, and jump back and forth between them.

We’ve also added a HELO/EHLO phase script, support for ARC in DKIMSign() and a full implementation of draft 18 on Github, EdDSA (ed25519) and a native boolean type with corresponding strict comparison operator. The standard library have many new functions such as rsa_sign() and verify, idna_encode() and decode, aes_encrypt() and decrypt.

We hope that the live debugging will come handy! Please see the changelog on Github for a full list of improvements and changes, or get in touch with us if you want more detailed information.

Halon 4.6 “curry” with outbound anti-spam

You probably know from before that Halon’s scriptable SMTP server enable email providers to avoid blacklisting and increase deliverability. The 4.6 release, “curry”, contains Cyren’s outbound anti-spam (OAS). In combination with our cluster-synchronised rate limit function, it provides incredibly effective and accurate abuse prevention. Just like their Cyren’s inbound anti-spam, OAS uses a hash-sharing technology called recurrent pattern detection (RPD) that identifies outbreak patterns. It’s designed to detect spam from internal sources rather than external, and doesn’t report/contribute any signatures since it could blacklist your own infrastructure.

With the flexibility of scripting you can determine customer/sender identities accurately even in mixed traffic. This is used as identifier for rate limits based on classifiers such as Cyren’s OAS, delivery failure rate, queue size, etc. By using IP source hashing and alternative IPs for suspicious traffic, deferring obvious abuse and controlling connection concurrency, you can achieve high deliverability with minimal administration.

The 4.6 release comes with many additional features and improvements. It adds SNI support to the TLS functions. The Monaco-based code editor now have additional code completion, built-in documentation, tabs, and a mini-map.

For more information on the release, see the full changelog on GitHub. If you want to try Cyren’s outbound anti-spam, contact our sales team.

Halon 4.6 “funny” supporting our SMTP LANG extension

In the beginning, everything was ASCII and English. Since then, we’ve seen Unicode (international character sets) and IDN (international domains names) become widely adopted. Last year we implemented SMTPUTF8 that enables international mailboxes.

So why not support other languages in text-based protocols? We give to you “The SMTP Service Extension for Protocol Internationalization” RFC draft, introducing the EHLO keyword LANG. It will be the first SMTP software to support our to-be submitted RFC draft. Initially it will support Swedish, Spanish and Australian, and will default to Swedish when talking to supported systems.

250 Ok
250 Tack
BREV TILL:<hå[email protected]ä>
250 Tack
Subject: asdf

250 Togs emot
250 Vi ses!

If you made it this far, April fool! We will publish information on the upcoming 4.6 release some time after the 1st of April.

Happy easter!