Skip to content

Getting started ​

notify-flow runs in your own Cloudflare account: one Worker, one D1 database and one queue.

You need Node.js 20+ and a Cloudflare account.

bash
npm install
cp wrangler.jsonc.example wrangler.jsonc # git-ignored: fill in your database_id before deploying
npm run db:migrate:local
npm run client:create -- my-app          # prints the API key once
cp .dev.vars.example .dev.vars           # fill in your SMTP credentials
npm run dev

To deploy:

bash
npx wrangler d1 create notify-flow       # copy the database_id into wrangler.jsonc
npm run db:migrate:remote                # on upgrades too: migrate before npm run deploy
npx wrangler queues create notify-flow-emails  # once: the async send queue
npx wrangler secret put SMTP_USERNAME    # repeat for SMTP_PASSWORD, SMTP_FROM_EMAIL, SMTP_FROM_NAME
npm run deploy
npm run client:create -- my-app --remote

NOTE

Gmail needs an app password when 2-step verification is on.

For development:

bash
npm test                                 # vitest inside workerd, with a local D1
npm run typecheck                        # regenerates worker types, then tsc

SMTP configuration ​

Credentials are stored as Cloudflare Secrets, never in the repository or in code.

NameWhereValue
SMTP_PROVIDERvars in wrangler.jsoncgmail, microsoft or generic
SMTP_HOST, SMTP_PORT, SMTP_SECURITYvars, optionalOverride the preset (SMTP_SECURITY is tls or starttls)
SMTP_AUTH_TYPEvars, optionalplain or login (default: per preset)
SMTP_USERNAME, SMTP_PASSWORDsecretSMTP account credentials
SMTP_FROM_EMAIL, SMTP_FROM_NAMEsecretSender identity
PresetHostPort, security and auth
gmailsmtp.gmail.com465 with TLS, AUTH PLAIN
microsoftsmtp.office365.com587 with STARTTLS, AUTH LOGIN
genericset SMTP_HOST587 with STARTTLS, AUTH PLAIN

WARNING

Microsoft 365 requires SMTP AUTH to be enabled on the sending mailbox, and Security Defaults block it. Microsoft is also retiring basic authentication for SMTP AUTH. If you use this preset, plan for OAuth2 (XOAUTH2 is on the roadmap).

Security ​

  • Per-client API keys, stored only as SHA-256 hashes.
  • Idempotency: retrying a request with the same Idempotency-Key never sends a duplicate email.
  • Rate limits: 300 requests per minute per IP (checked before the API key), 60 per minute per client, and RECIPIENT_LIMIT_PER_HOUR (default 5) emails per recipient and template for each client. Failed sends do not count.
  • No secrets in logs: delivery records and logs never contain variables, tokens, reset URLs or SMTP credentials.

Next ​

Wire your app to it with the integration guide, or look up an endpoint in the API Reference.