npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mailregime

v0.5.0

Published

Country code → email-marketing-consent rules. Informational only, not legal advice.

Readme

mailregime

The c15t for email marketing law.

mailregime is a country-code → email-marketing-consent-rules library. Inspired by c15t (which solved the same problem for cookie banners), but for email opt-in / opt-out law instead.

You give it where the user is, why you're collecting their email, and what your relationship with them is. It tells you whether you can email them, what kind of opt-in is required, what the audit trail must contain, and which statute it's referring to.


⚠️ READ FIRST — DISCLAIMER

This software is informational only. It is not legal advice. It does not create an attorney–client relationship. The bundled data may be wrong, out of date, incomplete, or inapplicable to your facts. Use of mailregime is entirely at your own risk. The maintainers carry zero liability for any consequence of your use, including regulatory fines, litigation, or business loss. You must retain qualified counsel for your specific use case.

Three things you should know before installing:

  1. mailregime was written largely with an AI coding assistant. Bugs are expected. Pin a version, read diffs, verify outputs.
  2. No lawyer reviews this software or its data. The maintainers are not lawyers and do not retain lawyers to vet what ships. If you are an expert in privacy law and you spot a mistake, please open an issue or a PR — that is how the data gets better.
  3. mailregime is offline. It runs in your process, returns data, opens no network connections, stores nothing, transmits nothing. Inputs stay with you.

Full terms in LICENSE, DISCLAIMER.md, CONTRIBUTING.md, COLLABORATION.md. By using this software you agree to those terms.


Status

v0.5.0 — 67 countries bundled. Storage layer rebuilt on top of fumadb so you bring your own ORM client (Prisma, Drizzle, Kysely, TypeORM, MongoDB). The bundled PostgresStore and npx mailregime CLI shipped in v0.4.x were removed — see the migration note below. Public API may change in any minor version (standard 0.x contract). Pin a version, read diffs.

Install

npm install mailregime
# or: pnpm add mailregime  /  yarn add mailregime  /  bun add mailregime

Zero runtime dependencies for the rules engine. ESM only. Edge-runtime safe.

Self-host audit trail (optional)

If you want mailregime to handle consent-receipt storage for you (still in your database — we never host data), you bring your own ORM client and mailregime wraps it. Same pattern as @c15t/backend; under the hood both libraries use fumadb to translate one schema into per-ORM queries, so users get c15t-style "drop in your existing client and it just works" UX.

1. Install peer deps

# core + the fumadb runtime that the storage layer is built on
npm install mailregime fumadb

2. Generate the schema for your ORM

The shape mailregime expects is exposed via the standard fumadb codegen flow. Pick the adapter for your stack and run once:

// scripts/print-mailregime-schema.ts
import { factory } from "mailregime/store"
import { prismaAdapter } from "mailregime/store/adapters/prisma"
//   or: drizzleAdapter / kyselyAdapter / typeormAdapter / mongoAdapter

const db = factory.client(prismaAdapter({} as never, { provider: "postgresql" }))
console.log(db.generateSchema("1.0.0", "prisma").code)

Run it (tsx scripts/print-mailregime-schema.ts) and paste the output into your prisma/schema.prisma (or drizzle/schema.ts, etc.). Then run your ORM's migration tool — prisma migrate dev, drizzle-kit push, etc. The canonical SQL table name is mailregime_consent_receipts; if you applied an older mailregime SQL migration, the new schema is identical and there is nothing to migrate.

3. Use it in your route handler

import { getEmailRules } from "mailregime"
import { consentStore } from "mailregime/store"
import { prismaAdapter } from "mailregime/store/adapters/prisma"
import { prisma } from "@/lib/prisma" // your existing Prisma client

const store = consentStore({
  database: prismaAdapter(prisma, { provider: "postgresql" }),
})

const rules  = getEmailRules({ country, context: "newsletter-signup", relationship: "none" })
const record = await rules.buildAuditRecord({ ip, userAgent, sourceUrl, wording, formVersion })
await store.save(record, rules)

// GDPR Art. 15 access request
const history = await store.findBySubject(userIdHash)

// On unsubscribe
await store.withdraw(consentId, "one-click-unsub")

// Cron sweep — deletes receipts past their retention window
await store.sweep({ limit: 1000 })

Don't want the storage helper? Skip it. Importing mailregime alone never touches a database; the storage layer only loads when you import from mailregime/store.

Migrating from v0.4.x PostgresStore

