mail-forwarding-core (or simply core) is the reference implementation used by Haltman.io to provide a free, public, production-grade mail forwarding service.
It is designed to be:
-
Fully open-source
-
Stateless (no mailbox storage)
-
Abuse-aware by design
-
Deterministic and auditable
-
Scalable by composition, not complexity
There is no open-core, no artificial limitation, and no telemetry.
This document describes how to install, configure, and validate the full stack from scratch.
A public instance is available at https://forward.haltman.io/:

Architecture Overview
mail-forwarding-core is composed of five main building blocks:
Component | Role |
|---|---|
Postfix | SMTP engine and policy enforcement |
PostSRSd | Sender Rewriting Scheme (SRS) |
MariaDB | Domain and alias lookup backend |
OpenDKIM | Optional DKIM signing |
DNS | Authentication and routing |
High-level flow
Inbound Mail
↓
Postfix (smtpd)
↓ (domain + alias lookup)
MariaDB
↓
PostSRSd (SRS rewrite)
↓
Postfix (smtp)
↓
External Destination
No messages are stored. No queues are inspected. No content is logged.
Installation Order (Important)
The order below is mandatory:
-
MariaDB (schema + user)
-
DNS records (MX / SPF / DMARC)
-
PostSRSd
-
Postfix
-
OpenDKIM (optional, last)
Installing components out of order will cause misleading failures.
1. MariaDB (Lookup Backend)
MariaDB is used only as a lookup backend. Postfix never writes to it.
Install
sudo apt install mariadb-server
Create database and user
CREATE DATABASE maildb;
CREATE USER 'maildb'@'localhost' IDENTIFIED BY 'strong-password';
GRANT SELECT, INSERT ON maildb.* TO 'maildb'@'localhost';
FLUSH PRIVILEGES;
Required tables
domain
CREATE TABLE `domain` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`active` tinyint(1) DEFAULT 1,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
alias
CREATE TABLE `alias` (
`id` int(11) NOT NULL,
`address` varchar(255) NOT NULL,
`goto` varchar(255) NOT NULL,
`active` tinyint(1) DEFAULT 1,
`domain_id` int(11) NOT NULL,
`created` timestamp NULL DEFAULT current_timestamp(),
`modified` timestamp NULL DEFAULT current_timestamp()
ON UPDATE current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `uq_alias_address` (`address`),
KEY `address` (`address`),
KEY `domain_id` (`domain_id`),
CONSTRAINT `alias_ibfk_1`
FOREIGN KEY (`domain_id`) REFERENCES `domain` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
MariaDB setup is now complete.
2. DNS Configuration
Each forwarded domain must define DNS records correctly.
Required records
MX
example.org. MX 10 mail.example.net.
SPF
example.org. TXT "v=spf1 mx -all"
DMARC
_dmarc.example.org. TXT "v=DMARC1; p=none"
Optional (recommended): DKIM
If OpenDKIM is enabled later, a DKIM record will be required.
3. PostSRSd (Mandatory)
Mail forwarding requires SRS to preserve SPF alignment.
Install
sudo apt install postsrsd
Configuration
Edit /etc/default/postsrsd:
SRS_DOMAIN=example.org
SRS_SEPARATOR==
SRS_SECRET=/etc/postsrsd.secret
SRS_HASHLENGTH=4
SRS_HASHMIN=4
SRS_FORWARD_PORT=10001
SRS_REVERSE_PORT=10002
RUN_AS=postsrsd
SRS_LISTEN_ADDR=127.0.0.1
CHROOT=/var/lib/postsrsd
Generate secret
openssl rand -hex 32 | sudo tee /etc/postsrsd.secret
sudo chmod 600 /etc/postsrsd.secret
Start service
sudo systemctl enable postsrsd
sudo systemctl restart postsrsd
Validate:
ss -ltnp | grep 1000
4. Postfix (Core Engine)
Postfix acts strictly as a forwarding MTA.
Install
sudo apt install postfix postfix-mysql
Choose Internet Site, but delivery will be disabled.
Key principles
-
No local delivery
-
No open relay
-
MySQL-backed domains and aliases
-
Sender spoofing protection
-
Mandatory SRS integration
Files Overview
/etc/postfix/main.cf
Primary Postfix configuration.
Key characteristics:
-
No
mydestination→ no local delivery -
Virtual domains and aliases backed by MySQL
-
Explicit relay and recipient restrictions
-
HELO/EHLO hygiene
-
Integration points for:
-
SRS (TCP maps)
-
DKIM (milter)
-
TLS settings are intentionally commented out.
# Postfix compatibility level (after major upgrades)
compatibility_level = 3.6
# SMTP Identity
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
# Networking listen interfaces
inet_interfaces = all
inet_protocols = ipv4
# The hostname to send on SMTP HELO or EHLO command
smtp_helo_name = mail.example.com
# Disable local email delivery
mydestination =
# Virtual domains are managed by MySQL
virtual_alias_domains = mysql:/etc/postfix/mysql-virtual-domains.cf
# Virtual aliases are managed by MySQL
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-aliases.cf
# Disable stack details on unknown alias addresses errors
show_user_unknown_table_name = no
# Disable VRFY command to prevent alias enumeration
disable_vrfy_command = yes
# Disable SASL for security
smtpd_sasl_auth_enable = no
# The numerical Postfix SMTP server response code when a recipient address is local
unknown_local_recipient_reject_code = 550
# Avoid information disclosure to SMTP client
smtpd_banner = $myhostname ESMTP
# Wait to reject
smtpd_delay_reject = yes
# -------------------------------------------------
# Anti open-relay
# -------------------------------------------------
smtpd_relay_restrictions =
permit_mynetworks,
reject_unauth_destination
# -------------------------------------------------
# Recipient restrictions
# -------------------------------------------------
smtpd_recipient_restrictions =
permit_mynetworks,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
reject_unlisted_recipient
# -------------------------------------------------
# Sender restrictions (ANTI-SPOOFING DINÂMICO)
# -------------------------------------------------
smtpd_sender_restrictions =
permit_mynetworks,
check_sender_access regexp:/etc/postfix/block_srs_inbound.regexp,
check_sender_access mysql:/etc/postfix/mysql-block-local-senders.cf,
permit
# -------------------------------------------------
# Client limits
# -------------------------------------------------
smtpd_client_connection_count_limit = 15
smtpd_client_connection_rate_limit = 60
# -------------------------------------------------
# HELO / EHLO hygiene
# -------------------------------------------------
smtpd_helo_required = yes
smtpd_helo_restrictions =
permit_mynetworks,
reject_invalid_helo_hostname
# -------------------------------------------------
# TLS
# -------------------------------------------------
# TLS is intentionally commented out in this example.
# Enable only after valid certificates are provisioned.
#smtpd_tls_security_level = may
#smtp_tls_security_level = may
#smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
#smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_tls_received_header = no
# -------------------------------------------------
# SRS (forwarding)
# -------------------------------------------------
sender_canonical_maps = tcp:localhost:10001
sender_canonical_classes = envelope_sender
recipient_canonical_maps = tcp:localhost:10002
recipient_canonical_classes = envelope_recipient
# -------------------------------------------------
# OpenDKIM
# -------------------------------------------------
# OpenDKIM is intentionally commented out in this example.
# Enable only after valid DKIM signatures on DNS are provisioned.
# smtpd_milters = inet:127.0.0.1:8891
# non_smtpd_milters = $smtpd_milters
# milter_default_action = tempfail
/etc/postfix/master.cf
Service definitions used by Postfix.
-
Largely defaults
-
No unsafe overrides
-
No custom listeners exposed
Provided for completeness and transparency.
smtp inet n - y - - smtpd
pickup unix n - y 60 1 pickup
cleanup unix n - y - 0 cleanup
qmgr unix n - n 300 1 qmgr
tlsmgr unix - - y 1000? 1 tlsmgr
rewrite unix - - y - - trivial-rewrite
bounce unix - - y - 0 bounce
defer unix - - y - 0 bounce
trace unix - - y - 0 bounce
verify unix - - y - 1 verify
flush unix n - y 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - y - - smtp
relay unix - - y - - smtp
-o syslog_name=${multi_instance_name?{$multi_instance_name}:{postfix}}/$service_name
showq unix n - y - - showq
error unix - - y - - error
retry unix - - y - - error
discard unix - - y - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - y - - lmtp
anvil unix - - y - 1 anvil
scache unix - - y - 1 scache
postlog unix-dgram n - n - 1 postlogd
/etc/postfix/mysql-virtual-domains.cf
Defines how Postfix queries MySQL to determine which domains are accepted.
This file controls:
-
Which domains are considered local/virtual
-
Whether a domain is active
user = <MARIADB_USERNAME>
password = <MARIADB_PASSWORD>
hosts = 127.0.0.1
dbname = <MARIADB_DATABASE>
query = SELECT 1 FROM domain WHERE name='%s' AND active=1
/etc/postfix/mysql-virtual-aliases.cf
Defines how Postfix resolves email aliases via MySQL.
This file controls:
-
Address → destination mappings
-
Forwarding behavior
user = <MARIADB_USERNAME>
password = <MARIADB_PASSWORD>
hosts = 127.0.0.1
dbname = <MARIADB_DATABASE>
query = SELECT goto FROM alias WHERE address='%s' AND active=1
/etc/postfix/mysql-block-local-senders.cf
Implements dynamic sender spoofing protection.
Instead of returning data, this query intentionally returns a static REJECT when the sender domain matches an active local domain.
This prevents external clients from forging MAIL FROM addresses belonging to hosted domains.
This behavior is deliberate.
user = <MARIADB_USERNAME>
password = <MARIADB_PASSWORD>
hosts = 127.0.0.1
dbname = <MARIADB_DATABASE>
query = SELECT 'REJECT forged local sender' FROM domain WHERE active=1 AND name='%d' LIMIT 1
/etc/postfix/block_srs_inbound.regexp
Rejects inbound messages with SRS-formatted senders.
This ensures:
-
SRS is only used internally for forwarding
-
External SRS traffic is not accepted blindly
/^SRS[01]=/ REJECT SRS sender not accepted inbound
5. OpenDKIM (Optional, Recommended)
OpenDKIM signs outbound mail to improve deliverability.
Install
sudo apt install opendkim opendkim-tools
Socket
OpenDKIM listens on:
inet:127.0.0.1:8891
Postfix connects via milter.
Tables
-
KeyTable -
SigningTable -
TrustedHosts
Private keys are deployment-specific and must never be committed.
If OpenDKIM is not installed, simply remove milter directives from Postfix.
Files Overview
/etc/opendkim.conf
Main OpenDKIM daemon configuration.
Notable characteristics:
-
Runs as an unprivileged user
-
Logs to syslog with success and failure visibility
-
Uses relaxed/simple canonicalization
-
Signs only selected headers
-
Listens locally via an INET socket
Relevant excerpts:
Syslog yes
SyslogSuccess yes
LogWhy yes
Canonicalization relaxed/simple
SubDomains no
OversignHeaders From
UserID opendkim
UMask 007
Socket inet:8891@127.0.0.1
PidFile /run/opendkim/opendkim.pid
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList /etc/opendkim/TrustedHosts
InternalHosts /etc/opendkim/TrustedHosts
/etc/opendkim/KeyTable
Maps DKIM selectors and domains to private key files.
Example structure:
selector1._domainkey.example.org example.org:selector1:/etc/opendkim/keys/example.org/selector1.private
Notes:
-
Private key files must never be committed
-
File paths are deployment-specific
-
One selector per domain is typical, but multiple are supported
/etc/opendkim/SigningTable
Defines which domains or addresses should be DKIM-signed and which selector should be used.
Example structure:
*@example.org selector1._domainkey.example.org
This allows:
-
Per-domain signing rules
-
Flexible expansion to multiple domains
/etc/opendkim/TrustedHosts
Defines hosts and networks trusted by OpenDKIM.
This file is used for both:
-
InternalHosts -
ExternalIgnoreList
Typical entries include:
127.0.0.1
localhost
::1
Only mail originating from trusted sources will be signed.
Validation Checklist
-
MX resolves to Postfix host
-
SPF passes on forwarded mail
-
SRS rewrite visible in headers
-
No local delivery occurs
-
External spoofing is rejected
-
DKIM (if enabled) signs correctly
FAQ
Is this an open relay?
No. Relay and recipient restrictions are explicit.
Are mails logged?
No message content is logged. Only minimal MTA operational logs exist.
Is PostSRSd optional?
No. Forwarding without SRS breaks SPF.
Why reject inbound SRS addresses?
To prevent external SRS forgery and abuse.
Can I use multiple domains?
Yes. Domains and aliases are unlimited.
Is OpenDKIM mandatory?
No, but strongly recommended for production.
Does this store mailboxes?
No. This is forwarding only.
Security & Disclosure
If you find a vulnerability or misconfiguration:
We respond as fast as possible.
Community & Support
Join the Haltman.io Telegram group for:
-
Questions
-
Networking
-
Design discussions
-
Operational feedback
References
Final Notes
mail-forwarding-core is intentionally boring.
No magic. No abstractions. No vendor lock-in.
If you understand SMTP, you can understand — and trust — this stack.