mansueli@email_guard

v0.35.0Created 8 months agoBy mansueli

email_guard

Trusted Language Extension (TLE) that guards Supabase Auth signups:

  • Blocks disposable email domains.
  • Normalizes Gmail addresses (remove dots and + tags) so each Gmail account can sign up only once.

Objects are created in the extension schema (@extschema@) so the package is relocatable.

What’s inside

  • Table: @extschema@.disposable_email_domains(domain text primary key)
  • Function: @extschema@.normalize_email(text)
  • Function: @extschema@.is_disposable_email_domain(text)
  • Function: @extschema@.is_disposable_email(text)
  • Hook helper: @extschema@.hook_prevent_disposable_and_enforce_gmail_uniqueness(jsonb)

Fresh installs and upgrades seed the full disposable-domain blocklist automatically; no extra seed scripts required.

Install via database.dev (Supabase-friendly workflow)

You can publish this package as mansueli@email_guard and install it the same way you would install other dbdev TLEs.

1. Install dbdev & Supabase CLI (if needed)

Make sure your local project is connected to your Supabase database (supabase link). Supabase already has the pg_tle extension installed, which is the only prerequisite.

2. Generate a migration with dbdev

Use dbdev to pull version 0.35.0 (or newer) into your migrations folder. Example:

dbdev add \
  -o ./supabase/migrations/ \
  -v 0.35.0 \
  -s extensions \
  package \
  -n mansueli@email_guard
  • -s extensions installs into the extensions schema (recommended on Supabase).
  • Adjust the output folder if your project keeps migrations elsewhere.

3. Apply with Supabase CLI

Push the generated migration to your project database:

supabase db push

After the migration runs, the extension is installed and seeded in the target schema.

Wire up the Supabase Auth hook

In the Supabase dashboard, add a before-user-created hook of type Postgres Function pointing to the schema and function you installed. For the example above (installed in extensions):

extensions.hook_prevent_disposable_and_enforce_gmail_uniqueness

Behavior:

  • Disposable domains trigger a 403 with a helpful error message.
  • Gmail/Googlemail addresses normalize to gmail.com with dots removed and +tags stripped; if a normalized Gmail already exists in auth.users, the hook raises a 409.
  • Signups without an email (e.g., phone) are passed through unchanged.

Keeping the blocklist current

This repo ships an automated workflow that runs every Monday at 12:00 UTC:

  1. Fetches the upstream disposable-email list.
  2. If there are changes, bumps the minor version, creates the upgrade script, and commits both the new base version and control-file update.
  3. Automatically publishes the updated package to database.dev using the dbdev CLI.

Required repository secrets

To enable automated publishing, add the following secret to the repository (Settings → Secrets and variables → Actions → New repository secret):

Secret nameDescription
DBDEV_TOKENYour database.dev token (found in your account settings).
SUPABASE_ANON_KEYYour Supabase anon key, used to authenticate the dbdev registry API.

Without these secrets the workflow will still commit and push blocklist updates, but the dbdev publish step will fail.

To publish manually:

dbdev login        # paste your database.dev token when prompted
dbdev publish --path email_guard

Upgrading your database to the new version pulls in the refreshed blocklist automatically.

Handy queries

-- Check if an email domain is disposable
select extensions.is_disposable_email('user@mailinator.com');

-- Normalize a Gmail address
select extensions.normalize_email('e.xam.ple+promo@gmail.com');

-- Simulate hook behavior
select extensions.hook_prevent_disposable_and_enforce_gmail_uniqueness(
  '{"user": {"email": "e.xam.ple+1@gmail.com"}}'::jsonb
);

Replace extensions with the schema you chose if different.

Notes

  • The hook runs before the user is inserted, so only existing users are checked for Gmail duplicates.
  • Domain matching walks up parent domains (sub.mailinator.com matches mailinator.com).
  • The extension is relocatable; you can install it under any schema and reference it in the hook configuration.

Install

  1. Install the dbdev CLI
  2. Generate migration:
dbdev add -o ./migrations -s extensions -v 0.35.0 package -n "mansueli@email_guard"

Downloads

  • 2 all time downloads
  • 0 downloads in the last 30 days
  • 0 downloads in the last 90 days
  • 2 downloads in the last 180 days