This is a modern version of The Hacker's Choice's Free Mail Forwarding Service.
The Hacker's Choice's Free Mail Forwarding Service was developed and supported by Lou Cipher.
This project is a Mail Forwarding Service API built with Node.js and Express.
A simple diagram showing how it works:
It exposes HTTP endpoints that allow users to:
- Create email aliases (
subscribe) - Confirm alias creation via email
- Request alias removal (
unsubscribe) - Confirm alias removal via email
All operations are:
- Rate-limited
- Protected against abuse
- Confirmed via email tokens
- Persisted directly into the base-postfix-forwarder MariaDB database
This API does not receive emails. It only manages forwarding rules (aliases) that the base-postfix-forwarder mail server will later use.
This Node.js project depends on the base-postfix-forwarder to run properly.
Before installing or running this API, you MUST read and deploy the base-postfix-forwarder first, since this service writes directly into the same database used by the base-postfix-forwarder (Postfix + MariaDB stack).
👉 Read first:
📄 FWD-Basestack.md
- Node.js
- Express
- MariaDB
- Nodemailer
expresscorsdotenvexpress-rate-limitexpress-slow-downmariadbnodemailer
Client
│
│ HTTP Requests
▼
Node.js API (this project)
│
│ SQL INSERT / UPDATE / DELETE
▼
MariaDB (base-postfix-forwarder)
│
▼
Postfix (Mail Forwarding)
git clone https://github.com/haltman-io/mail-forwarding.git
cd ./mail-forwarding/appnpm installThis project does not ship with a .env file.
You must create one manually.
cp .env.example .envIf .env.example is not present, create a new .env file from scratch.
Below is a guided explanation of the required environment variables.
APP_ENV=dev
APP_PORT=3000
TRUST_PROXY=1APP_ENV:dev,hml, orprodAPP_PORT: Express listening portTRUST_PROXY: number of reverse proxies in front of the app (important for rate limiting by IP)
APP_PUBLIC_URL=http://127.0.0.1:8080
EMAIL_CONFIRM_CONFIRM_ENDPOINT=/forward/confirmUsed to generate confirmation links sent by email.
EMAIL_CONFIRMATION_TTL_MINUTES=10
EMAIL_CONFIRMATION_RESEND_COOLDOWN_SECONDS=60
EMAIL_CONFIRMATION_TOKEN_LEN=12
EMAIL_CONFIRMATION_TOKEN_MIN_LEN=10
EMAIL_CONFIRMATION_TOKEN_MAX_LEN=24Controls token lifetime, size, validation, and resend behavior.
SMTP_HOST=
SMTP_PORT=587
SMTP_SECURE=false
SMTP_AUTH_ENABLED=true
SMTP_USER=
SMTP_PASS=
SMTP_FROM="John Doe <john.doe@ccc.de>"
SMTP_TLS_REJECT_UNAUTHORIZED=trueMARIADB_HOST=
MARIADB_PORT=
MARIADB_USER=
MARIADB_PASSWORD=
MARIADB_DATABASE=These credentials must point to the SAME database used by the base-postfix-forwarder.
REDIS_URL=
REDIS_RATE_LIMIT_PREFIX=rl:
REDIS_CONNECT_TIMEOUT_MS=5000- If
REDIS_URLis empty, rate-limit uses in-memory storage (not shared). - For multi-instance setups, Redis is strongly recommended.
The API applies different limits per route, IP, alias, token, and destination.
Examples:
RL_GLOBAL_PER_MIN=300
RL_SUBSCRIBE_PER_10MIN_PER_IP=60
RL_CONFIRM_PER_10MIN_PER_IP=120These values are directly consumed by the middleware.
DEFAULT_ALIAS_DOMAIN=thc.orgUsed when the user does not specify ?domain=.
node ./source/server.jsOr with process managers:
pm2 start ./source/server.js --name mail-forwarding-api --no-daemonAll endpoints accept GET requests only. All input data must be provided via URL query parameters. No request body (JSON / POST) is used anywhere in this API.
Requests the creation of a new email alias.
/forward/subscribe?name=github&to=user@gmail.com&domain=example.org| Parameter | Required | Description |
|---|---|---|
name |
yes | Alias local-part (before @) |
to |
yes | Destination email address |
domain |
no | Alias domain |
- If
domainis omitted,DEFAULT_ALIAS_DOMAINis used.
| Status | Code | Meaning |
|---|---|---|
| 200 | ok |
Confirmation email sent |
| 400 | invalid_input |
Missing or invalid parameters |
| 409 | alias_taken |
Alias already exists |
| 429 | rate_limited |
Too many requests |
| 403 | banned |
IP or destination blocked |
| 500 | internal_error |
Unexpected server error |
Confirms alias creation using the token received by email.
/forward/confirm?token=AbC123xYz| Parameter | Required | Description |
|---|---|---|
token |
yes | Confirmation token |
| Status | Code | Meaning |
|---|---|---|
| 200 | confirmed |
Alias created successfully |
| 400 | invalid_token |
Token malformed |
| 404 | token_not_found |
Token does not exist |
| 410 | token_expired |
Token expired |
| 429 | rate_limited |
Too many attempts |
| 500 | internal_error |
Server failure |
Requests the removal of an existing alias.
/forward/unsubscribe?address=github@example.org| Parameter | Required | Description |
|---|---|---|
address |
yes | Full alias address to be removed |
| Status | Code | Meaning |
|---|---|---|
| 200 | ok |
Confirmation email sent |
| 404 | not_found |
Alias does not exist |
| 429 | rate_limited |
Too many requests |
| 403 | banned |
Blocked |
| 500 | internal_error |
Server error |
Confirms alias removal using the token received by email.
/forward/unsubscribe/confirm?token=ZyX987Ab| Parameter | Required | Description |
|---|---|---|
token |
yes | Unsubscribe confirmation token |
| Status | Code | Meaning |
|---|---|---|
| 200 | removed |
Alias deleted |
| 400 | invalid_token |
Token invalid |
| 404 | token_not_found |
Token unknown |
| 410 | token_expired |
Token expired |
| 429 | rate_limited |
Abuse detected |
| 500 | internal_error |
Server failure |
This API implements:
- IP-based rate limiting
- Alias-based throttling
- Destination email throttling
- Token attempt limits
- Cooldowns between confirmation emails
- Optional Redis-backed distributed rate limiting
- Ban checks before processing requests
- This project does not work standalone
- base-postfix-forwarder must be running first
- The database schema is owned by base-postfix-forwarder
- This API writes directly to production mail tables
- Always test in a staging environment
This project is licensed under the Unlicense, see the LICENSE file for details.
👉 Do NOT deploy this API without reading:
📄 FWD-Basestack.md
This service is stateless, destructive, and directly affects mail routing.
Use responsibly.
