This is a postfix socketmap adapter for the userli project. It implements the socketmap protocol to provide dynamic lookups for aliases, domains, mailboxes, and senders.
The adapter is configured via environment variables:
USERLI_TOKEN: The token to authenticate against the userli API.USERLI_BASE_URL: The base URL of the userli API.SOCKETMAP_LISTEN_ADDR: The address to listen on for socketmap requests. Default::10001.METRICS_LISTEN_ADDR: The address to listen on for metrics. Default::10002.
In Postfix, you can configure the adapter using the socketmap protocol like this:
virtual_alias_maps = socketmap:inet:localhost:10001:alias
virtual_mailbox_domains = socketmap:inet:localhost:10001:domain
virtual_mailbox_maps = socketmap:inet:localhost:10001:mailbox
smtpd_sender_login_maps = socketmap:inet:localhost:10001:senders
You can run the adapter using Docker.
A docker-compose.yml file is provided for convenience.
docker compose up -d
# Create the database and load fixtures
docker compose exec userli bin/console doctrine:schema:create
docker compose exec userli bin/console doctrine:fixtures:load --no-debug
docker compose exec postfix postmap -q "example.org" socketmap:inet:adapter:10001:domainThe socketmap names supported are:
alias- For virtual alias lookupsdomain- For virtual domain lookupsmailbox- For virtual mailbox lookupssenders- For sender login map lookups
You can test the socketmap adapter using postmap:
# Test alias lookup
postmap -q "[email protected]" socketmap:inet:localhost:10001:alias
# Test domain lookup
postmap -q "example.com" socketmap:inet:localhost:10001:domain
# Test mailbox lookup
postmap -q "[email protected]" socketmap:inet:localhost:10001:mailbox
# Test sender lookup
postmap -q "[email protected]" socketmap:inet:localhost:10001:senders# Build and run with docker-compose
docker-compose up --build
# Or build manually
docker build -t userli-postfix-adapter .
docker run -e USERLI_TOKEN=your_token -e USERLI_BASE_URL=http://your-userli-instance -p 10001:10001 -p 10002:10002 userli-postfix-adapterThe adapter implements the Postfix socketmap protocol using netstrings for encoding. Each request and response is formatted as:
[length]:[data],
Where:
lengthis the decimal length of the data:is a delimiterdatais the actual request or response content,is the terminating comma
[length]:[mapname key],
Examples:
22:alias [email protected],- Look up alias for [email protected]18:domain example.com,- Check if domain example.com exists23:mailbox [email protected],- Check if mailbox [email protected] exists24:senders [email protected],- Get senders for [email protected]
The adapter returns one of these response types:
OK [data]- Successful lookup with dataNOTFOUND- No data found for the keyTEMP [reason]- Temporary error (retry later)PERM [reason]- Permanent error (don't retry)
Examples:
19:OK [email protected],- Alias found, destination is [email protected]4:OK 1,- Domain/mailbox exists8:NOTFOUND,- No data found20:TEMP Service error,- Temporary service error
The adapter exposes Prometheus metrics on /metrics (port 10002) and provides health check endpoints.
Socketmap Metrics:
userli_postfix_adapter_request_duration_seconds- Request duration histogramuserli_postfix_adapter_requests_total- Total request counteruserli_postfix_adapter_active_connections- Active connections gaugeuserli_postfix_adapter_connection_pool_usage- Connection pool usage (0-500)
HTTP Client Metrics:
userli_postfix_adapter_http_client_duration_seconds- Userli API request durationuserli_postfix_adapter_http_client_requests_total- Userli API request counter
Health:
userli_postfix_adapter_health_check_status- Health check status (1=healthy, 0=unhealthy)
All metrics include relevant labels (handler, status, endpoint, etc.).
/health- Liveness probe (always returns 200 OK)/ready- Readiness probe (checks Userli API connectivity)
Example Kubernetes configuration:
livenessProbe:
httpGet:
path: /health
port: 10002
readinessProbe:
httpGet:
path: /ready
port: 10002