MTA integration

xListman integrates with an existing mail server rather than replacing it. Your MTA accepts mail for the list domain and hands it to xListman over LMTP (or the pipe-mode Unix socket); xListman delivers outbound mail back through your relay.

This is the step most first-time setups underestimate. Set aside time for it, and test each leg before moving on.

The flow

  1. Inbound. A message to dev@example.com arrives at your MTA. It is routed to xListman’s LMTP server, which parses the address — dev@example.com is a post, dev-subscribe@… is a subscription request, dev-request@… is an email command, and so on.
  2. Outbound. Posts, digests, and notices go through a persistent queue and out via SMTP to your relay (smtp.host:smtp.port).
  3. The bounce reverse leg. Outbound envelope senders are VERP-encoded — a message to alice@work.com on dev@example.com leaves with envelope sender dev-bounces+alice=work.com@example.com. If delivery fails, your MTA bounces a DSN back to that address, which routes in through the same LMTP transport and is attributed to Alice’s subscription. The reverse leg is part of the loop, not a separate channel.

Which path to use

  • LMTP — the primary path, validated end to end against Postfix and exim, including the VERP bounce reverse leg. Use this unless you have a reason not to.
  • Pipe mode — a Unix socket that a mail filter program hands messages to (xlistman deliver <address>). For setups where you’d rather pipe mail than run an LMTP listener.

The LMTP server

The LMTP server listens on lmtp.listen (:8024 by default) and is unauthenticated. In production, bind it to a private interface (127.0.0.1:8024) so only your MTA can reach it — don’t leave it exposed on a public address.

Guides

  • Postfix — the virtual_transport wiring.
  • exim — the manualroute router to an LMTP transport.
  • Pipe mode — using xlistman deliver with a pipe-based MTA config.

Testing without an MTA

To exercise xListman’s inbound half before wiring a real MTA, set smtp.mode: sink. Outbound mail is written as files to smtp.sink_dir instead of being relayed, so you can confirm the full pipeline with nothing but the binary:

smtp:
  mode: "sink"
  sink_dir: "./mail"

Each outbound message becomes one <nanoseconds>-<recipient>.eml file with X-Envelope-From: and X-Envelope-To: headers prepended.