← nostrmail.org

Run your own bridge.

Connect legacy email and Nostr on infrastructure you control. Pick your setup below. You'll get one .env and one docker-compose.yml to copy, tailored to your choices.

Configure my setup ↓
What do you want to do?
Outbound SMTP
Policy & identity Advanced

Optional. A whole domain (example.com) or a subdomain (nostr.example.com) both work. Whatever you enter is used for the mail host, DNS records, addresses and tests below.

Setup

Everything runs from published images with Docker Compose. The files below are generated for your selection. Internal wiring (service hostnames, the shared signing key) is already filled in.

First: your SMTP server

postfix-rspamd-docker ships its own config, so it runs as a separate stack. Repo →

Prerequisites: a public IP whose reverse DNS (PTR) matches MAIL_HOSTNAME, your sending domain(s), and port 587 open.

postfix .env
MAIL_HOSTNAME=mail.example.com
MAIL_DOMAINS=example.com
SMTP_USERS=postmaster@example.com:change-me-strong-password
SUBMISSION_PORT=587
Run it, then generate DKIM keys
git clone https://github.com/nogringo/postfix-rspamd-docker.git
cd postfix-rspamd-docker
cp .env.example .env
# edit .env: set MAIL_HOSTNAME, MAIL_DOMAINS, SMTP_USERS
docker compose up -d
docker compose exec rspamd rspamadm dkim_keygen -d example.com -s dkim -b 2048
cd ..

It publishes 587 on the host, so the bridge reaches it at mail.example.com on port 587 (its MAIL_HOSTNAME). Use the SMTP_USERS account as SMTP_USERNAME / SMTP_PASSWORD in the .env below, and publish the DNS records further down before sending.

Create .env

Make a new folder, save this as .env, and fill in the placeholder values.

.env

Generate WEBHOOK_SIGNING_KEY with openssl rand -hex 32. It is defined once here and shared by both inbound services automatically.

Generate each decision token with openssl rand -hex 32 too.

Create docker-compose.yml

Save this next to your .env, in the same folder.

docker-compose.yml

Launch

Bring the whole stack up.

docker compose up -d

Then apply the nmail-api database migrations once (they ship as SQL in the repo):

One-time database migrations
git clone --depth 1 https://github.com/nogringo/nmail-api.git
for f in nmail-api/migrations/*.sql; do docker compose exec -T postgres psql -U nmail -d nmail < "$f"; done

NIP-05 is then served at /.well-known/nostr.json?name=<local-part>, and the admin console at /admin when you set ADMIN_PASSWORD.

DNS records

Configure these at your DNS provider, using the domain from the configurator above. Replace the IPs and DKIM key with your own.

Inbound (MX)

Route legacy mail to your bridge server. Add an A/AAAA record for the mail host too.

MX + A
example.com.            MX   10 mail.example.com.
mail.example.com.       A       203.0.113.10

Self-hosted SMTP (deliverability)

Reverse DNS (PTR) for your IP must resolve to mail.example.com. Set this with your hosting provider; it must match MAIL_HOSTNAME. Then publish:

A / AAAA
mail.example.com.       A       203.0.113.10
mail.example.com.       AAAA    2001:db8::1
SPF (TXT)
example.com.            TXT  "v=spf1 mx ~all"
DKIM (TXT): paste the key from rspamadm dkim_keygen
dkim._domainkey.example.com.  TXT  "v=DKIM1; k=rsa; p=MIGfMA0GCSq...your-public-key..."
DMARC (TXT)
_dmarc.example.com.     TXT  "v=DMARC1; p=none; rua=mailto:postmaster@example.com"

Provider SMTP

Your SMTP provider (Mailgun, SendGrid, Amazon SES, etc.) documents the exact SPF, DKIM and tracking-CNAME records to add for your sending domain. Follow their dashboard. No mail server to run.

NIP-05 identity

To serve NIP-05 from your domain, expose nmail-api's /.well-known/nostr.json at https://example.com/.well-known/nostr.json (reverse-proxy it).

Test it

Inbound

Send a normal email from any mail client to a bridged address, then watch it flow and confirm the Nostr event arrives in your client / relays.

docker compose logs -f haraka-webhook webhook

Outbound

From a Nostr Mail client, send a message to a legacy email address and confirm delivery (check spam too). Watch the bridge:

docker compose logs -f bridge

Self-hosted SMTP

Verify SMTP auth + TLS, then score deliverability against a service like mail-tester.com before going live.

swaks --to test@example.com --from postmaster@example.com \
  --server mail.example.com:587 --tls \
  --auth LOGIN --auth-user postmaster@example.com --auth-password 'change-me-strong-password' \
  --body "Test from my bridge"

Policy & identity

Hit the NIP-05 endpoint and confirm a decision call appears in the nmail-api logs when you send or receive.

curl 'http://localhost:3000/.well-known/nostr.json?name=alice'