postmarkd

    v0.1.0 · open source · one static Go binary

    Sending mail should be one line.

    postmarkd is a small daemon that sits next to your apps, on a server or as a container sidecar, and delivers their mail through Postmark. Use HTTP, SMTP, sendmail or the CLI. Your Postmark token stays in one place.

    Try it without a Postmark accountdocker run -e POSTMARKD_BLACKHOLE=true -p 8025:8025 ghcr.io/rossedman/postmarkd:0.1
    # Body from stdin, sent through Postmark
    $ df -h | postmarkd send -to ops@example.com \
        -subject "Disk usage on web-1"
    b7bc2f4a-e38e-4336-af7d-e6c392c2f817
    
    # Templates, streams, attachments
    $ postmarkd send -to ada@example.com \
        -template welcome -model '{"name":"Ada"}'

    How it works

    Every way in. One way out.

    Whatever your software speaks, postmarkd turns it into the same validated, rate-limited Postmark API call, over pooled connections and with retries that never send a message twice.

    • sendmailcron, mail, PHP mail(), git
    • SMTPRails, Django, Laravel, Grafana
    • HTTPPostmark SDKs, curl, any HTTP client
    • CLIshell scripts, CI jobs, alerts
    postmarkd
    • Defaults: From, message stream
    • Validation before Postmark sees it
    • Parallel sends, shared connections
    • Safe retries, optional async queue
    • Metrics, health, blackhole mode
    Postmark

    DKIM-signed and delivered to the inbox

    Features

    Small daemon. Everything you need.

    Postmark-compatible API

    The same endpoints and JSON as Postmark: /email, batches, templates. Existing SDKs work by changing the base URL.

    SMTP and sendmail

    A local SMTP listener and a drop-in sendmail. MIME, attachments, inline images and X-PM-* headers handled.

    Blackhole for tests

    Accept everything, send nothing, answer like Postmark. Tests read back what was “sent”. No account, no network.

    Message streams

    Receipts on outbound, newsletters on broadcast, per message or per request, even mixed in one batch.

    Built for volume

    500-message batches, a concurrency limit, pooled keep-alive connections and a bounded queue with back-pressure.

    DKIM, SPF, DMARC check

    postmarkd check-domain tells you which DNS records are missing, and the exact values to add.

    systemd native

    Socket activation (even port 25, unprivileged), readiness, watchdog, graceful drain and a hardened unit.

    Sidecar ready

    A 16 MB non-root image with a built-in health check. Compose, Kubernetes and CI examples included.

    Observable

    Prometheus metrics for every endpoint and Postmark call, health and readiness checks, structured logs.

    33,700messages per second end to end over the unix socket on 4 CPUs
    4.4 µsto validate and apply defaults to a message
    0third-party dependencies in the daemon
    16 MBdistroless, non-root container image

    Benchmarked against an instant fake Postmark, so these numbers are postmarkd’s own overhead. See the benchmarks.

    Install

    Running in a minute.

    # Debian / Ubuntu (for Fedora, RHEL: dnf install the .rpm; see the docs)
    $ VERSION=0.1.0 ARCH=$(dpkg --print-architecture)
    $ REL=https://github.com/rossedman/postmarkd/releases/download/v$VERSION
    $ curl -fsSLO $REL/postmarkd_${VERSION}_linux_$ARCH.deb
    $ sudo apt install ./postmarkd_${VERSION}_linux_$ARCH.deb
    
    $ sudo install -m 0600 /dev/stdin /etc/postmarkd/server-token <<< 'your-server-token'
    $ sudo systemctl enable --now postmarkd
    
    $ echo "Hello from $(hostname)" | postmarkd send -to you@example.com -subject "It works"

    Full getting-started guide

    Why postmarkd

    Why not call Postmark directly?

    For one app with a Postmark SDK, you should. postmarkd helps when mail comes from many places, or from places that can’t easily talk to Postmark.

    Postmark directlyWith postmarkd
    Server tokenCopied into every app, container and CI secretIn one place. Apps get nothing, or their own revocable token
    cron, PHP mail(), mailxConfigure Postfix as an authenticated TLS relaySymlink postmarkd as sendmail
    SMTP-only appsPostmark's SMTP host, TLS and credentials in eachlocalhost:2525, nothing else
    Tests and CITest token: needs network, can’t read back mailBlackhole mode: offline, assert on what was sent
    LatencyEvery send waits on the Postmark round tripLocal socket, or ?async=true returns immediately
    Defaults and rulesRepeated in each appSet once for the host

    Ship mail from anywhere in minutes.

    Free, open source and dependency-free. Read the docs, or try it right now in blackhole mode. No Postmark account needed.