Why agencies need a proper SMTP platform
Running client email delivery with Postfix alone means flying blind. The MTA delivers or rejects, but it won't tell you why a bounce occurred, which campaign degraded a domain's reputation, or which client is consuming the most sending resources.
For an agency managing 10, 20 or 50 client domains, that opacity is a direct operational risk. A single misconfigured client can trigger a blacklisting of the shared IP and penalise the entire portfolio. And when the client calls to report a problem, you have nothing to show them.
Postal solves this by adding a full control layer on top of the SMTP pipeline.
What Postal brings to your agency
- Multi-server web interface: create an isolated sending server per client or per project, each with its own SMTP credentials and API key.
- Per-server statistics: incoming and outgoing volume and bounces, graphed over 24 h, 48 h or 30 days — one server per client gives you a per-client view.
- Real-time bounce management: every failed delivery is recorded and classified (
SoftFailtemporary,HardFailpermanent), every incoming bounce is linked to the original message, viewable in the interface and dispatched via webhook to your application. - REST API and webhooks: integrate Postal with your CRM, e-commerce platform or invoicing tool — one sending endpoint, events in return.
- Message queues: sends are queued and traceable through to delivery receipt or final error, with no black box.
- Client isolation: each Postal server can be given its own IP pool (
use_ip_poolsoption) and its own send limit — with separate IPs, one client in difficulty does not affect the others' reputation. - MIT licence: open source, no per-email cost, no third-party vendor dependency.
Prerequisites: VPS, port 25 and dedicated IPv4
Postal v3.3.7 installs via Docker. The official prerequisites are:
Resources: at least 2 vCPU and 4 GB of RAM. The documentation strongly recommends a server dedicated to Postal, running no other software. Allow at least 25 GB of SSD storage — message logs can grow quickly depending on your configured retention period.
Operating system: any distribution that runs Docker Engine and the Docker Compose plugin (this guide uses Ubuntu 24.04 LTS), plus git, curl and jq.
Database: MariaDB 10.6 or higher — the 10.6 branch has been out of community maintenance since July 2026, so aim for 10.11 or newer. MySQL is explicitly not supported. The innodb_log_file_size parameter must be set to at least 10 times the maximum message size.
Port 25: the critical point. Outbound port 25 must be open for Postal to deliver messages to recipient servers. Many cloud providers block it by default — confirm your VPS has a dedicated IPv4 and that port 25 is unblocked before starting installation.
rDNS: the reverse DNS of your IPv4 must point to your Postal hostname (e.g. postal.your-agency.com). A missing or incorrect PTR gets your messages rejected: since February 2024 Gmail has required a valid PTR for every sending IP.
Installing Postal on a VPS
Prepare the server and install Docker
Log in as root on your Ubuntu 24.04 VPS, update packages, then install Docker Engine and the Compose plugin:
apt update && apt upgrade -y curl -fsSL https://get.docker.com | sh apt install -y git curl jq docker --version && docker compose versionVerify that outbound port 25 is open:
nc -zv smtp.gmail.com 25. If the connection fails, contact your hosting provider to unblock it.Configure DNS for your Postal server
Before bootstrapping, create DNS records for your Postal installation domain (e.g.
postal.your-agency.com):- A record:
postal.your-agency.com→ VPS IP
- rDNS (PTR): configure this in your control panel so your IP resolves back topostal.your-agency.com
- Global SPF (TXT atspf.postal.your-agency.com):v=spf1 ip4:<VPS_IP> ~all
- Return path:rp.postal.your-agency.comwith an A record to the IP, an MX10 postal.your-agency.com, a TXTv=spf1 a mx include:spf.postal.your-agency.com ~alland, after bootstrap, the DKIM record printed bypostal default-dkim-recordatpostal._domainkey.rp.postal.your-agency.comWait for DNS propagation (15 to 30 minutes) before proceeding.
Bootstrap the Postal configuration
Clone the official installation repository, which provides the
postalcommand, then generate the configuration:git clone https://github.com/postalserver/install /opt/postal/install ln -s /opt/postal/install/bin/postal /usr/bin/postal postal bootstrap postal.your-agency.comThis generates
postal.yml,signing.keyand aCaddyfilein/opt/postal/config, plus adocker-compose.yml(in/opt/postal/install) pinned to the latest release. Openpostal.ymland fill in the MariaDB credentials, notification SMTP and the DNS names of your installation (dnssection).Start MariaDB and initialise the database
Launch a dedicated MariaDB container, reachable only locally and protected by a generated password, then initialise the Postal schema:
openssl rand -hex 24 > /root/postal-db.pass && chmod 600 /root/postal-db.pass docker run -d --name postal-mariadb \ -p 127.0.0.1:3306:3306 \ -e MARIADB_ROOT_PASSWORD="$(cat /root/postal-db.pass)" \ -e MARIADB_DATABASE=postal \ --restart always mariadb:10.11 postal initializeCopy this password into the
main_dbandmessage_dbsections ofpostal.ymlbefore runningpostal initialize.Create the first admin user
Create your administrator account to access the web interface:
postal make-userEnter the email address, name and password for the administrator.
Start Postal and configure the reverse proxy
Launch all Postal services (web, workers, SMTP):
postal start postal statusPostal exposes the web interface on
127.0.0.1:5000, unreachable from the Internet. Place a reverse proxy (Caddy or nginx) in front to terminate TLS, then accesshttps://postal.your-agency.com.Create an organisation and first sending server
In the Postal interface, create an organisation (your agency), then a sending server for your first client. Each server has its own SMTP credentials, its own API key and its own sending domains — it is the client isolation unit.
Note the SMTP hostname, port (25 by default, configurable via
smtp_server.default_port) and the generated credentials: these are the settings to hand to the client application or configure in its sending panel.
Configuring a sending domain
In each Postal sending server, add the domains from which your clients will send email. For each domain, Postal automatically generates a 1024-bit RSA key pair and a unique DKIM selector (format postal-XXXXXX._domainkey).
DNS records to publish for each client domain:
SPF — add include:spf.postal.your-agency.com in the apex TXT record:
v=spf1 include:spf.postal.your-agency.com ~allDKIM — publish the TXT value shown in the interface at the generated subdomain:
postal-XXXXXX._domainkey.client-domain.com TXT "v=DKIM1; t=s; h=sha256; p=<public key>"Return Path (recommended) — a CNAME that receives bounces and aligns SPF for DMARC:
psrp.client-domain.com CNAME rp.postal.your-agency.comPostal checks these records automatically every hour and flags any missing or incorrect record in the interface. The Check my records are correct button triggers an immediate manual check.
DMARC: the final piece of deliverability
With SPF and DKIM in place, add a DMARC policy on each client domain to tell receivers how to handle alignment failures. Start in monitoring mode (p=none) to collect reports without risk of blocking, then progressively harden to p=quarantine and p=reject:
_dmarc.client-domain.com TXT "v=DMARC1; p=none; rua=mailto:[email protected]; fo=1"The rua attribute sends daily aggregate reports to your address — you will see which sources send on your behalf, legitimate or otherwise. Postal signs each message with the domain's DKIM key once its record is validated, and the psrp return path aligns SPF: on correctly configured domains, DMARC will pass from day one.
Bounce management and statistics
This is the most visible difference between Postal and a bare Postfix relay. In the Messages tab of each sending server, every sent email is tracked with its status: Pending, Sent, Held, SoftFail, HardFail, Bounced.
When a delivery fails or a bounce comes back, Postal:
1. Records the exact rejection reason in the message log (e.g. 550 5.1.1 The email account does not exist)
2. Updates the delivery status in the interface (HardFail if the recipient server refuses during the SMTP session, Bounced if a bounce message arrives later)
3. Fires a webhook event (MessageDeliveryFailed or MessageBounced) to your configured HTTP endpoint
Schematically, a failed delivery reads like this (simplified example):
[2026-10-15 09:14:22] Delivery attempt to mx1.example.com (203.0.113.10:25)
[2026-10-15 09:14:22] << 550 5.1.1 <[email protected]> User unknown
[2026-10-15 09:14:22] Message marked as HardFail (permanent)Per-server statistics show incoming volume, outgoing volume and bounces over 24 h, 48 h or 30 days. These data let you detect a deliverability issue before the client notices it themselves.
Postal vs SaaS solutions vs Postfix relay
Scroll the table
| Criterion | Postal (self-hosted) | Mailgun / Postmark | SMTP relay Postfix |
|---|---|---|---|
| Visibility | Full interface: per-message log, bounce log, per-server statistics | SaaS dashboard, log retention depends on the plan | No interface — system logs only |
| Cost | VPS + administration time (no per-email cost) | Billing based on sending volume (see each provider's pricing) | VPS only (no software cost) |
| Control | Total: IP, retention, bounce policy, per-client isolation | Partial: policies imposed by provider, shared IPs by default | Full routing control, zero visibility |
| Send limit | Limited by VPS resources and IP reputation — scalable | Quotas per plan, scale-up billed | Limited by VPS — no native per-domain quota management |
An email infrastructure you control
Postal is the tool agencies look for when they realise Postfix alone is no longer enough to operate a client portfolio. The platform brings the visibility that was missing — structured logs, tracked bounces, per-server statistics — without the pricing constraints and vendor dependencies of SaaS alternatives.
A VPS with 2 vCPU, 4 GB of RAM and a dedicated IPv4 is sufficient to get started. Unblocked port 25 and a correctly configured rDNS are the two prerequisites that many providers do not fulfil by default — check them before ordering.
The articles Postfix SMTP relay on VPS and VPS email deliverability: port 25 and PTR complete this guide to cover deliverability as a whole.