v0.4.x shipped a PostgresStore that opened its own pg connection and a npx mailregime CLI for migrations. Both are gone in v0.5.0:

  • Replace new PostgresStore({ connectionString }) with consentStore({ database: <fumadb adapter> }) as shown above. The wire is now whatever your ORM client is configured against — managed-Postgres SSL just works.
  • Replace npx mailregime init / migrate with the codegen + your-ORM-migrate flow above.
  • Drop the postgres peer dep — mailregime no longer needs it.
  • The SQL table (mailregime_consent_receipts) and column names are unchanged. No data migration required.

Install with an AI agent

If you use Claude Code, Cursor, Codex, Aider, Windsurf, or similar — paste this prompt:

Install and wire up the `mailregime` library in this project.

Steps:
1. `npm install mailregime`
2. Read https://github.com/davidmoserai/mailregime/blob/main/AGENTS.md for integration guidance.
3. In every API route that collects an email for marketing purposes:
   - import { getEmailRules } from "mailregime"
   - import the matching adapter (vercel, cloudflare, or header)
   - call getEmailRules({ country, region, context, relationship })
   - branch on rules.canCollectForMarketing and rules.optIn
   - persist rules.buildAuditRecord({...}) to whatever storage I already use
4. Add `process.env.MAILREGIME_SILENCE_DISCLAIMER = "1"` in test files.
5. Do NOT remove or modify any disclaimer language anywhere.
6. mailregime is informational only, not legal advice — preserve that posture
   in any code comments you add.

mailregime ships an AGENTS.md and an llms.txt so agents can fetch full context in one request.

Why this exists

Cookie consent has c15t. Email marketing law has nothing equivalent.

ESP SDKs (Brevo, Mailchimp, Klaviyo, Resend) handle the mechanics of double opt-in but punt the legal "which country requires what" decision to the developer. Existing country-set libraries (eu-countries, c15t's classifier, etc.) are built for cookie/tracking law — a meaningfully different scope from email marketing law.

The result: every app that does email marketing across borders re-implements the same jurisdiction switch, usually wrong, usually with a TODO comment about "fix this later when we expand."

mailregime aims to be the shared, citation-backed source of truth.

Quickstart

import { getEmailRules } from "mailregime"
import { fromVercelRequest } from "mailregime/adapters/vercel"

const { country } = fromVercelRequest(request)

const rules = getEmailRules({
  country,                    // "DE" | "US" | null
  context: "lead-magnet",     // newsletter-signup | lead-magnet
                              // | account-signup | purchase
                              // | transactional | drip-onboarding
                              // | abandoned-cart | referral
                              // | co-registration | event-registration
                              // | channel-migration | win-back
  relationship: "none",       // none | existing-customer | former-customer
                              // | inquirer | donor | member
                              // | publicly-listed-business | b2b-cold
})

if (!rules.canCollectForMarketing) {
  // strict regime + lead-magnet → cannot auto-add to newsletter
}

if (rules.optIn === "double") {
  // trigger DOI flow
}

const auditRecord = await rules.buildAuditRecord({
  ip, userAgent, sourceUrl, wording, formVersion,
})
// → ISO/IEC TS 27560:2023-aligned consent receipt. Persist anywhere.

See docs/DESIGN.md for the full output shape, edge cases, and architecture.

Non-goals

  • Not legal advice. See DISCLAIMER.md.
  • Not a consent UI library. Bring your own checkbox.
  • Not an ESP wrapper. Integrations are thin adapters that emit the right shape for each ESP; the ESP itself does the sending.
  • Not a cookie banner. That's c15t.
  • Not a consent database. See docs/CONSENT_STORAGE.md. mailregime is stateless and never opens a connection to anything.

Roadmap

  • [x] Design doc
  • [x] Consent-storage doc
  • [x] Modularity contract
  • [x] Liability shields (LICENSE, DISCLAIMER, CONTRIBUTING, SECURITY, COLLABORATION + GitHub issue/PR templates)
  • [x] Core API + types
  • [x] ISO/IEC TS 27560:2023 audit-record serializer
  • [x] Vercel adapter
  • [x] Cloudflare Workers adapter
  • [x] Static + generic-header adapters
  • [x] Tests + CI
  • [x] 67 bundled countries — full EU/EEA, Anglo, key APAC + LATAM + MENA + ZA + RU + UA. See src/data/countries/.
  • [x] npm publish with verified provenance (OIDC trusted publisher)
  • [x] fumadb-based storage — bring-your-own ORM (Prisma, Drizzle, Kysely, TypeORM, MongoDB) — replaces the v0.4 bundled PostgresStore + CLI
  • [ ] Brevo integration
  • [ ] Resend integration

Contributing

See CONTRIBUTING.md. Contributions licensed under MIT with the DISCLAIMER. Country data PRs without primary-source citations will be closed.

License

MIT — but read the additional disclaimer in LICENSE. It is binding on every user.