Catalog PyPI
PACKAGE EXPLORERView in registry

aa-skip-email

PyPI

Allows you to skip entering your email after registering via EVE SSO

allianceauthdjangoemaileveonlinesso
Versions collected1
Direct dependencies1From release 0.4.1
Last observed20 Oct, 17:03 UTC

README

Version 0.4.1 documentation

AA Skip Email (aa_skip_email)

A small Alliance Auth plugin that lets you skip collecting real email addresses during EVE SSO registration by automatically generating a placeholder User.email. This is useful for integrations (e.g., OIDC clients) that expect email to be present.


Features

  • Creates a placeholder email for newly created users during SSO registration.
  • Includes a one-off Django management command to backfill missing emails.
  • Includes a Celery task suitable for periodic execution to keep data consistent.
  • Emits a placeholder_email_replaced signal when a user's placeholder is replaced with a real address — downstream plugins (OIDC providers, audit logs, welcome flows) can react without polling.
  • Exposes is_placeholder_email() and get_placeholder_users() helpers so callers can classify addresses without re-implementing the domain check.
  • Ships a PlaceholderEmailFilter for the Django admin user list.
  • Translated user-visible strings (admin filter, command output, AppConfig name) — currently en source + ru catalogue.

Requirements

  • Python >= 3.12 (tested on 3.12 and 3.13)
  • Alliance Auth >= 4.0, < 6 (tested against the latest AA 4.x and AA 5.x)

Installation

Install the plugin into the same Python environment as Alliance Auth (pip/uv/poetry-whatever you use).

pip install aa-skip-email

Add the app to INSTALLED_APPS (typically in local.py):

INSTALLED_APPS += [
    ...
    "aa_skip_email",
    ...
]

Add the authentication backend to AUTHENTICATION_BACKENDS.

[!IMPORTANT] This plugin replaces Alliance Auth’s default allianceauth.authentication.backends.StateBackend behavior. Update AUTHENTICATION_BACKENDS so that SkipEmailBackend is used instead of the original AA StateBackend.

Example:

AUTHENTICATION_BACKENDS = [
    # Replace the original AA StateBackend with this plugin backend
    "aa_skip_email.authentication.backends.SkipEmailBackend",
    # Keep the rest of your original backends
    "django.contrib.auth.backends.ModelBackend",
]

Configuration

Configure these in local.py (or your equivalent settings file).

AA_SKIP_EMAIL_DOMAIN

Domain used for placeholder addresses.

  • Type: str
  • Default: no-email.invalid
AA_SKIP_EMAIL_DOMAIN = "no-email.invalid"

Using a domain under .invalid helps avoid accidentally generating addresses at a real domain.

The plugin validates this setting at process start and raises ImproperlyConfigured if the value is empty, contains @ or whitespace, or has no . (single-label "domain"). This catches misconfigurations before the first SSO registration attempt.

AA_SKIP_EMAIL_LIMIT

Default limit for how many users are processed per run by the management command and the Celery task.

  • Type: int
  • Default: 5000
AA_SKIP_EMAIL_LIMIT = 5000

How placeholder emails are generated

A placeholder email is generated from the user’s username (sanitized to a conservative character set) and a unique suffix (typically the user id; otherwise a UUID). The local-part is kept within 64 characters.

Resulting format is similar to:

<sanitized-username>-<id-or-uuid>@<AA_SKIP_EMAIL_DOMAIN>

One-off backfill (management command)

The plugin provides a Django management command to fill missing emails.

Fill missing emails (default)

python manage.py fill_missing_emails

Limit number of users

python manage.py fill_missing_emails --limit 5000

Dry-run (no writes)

python manage.py fill_missing_emails --dry-run --limit 50

Overwrite emails for all users

[!CAUTION] This will replace existing emails.

python manage.py fill_missing_emails --overwrite

Overwrite only existing placeholders

Safer if some users have real emails and you only want to regenerate placeholders.

python manage.py fill_missing_emails --overwrite --only-placeholders

