Postfix Address Mapping Service
Clone or download
burgerdev update circleci config
* use single steps for fetch, build, test
* use new 'make docker' target
* remove ubuntu build (which was in fact also alpine)
Latest commit a916800 Jan 8, 2018



Implementation of a postfix tcp lookup table that transforms the requested address according to a configurable set of mapping rules. A common use case is to transform an address to a canonical form.

Built-in mapping rules are accept, reject, match a regular expression and replace a regular expression with a fixed string. Those can be combined with all and first. Additionally, you can use the case transforming rules lower and upper. The mapping rules are specified as S-expressions:

 (matches "^.*$")
 (replace "+[^@]*@" "@")

This accepts emails for domain and removes a sub-address (the plus part).



  • Ocaml >= 4.04.2
  • Opam

Build on Host

make fetch_deps # installs dependencies using opam
make build

# optionally, run tests and/or create API doc
# make test
# make doc

Build in Development Container

There's a special docker image for building this project. Run the above commands inside the container, or use the script. The latter builds the development image, compiles the OCaml sources, runs tests (triggered by environment variable CI) and builds the production image.

export CI=true
bash alpine


./main.native --help

Command line arguments:

  • -r <file> path to the rules file on the container (default: /rules/rules.sexp)
  • -b <address> IP address to bind to (default:
  • -p <port> listening port (default: 30303)
  • -u re-read the rules file for each request (default: false)

Docker Image

Run the AddressMapper as a docker container in the background, forward the port to localhost:30303 and use the rules file /tmp/rules.sexp below.

docker run -d -p 30303:30303 -v /tmp/rules.sexp:/rules.sexp:ro burgerdev/ocaml-addressmapper
  (lower (replace "+[^@]*@" "@"))

  (not (prefix_matches "sauron"))

        (matches "^[^@]+@business\.com$")
        (first ((matches "^ceo@.*")
                (matches "^pr@.*"))
      (equals "")

This file contains the following instructions (see for an explanation of the addressmapper rules):

  1. Address sanitizing.
    1. Convert the email address to lower case.
    2. Strip the sub-addresses.
  2. Keep Sauron on the far side of the walls.
  3. User database. If any of the sub-clauses matches, we got our user.
    1. There are two acceptable users at, the CEO and the Public Relations Department.
    2. The non-profit organization has just one email address, which is reserved for raising funds.

Let's see some examples for how to use the container we spawned:

echo "get CEO@business.COM" | nc localhost 30303
# we convert everything to lower case, so the result should be
# '200'.

echo "get" | nc localhost 30303
echo "get" | nc localhost 30303
# Both with and without a sub-address, this should result in
# '200'.

echo "get sauron@mord.or" | nc localhost 30303
# Sauron is explicitly excluded, this should be '500 not-found'.

echo "put sauron@mord.or" | nc localhost 30303
# This is not valid postfix mapper syntax, therefore '400 malformed request'.