Email notifications for Nostr private groups
- test/integration.sh: runs full E2E flow against fresh server - pnpm test and pnpm test:server scripts added - Root endpoint handles missing web UI gracefully (returns JSON) - database.ts reads DATA_DIR env var for test isolation - .gitignore updated for test artifacts |
||
|---|---|---|
| src | ||
| test | ||
| web | ||
| .env.template | ||
| .gitattributes | ||
| .gitignore | ||
| .nvmrc | ||
| .prettierignore | ||
| .prettierrc | ||
| build-in-production.sh | ||
| eslint.config.mjs | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| remove-pnpm-overrides.js | ||
| tsconfig.json | ||
Mailship
A Nostr email notification server. Receives events pushed from relays via NIP-9a, stores them, and sends daily or weekly digest emails.
Architecture
Flotilla ──HTTP──▶ Mailship (POST /subscription/email)
│ NIP-98 auth
│ returns {key, callback}
│
└──kind 30390──▶ relay or NPB
│
event matches filter
│
▼
POST /notify/:subId ──▶ Mailship
{id, relay} │
UUID in path ├── fetch event from relay
is the auth ├── store in SQLite (dedup)
│
cron fires ──▶ render digest ──▶ Postmark ──▶ email
Configuration
| Variable | Required | Description |
|---|---|---|
MAILSHIP_SECRET |
✓ | A nostr private key hex string for the server's identity |
MAILSHIP_NAME |
✓ | Name of this Mailship instance |
MAILSHIP_URL |
✓ | Public URL of this instance |
BASE_URL |
✓ | Base URL for callback URLs (same as MAILSHIP_URL typically) |
POSTMARK_API_KEY |
✓ | Postmark API key for sending emails |
POSTMARK_SENDER_ADDRESS |
✓ | Verified sender email in Postmark |
DEFAULT_RELAYS |
✓ | Comma-separated list of default relays |
INDEXER_RELAYS |
✓ | Comma-separated list of indexer relays |
SEARCH_RELAYS |
✓ | Comma-separated list of search relays |
PORT |
Port to run on (default: 3000) |
API
POST /subscription/email
Register for email digests.
Body: { email, frequency, pubkey }
Auth: NIP-98 (planned)
Response: { key, callback }
DELETE /subscription/:key
Unsubscribe.
Auth: NIP-98 (planned)
Response: { ok: true }
POST /notify/:id
NIP-9a relay push callback. Called by relays or NPB when matching events are found.
Body: { id, relay }
Response: { ok: true, stored: boolean }
Returns 404 if subscription not found or inactive.
GET /confirm?token=...
Confirm email address via link from confirmation email.
GET /unsubscribe?token=...
Unsubscribe via link from digest email.
Development
pnpm install
pnpm run build
pnpm run start
Forked from Anchor
Mailship is a fork of Anchor, stripped of push notification support and adapted for NIP-9a relay push event intake.