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-domain statistics: delivery rate, bounces, deliverability and sending volume — per sending domain, per period, exportable.
- Real-time bounce management: every returned message is recorded, categorised (hard/soft), 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 has its own IP pools, its own reputation and its own limits — one client in difficulty does not affect the others.
- 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. For volumes above 50,000 emails per day, 8 GB is recommended. Allow at least 25 GB of SSD storage — message logs can grow quickly depending on your configured retention period.
Operating system: Ubuntu 22.04 or Ubuntu 24.04 LTS with Docker Engine and the Docker Compose plugin.
Database: MariaDB 10.6 or higher. 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 record is the leading cause of rejection by major mail providers.
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 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
- SPF for the infrastructure domain:v=spf1 ip4:<VPS_IP> ~allWait for DNS propagation (15 to 30 minutes) before proceeding.
Bootstrap the Postal configuration
Pull the Postal image and run bootstrap to generate configuration files:
docker pull ghcr.io/postalserver/postal:latest mkdir -p /opt/postal/config docker run --rm -v /opt/postal/config:/config \ ghcr.io/postalserver/postal:latest \ postal bootstrap postal.your-agency.comThis generates
/opt/postal/config/postal.ymlandsigning.key. Openpostal.ymland fill in the MariaDB credentials, notification SMTP and the public URL of your installation.Start MariaDB and initialise the database
Launch a dedicated MariaDB container (or use an existing instance), then initialise the Postal schema:
docker run -d --name postal-mariadb \ -e MYSQL_ROOT_PASSWORD=<password> \ -e MYSQL_DATABASE=postal \ --restart always mariadb:10.11 docker run --rm -v /opt/postal/config:/config \ --network host \ ghcr.io/postalserver/postal:latest \ postal initializeCreate the first admin user
Create your administrator account to access the web interface:
docker run --rm -v /opt/postal/config:/config \ --network host \ ghcr.io/postalserver/postal:latest \ 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):
docker run -d --name postal \ --restart always \ --network host \ -v /opt/postal/config:/config \ ghcr.io/postalserver/postal:latest \ postal startPostal exposes the web interface on port 5000. Place a reverse proxy (Caddy or nginx) in front to terminate TLS, then access
https://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, 465 or 587) 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; k=rsa; p=<public key>"Return Path (recommended) — a CNAME to improve bounce tracking:
psrp.client-domain.com CNAME psrp.postal.your-agency.comPostal checks these records automatically every hour and flags any missing or incorrect record in the interface. The Check my records 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 itself produces SPF + DKIM aligned emails: 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: Sent, Delivered, SoftFail, HardFail, Bounced.
When a bounce is detected, 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
3. Fires a MessageBounced webhook event to your configured HTTP endpoint
A bounce log visible in the interface looks like:
[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-domain statistics aggregate, over sliding windows (24 h, 7 d, 30 d): volume sent, delivery rate, bounce rate, spam filter rejection rate. 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-domain statistics | SaaS dashboard with 30-day logs (plan dependent) | No interface — system logs only |
| Cost | VPS + administration time (no per-email cost) | Per-send billing (approximately $0.80–$1.20 per 1,000 emails) | 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-domain 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 SPF, DKIM and DMARC complete this guide to cover deliverability as a whole.