Skip to content

Deploying a Postal App

Introduction

Postal is an open-source mail server for transactional and bulk email, combining a web console, SMTP ingress, and message tracking. Deploying Postal with a Dockerfile on Klutch.sh keeps builds reproducible, secrets managed, and storage persistent—all configured from klutch.sh/app. This guide walks through installation, repo setup, Dockerfile, environment, storage, multi-service port strategy, and sample SMTP usage.


Prerequisites

  • A Klutch.sh account (sign up)
  • A GitHub repository with your Postal Dockerfile (GitHub is the only supported git source)
  • External MySQL-compatible database (e.g., MariaDB) and RabbitMQ broker
  • DNS control for sending domains, SPF/DKIM/DMARC, and inbound MX pointing to your Postal host

For onboarding, see the Quick Start.


Architecture and ports

  • Web console/API: HTTP on internal port 5000 → choose HTTP traffic and set internal port to 5000.
  • SMTP submission: run a second Klutch.sh TCP app (same image/env) on internal port 2525; select TCP traffic and set internal port to 2525 to accept authenticated SMTP. Connect on example-app.klutch.sh:8000 externally (Klutch TCP listens on 8000), so align your clients accordingly.
  • Inbound MX on port 25 is not available in Klutch.sh; use 2525 for submissions.

Repository layout

postal/
├── Dockerfile # Must be at repo root for auto-detection
└── README.md

Keep secrets out of Git; store them in Klutch.sh environment variables.


Installation (local) and starter commands

Validate locally (requires running MySQL and RabbitMQ):

Terminal window
docker build -t postal-local .
docker run -p 5000:5000 -p 2525:2525 \
-e POSTAL_HOSTNAME=postal.local \
-e POSTAL_DOMAIN=example.com \
-e RABBITMQ_URL=amqp://user:pass@localhost:5672/ \
-e DB_HOST=localhost \
-e DB_USER=postal \
-e DB_PASS=changeme \
-e DB_NAME=postal \
-e SECRET_KEY_BASE=$(openssl rand -hex 64) \
postal-local

Dockerfile for Postal (production-ready)

Place this at the repo root; Klutch.sh auto-detects Dockerfiles.

FROM ghcr.io/postalserver/postal:latest
ENV PORT=5000
ENV SMTP_PORT=2525
EXPOSE 5000 2525
CMD ["postal", "run"]

Notes:

  • Pin to a stable tag (e.g., ghcr.io/postalserver/postal:3.3.2) for predictable upgrades.
  • postal run starts both web and SMTP listeners; ports are parameterized for Klutch.sh.

Environment variables (Klutch.sh)

Configure these before deploying:

  • PORT=5000 (web)
  • SMTP_PORT=2525 (SMTP submission)
  • POSTAL_HOSTNAME=postal.example.com
  • POSTAL_DOMAIN=example.com
  • RABBITMQ_URL=amqp://<user>:<pass>@<host>:5672/
  • DB_HOST=<db-host>
  • DB_USER=<db-user>
  • DB_PASS=<db-password>
  • DB_NAME=postal
  • SECRET_KEY_BASE=<secure-random-hex>
  • RAILS_ENV=production
  • Optional: POSTAL_SMTP_USERNAME, POSTAL_SMTP_PASSWORD, POSTAL_SMTP_FROM, SMTP_TLS=true

If you deploy without the Dockerfile and need Nixpacks overrides:

  • NIXPACKS_START_CMD=postal run
  • NIXPACKS_RUBY_VERSION=3.2

Attach persistent volumes

Add mount paths and sizes in Klutch.sh storage settings (no names required):

  • /opt/postal/storage — message storage and logs.

Ensure the paths are writable inside the container.


Deploy Postal on Klutch.sh (Dockerfile workflow)

  1. Push your repo with the Dockerfile at the root to GitHub.
  2. In klutch.sh/app, create a new app for the Postal web console.
  3. Select HTTP traffic and set the internal port to 5000.
  4. Add the environment variables above and attach a volume at /opt/postal/storage sized for your retention.
  5. Deploy. Your console will be reachable at https://example-app.klutch.sh.
  6. Create a second app (same GitHub repo and env) for SMTP submission: choose TCP traffic, set the internal port to 2525, and attach the same storage path/size.
  7. Point SMTP clients to example-app.klutch.sh on external port 8000 (Klutch TCP) with credentials you configure in Postal.

Sample SMTP usage

Configure an SMTP client (e.g., msmtp or app settings):

  • Host: example-app.klutch.sh
  • Port: 8000 (Klutch TCP) → maps to internal 2525
  • TLS: optional (enable if configured)
  • Username/Password: values created in Postal
  • From: a verified sender on your domain

Test with swaks:

Terminal window
swaks --to you@example.com --from no-reply@example.com \
--server example-app.klutch.sh:8000 \
--auth LOGIN --auth-user postal-user --auth-password postal-pass \
--data "Subject: Test from Klutch\r\n\r\nHello from Postal on Klutch.sh"

Health checks and production tips

  • Use an HTTP readiness probe on / (web UI) for the HTTP app.
  • Monitor RabbitMQ and DB health; keep credentials in Klutch.sh secrets and rotate regularly.
  • Enforce SPF/DKIM/DMARC for sending domains; align MX records if you forward inbound mail elsewhere.
  • Pin image versions and test upgrades in staging before production rollout.
  • Watch storage usage on /opt/postal/storage and resize volumes proactively.

Postal on Klutch.sh offers a reproducible Docker workflow, isolated web and SMTP services via separate apps, managed secrets, and persistent storage—without extra YAML or CI config. Configure ports, attach volumes, connect MySQL/RabbitMQ, and start sending.