logo
Mail Forwarding (Self-Host)mail-forwarding-api
Mail Forwarding (Self-Host)

mail-forwarding-api

Node.js + Express API to manage mail forwarding aliases. Handles subscribe, confirm, unsubscribe operations with rate limiting and email confirmation.

mail-forwarding-api is a Node.js/Express service maintained by a member of Haltman.io. It exposes HTTP endpoints that allow users to:

  • Request alias creation (subscribe)
  • Confirm alias creation via email token (confirm)
  • Request alias removal (unsubscribe)
  • Confirm alias removal via email token (unsubscribe confirm)

Key points:

  • This API does not receive emails
  • It only manages forwarding rules (aliases) by writing into the same MariaDB database used by the core stack
  • All operations are rate-limited, abuse-resistant, and confirmed via email tokens

This API does not work standalone. You must deploy the mail-forwarding-core stack first (Postfix + MariaDB + PostSRSd).


Installation

Requirements

  • Node.js (current LTS recommended)
  • A running core stack (MariaDB reachable with correct schema)
  • Working SMTP credentials (required for confirmation emails)
  • Redis (optional, recommended for production rate limiting)

Install

git clone https://github.com/haltman-io/mail-forwarding
cd ./mail-forwarding/mail-forwarding-api/app/
npm install

Configuration

Create .env

cp .env.example .env

Minimal required settings

APP_ENV=prod
APP_PORT=3000
TRUST_PROXY=1
APP_PUBLIC_URL=https://api.example.org
EMAIL_CONFIRM_CONFIRM_ENDPOINT=/forward/confirm
  • TRUST_PROXY must reflect how many reverse proxies are in front of the API (affects IP-based rate limiting)
  • APP_PUBLIC_URL is used to build confirmation links

Optional but recommended:

DEFAULT_ALIAS_DOMAIN=example.org

Running

node ./source/server.js

Optional with PM2:

pm2 start ./source/server.js --name mail-forwarding-api --no-daemon

HTTP Endpoints

All endpoints are GET-only. All inputs are query parameters. No JSON body / POST is used.

1) Create alias request

GET /forward/subscribe?name={handle}&to={destination}&domain={domain}
query
namestring
Required

Alias local-part (e.g., github)

query
tostring
Required

Destination mailbox (e.g., user@gmail.com)

query
domainstring

Alias domain. Defaults to DEFAULT_ALIAS_DOMAIN.

Responses: 200 ok, 400 invalid_input, 409 alias_taken, 429 rate_limited, 403 banned

2) Confirm alias creation

GET /forward/confirm?token={token}

Responses: 200 confirmed, 400 invalid_token, 404 token_not_found, 410 token_expired, 429 rate_limited

3) Remove alias request

GET /forward/unsubscribe?alias={full_alias_address}
query
aliasstring
Required

Full alias address (e.g., github@example.org)

Responses: 200 ok, 404 not_found, 429 rate_limited, 403 banned

4) Confirm alias removal

GET /forward/confirm?token={token}

Responses: 200 removed, 400 invalid_token, 404 token_not_found, 410 token_expired, 429 rate_limited


Possible Problems / Important Notes

  • Core stack not deployed: API may start, but operations will fail (missing schema / wrong DB)
  • SMTP misconfigured: subscribe/unsubscribe will not complete (no confirmation emails)
  • Behind proxy without TRUST_PROXY: rate limiting may treat all users as the same IP
  • No Redis in production: multi-instance deployments will have inconsistent rate limiting
  • Destructive behavior: this service writes directly into mail routing tables — test in staging first
Was this page helpful?
Built with Documentation.AI

Last updated today