Scheduler (Celery Beat)

The plugin includes a Celery task named:

  • aa_skip_email.fill_missing_emails

To run it periodically, add a schedule entry in local.py using CELERYBEAT_SCHEDULE.

Example: run every 6 hours

from celery.schedules import crontab

CELERYBEAT_SCHEDULE["aa_skip_email_fill_missing_emails"] = {
    "task": "aa_skip_email.fill_missing_emails",
    "schedule": crontab(minute=0, hour="*/6"),
    # Optional: helps spread load across instances in some AA deployments
    "apply_offset": True,
}

Example: run daily at 04:15

from celery.schedules import crontab

CELERYBEAT_SCHEDULE["aa_skip_email_fill_missing_emails"] = {
    "task": "aa_skip_email.fill_missing_emails",
    "schedule": crontab(minute=15, hour=4),
    "apply_offset": True,
}

Public API for downstream plugins

is_placeholder_email(email)

from aa_skip_email import is_placeholder_email

if is_placeholder_email(user.email):
    ...  # treat as unverified / non-routable

Centralised classifier — returns True for any address produced by this plugin (case-insensitive domain match, anchored to the domain part). Falsy values (None, "") return False.

get_placeholder_users()

from aa_skip_email.helpers import get_placeholder_users

count = get_placeholder_users().count()

ORM-side analogue of is_placeholder_email. Returns a queryset of all users whose email is a plugin-generated placeholder. Useful for admin reports, audit dashboards, or batch follow-up.

Admin filter

Add PlaceholderEmailFilter to AA's existing UserAdmin.list_filter to surface a "Placeholder / Real / Blank" sidebar in the admin user list. The plugin does not re-register the User model so AA's custom UserAdmin remains intact:

# in your local.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from aa_skip_email.admin import PlaceholderEmailFilter

User = get_user_model()
UserAdmin = admin.site._registry[User].__class__
UserAdmin.list_filter = (*UserAdmin.list_filter, PlaceholderEmailFilter)

Signal placeholder_email_replaced

Sent when User.email transitions from a plugin-generated placeholder to a real address. Useful for OIDC providers that flip email_verified=true on the ID token, audit logs, welcome emails, etc.

from django.dispatch import receiver
from aa_skip_email.signals import placeholder_email_replaced

@receiver(placeholder_email_replaced, dispatch_uid="my_app.email_verified")
def on_email_replaced(sender, user, old_email, new_email, **kwargs):
    ...

The signal does not fire on:

  • Initial fill of a blank/NULL email (placeholder is the new value).
  • Placeholder rewritten as another placeholder (--overwrite --only-placeholders).
  • Real email replaced with another real email.

See also

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.4.118 Oct 20261

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

ACCESSIBLE
zima-corp/aa-skip-email

Shared repository data · GitLab

License detected in repository
Not collected
Contributor identities
1 · complete API traversal
Contributors · showing 1 of 1 collected
ContributorContributions
Boris Talovikov68

Default-branch author identities; GitLab commit counts exclude merge commits.

Public sponsor counts have not been collected. These signals belong to the repository owner.

Downloads & popularity

1identities
Gauge · observed snapshots23 Oct 2026
10.50
2026-10-20: 1 · observed 2026-10-20T18:49:40.3461886Z2026-10-21: 1 · observed 2026-10-21T18:49:59.0992854Z2026-10-22: 1 · observed 2026-10-22T18:50:22.0750435Z2026-10-23: 1 · observed 2026-10-23T18:50:39.1465401Z
20 Oct23 Oct

gitlab · 4 observations shown. Missing days are unknown.

View observed values
Date / source periodValueObserved at
2026-10-2312026-10-23T18:50:39.1465401Z
2026-10-2212026-10-22T18:50:22.0750435Z
2026-10-2112026-10-21T18:49:59.0992854Z
2026-10-2012026-10-20T18:49:40.3461886Z

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 17:03 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:b0efdf554c180c6c99e2e02fa803814b1674291ed72e5a116d640e4b12c05c47