Skip to content

Aerilym/simple-email-list

Repository files navigation

Simple Email List

A minimal API to collect email subscriptions with SQLite.

Requirements

  • Node.js 24 LTS
  • pnpm

Setup

pnpm install
pnpm build

Running

pnpm start

Port defaults to 3000. Override with the PORT env var.

Runs behind nginx — client IP is read from X-Forwarded-For.

API

POST /subscribe

curl -X POST http://localhost:3000/subscribe \
  -H 'Content-Type: application/json' \
  -d '{"email": "user@example.com"}'

Responses

Status Body
200 { "ok": true }
400 { "error": "Invalid email address" }
400 { "error": "Invalid JSON" }
400 { "error": "Payload too large" }
404 { "error": "Not found" }

Rate limited requests are silently dropped — they return 200 identically to a successful subscription.

CSV import

pnpm import -- path/to/file.csv

Expected format — one email per line, email header row:

email
user@example.com
another@example.com

Duplicate and invalid emails are skipped. A summary is printed on completion.

CSV export

pnpm export -- path/to/output.csv

Exports all emails in the database in the same format accepted by import.

Summary

pnpm summary

Prints a count of total emails and new emails in the last 7 and 30 days:

Total:        1000
Last 7 days:  12
Last 30 days: 47

Configuration

Env var Default Description
PORT 3000 Port to listen on
DB_PATH data/emails.db SQLite database path
RATE_LIMIT_ENABLED true Enable IP and email rate limiting

Rate limit: 10 requests per IP and per email address per hour.

Nginx

A template nginx config is provided in email-list.nginx.conf. It:

  • Redirects HTTP to HTTPS
  • Exposes only POST /subscribe and returns 404 for all other paths
  • Forwards the real client IP via X-Forwarded-For for rate limiting
  • Enforces a 2 KB body size limit at the nginx level

Copy and adjust the file (replace example.com and TLS paths), then:

cp email-list.nginx.conf /etc/nginx/sites-available/email-list
ln -s /etc/nginx/sites-available/email-list /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

Systemd

Copy and adjust email-list.service, then:

useradd -r -s /sbin/nologin email-list
cp email-list.service /etc/systemd/system/
systemctl enable --now email-list

The service expects the app to be deployed to /opt/email-list.

Development

pnpm test     # build + run tests
pnpm check    # format + lint + fix

Contributing

The goal of this project is a long-running, stable service that requires minimal maintenance. Contributions should respect that goal.

No runtime dependencies. The API uses only Node.js built-ins and SQLite (via the built-in node:sqlite module available in Node.js 22+). Do not add npm packages to dependencies. If something can be done with the standard library, it should be.

LTS versions only. Node.js and all tooling should track Active or Maintenance LTS releases. Avoid features or syntax that require a non-LTS version.

Stability over features. Prefer simple, explicit code over clever abstractions. New features should have a clear operational use case and should not increase the maintenance surface.

It just an email list. This is a simple email collector, nothing more. No new production-facing features should be added to extend functionality, the production API surface should do nothing more than collect emails.

About

Simple mailing list subscription API

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

  •  

Contributors