Postal: Open Source Mail Delivery Platform
Postal is a complete and fully-featured mail server for incoming and outgoing e-mail, designed to be an open-source alternative to services like Sendgrid or Mailgun.
Prerequisites
Before deploying Postal, ensure you have the following installed and configured:
- Operating System: Ubuntu 20.04 LTS or newer (recommended).
- Ruby: Postal is built with Ruby. A compatible version will be installed during the setup process.
- MySQL/MariaDB: A database server for storing Postal's data.
- RabbitMQ: A message broker for handling background jobs.
- Redis: An in-memory data store, used for caching and session management.
- NGINX: A web server to proxy requests to Postal's web interface.
- DNS Configuration:
Arecord for your Postal web interface (e.g.,postal.example.com).Arecord for your SMTP hostname (e.g.,smtp.example.com).MXrecords pointing to your SMTP hostname.SPFandDKIMrecords for email authentication.
- Server Resources: Minimum 2 CPU cores, 4GB RAM, and 40GB storage.
Installation
The recommended installation method for Postal is using the provided curl script, which automates most of the setup.
-
Log in as root:
sudo -i -
Download and run the installation script:
curl https://install.postal.dev/install | shThis script will:
- Install necessary dependencies (Ruby, MySQL, RabbitMQ, Redis, NGINX).
- Set up Postal's database.
- Configure system services.
- Prompt you for configuration details during the process.
-
Follow the on-screen prompts: The installer will ask for information such as:
- The hostname for your Postal web interface (e.g.,
postal.example.com). - The hostname for your SMTP server (e.g.,
smtp.example.com). - Database credentials.
- The hostname for your Postal web interface (e.g.,
Configuration
Postal's configuration is managed through a postal.yml file, typically located at /opt/postal/config/postal.yml. The installer will generate a basic configuration, but you can customize it further.
The ConfigSchema in lib/postal/config_schema.rb defines available configuration options. Key configuration groups include:
postal:web_hostname: The hostname for the Postal web interface (default:postal.example.com).web_protocol: The HTTP protocol for the web interface (default:https).smtp_hostname: The hostname for the Postal SMTP server (default:postal.example.com).use_ip_pools: Enable or disable IP pools (default:false).default_maximum_delivery_attempts: Max delivery attempts for messages (default:18).default_spam_threshold: Score at which a message is considered spam (default:5).
Example postal.yml snippet (for illustration, actual file generated by installer):
# /opt/postal/config/postal.yml
postal:
web_hostname: your.postal.domain.com
web_protocol: https
smtp_hostname: smtp.your.postal.domain.com
use_ip_pools: false
default_maximum_delivery_attempts: 18
default_maximum_hold_expiry_days: 7
default_spam_threshold: 5
database:
host: 127.0.0.1
port: 3306
database: postal
username: postal
password: your_database_password
# ... other configurations for rabbitmq, redis, etc.
After modifying postal.yml: You may need to restart Postal services for changes to take effect.
Build & Run
Postal is designed to run as a set of services. There isn't a typical "build" step in the development sense for deployment, as the installation script handles setting up the application.
Running Locally (Development)
For local development, you would typically clone the repository and set up the environment manually. This is generally not recommended for production.
-
Clone the repository:
git clone https://github.com/postalserver/postal.git cd postal -
Install Ruby dependencies:
bundle install -
Database setup:
- Configure your
config/database.ymlfor development. - Create and migrate the database:
bin/rails db:create bin/rails db:migrate - The
db/schema.rbfile defines the current database schema.
- Configure your
-
Start services: You would typically need to run the web server, SMTP server, and worker processes.
- Web server:
bin/rails server - SMTP server:
bin/rails postal:smtp_server:run(or similar, check Rake tasks) - Workers:
bundle exec rake postal:worker:run
- Web server:
Production Environment
In a production environment, Postal runs as system services managed by systemd. The installation script configures these automatically.
- Web interface: Handled by NGINX proxying to the Postal Rails application.
- SMTP server: Runs as a dedicated service, handling incoming mail (
app/lib/smtp_server/client.rb). - Message processing: Background workers process messages, handle deliveries, etc. (
lib/postal/message_db/message.rb).
Deployment
The primary deployment method is the automated installation script described in the "Installation" section. This script is designed for a single-server deployment.
Key components deployed:
- Postal Application: Ruby on Rails application.
- MySQL/MariaDB: Database for all Postal data (e.g.,
credentials,messages,serversas seen indb/initial_schema.rbanddb/schema.rb). - RabbitMQ: Message queue for internal communication and job processing.
- Redis: Caching and session management.
- NGINX: Reverse proxy and SSL termination for the web interface.
- Postal SMTP Server: A custom SMTP server written in Ruby, handling incoming mail.
Post-Installation Steps:
- Access the Web Interface: Navigate to the
web_hostnameyou configured (e.g.,https://postal.example.com). - Create Admin Account: The first time you access the web interface, you'll be prompted to create an administrator account.
- Configure DNS: Ensure your DNS records (A, MX, SPF, DKIM) are correctly pointing to your Postal server.
- Add Servers and Domains: In the Postal web interface, add your mail servers and domains.
- Generate API Keys/Credentials: Create credentials for sending mail through Postal. The
credentialstable in the database stores these.
Troubleshooting
Here are some common issues and their solutions:
-
550 5.1.1 Recipient address rejected: User unknown:- Cause: The recipient domain or address is not configured in Postal, or the server for the domain is not enabled.
- Solution: Ensure the domain is added to a server in Postal and that the server is active. Check your routes and aliases.
-
Emails are not being sent/received:
- Check Postal logs: The main Postal logs are usually found in
/opt/postal/log/postal.log. Look for errors related to SMTP connections, delivery attempts, or worker failures. - Check system services: Ensure all Postal services are running:
sudo systemctl status postal sudo systemctl status postal-web sudo systemctl status postal-smtp sudo systemctl status postal-worker sudo systemctl status mysql # or mariadb sudo systemctl status rabbitmq-server sudo systemctl status redis-server sudo systemctl status nginx - Firewall: Verify that ports 25 (SMTP), 587 (SMTP Submission), 465 (SMTPS), and 80/443 (HTTP/HTTPS) are open on your server's firewall.
- DNS Issues: Double-check your MX, SPF, and DKIM records using a DNS lookup tool. Incorrect DNS can lead to emails being rejected or marked as spam.
- Check Postal logs: The main Postal logs are usually found in
-
Web interface not loading:
- NGINX configuration: Check
/etc/nginx/sites-enabled/postal.conffor correct proxy settings. - Postal web service: Ensure
postal-webservice is running. - Firewall: Make sure ports 80 and 443 are open.
- NGINX configuration: Check
-
Database connection errors:
- Check MySQL/MariaDB service: Ensure the database server is running.
- Credentials: Verify database credentials in
/opt/postal/config/postal.ymlmatch those configured in your database. - Disk space: Ensure your database server has sufficient disk space.
-
Slow performance:
- Server resources: Check CPU, RAM, and disk I/O usage. Upgrade resources if necessary.
- Database optimization: Ensure your database is properly indexed and maintained.
- RabbitMQ: Check RabbitMQ queue lengths. If queues are backing up, it might indicate worker issues.
-
Updating Postal:
- Refer to the official documentation for upgrade instructions. Typically, this involves pulling the latest code and running database migrations.
bundle exec rake postal:generate_config_docsis mentioned inlib/postal/config_schema.rbfor regenerating config documentation after schema changes, which might be relevant during upgrades.