Metadata-Version: 2.4
Name: django-email-validators
Version: 0.3.0
Summary: no more invalid or disposable emails in your database.
Author-email: Fabio Caccamo <fabio.caccamo@gmail.com>
Maintainer-email: Fabio Caccamo <fabio.caccamo@gmail.com>
License: MIT License
        
        Copyright (c) 2025-present Fabio Caccamo
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/fabiocaccamo/django-email-validators
Project-URL: Download, https://github.com/fabiocaccamo/django-email-validators/releases
Project-URL: Documentation, https://github.com/fabiocaccamo/django-email-validators#readme
Project-URL: Issues, https://github.com/fabiocaccamo/django-email-validators/issues
Project-URL: Funding, https://github.com/sponsors/fabiocaccamo/
Project-URL: Twitter, https://twitter.com/fabiocaccamo
Keywords: python,django,email,validation,validator,disposable,deliverable,mx,check,strict,validator,verification
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.0
Classifier: Framework :: Django :: 4.1
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: disposable-email-domains<1.0.0,>=0.0.147
Requires-Dist: email-validator<3.0.0,>=2.3.0
Requires-Dist: mailchecker<7.0.0,>=6.0.19
Requires-Dist: pyIsEmail<3.0.0,>=2.0.1
Dynamic: license-file

[![](https://img.shields.io/pypi/pyversions/django-email-validators.svg?color=3776AB&logo=python&logoColor=white)](https://www.python.org/)
[![](https://img.shields.io/pypi/djversions/django-email-validators?color=0C4B33&logo=django&logoColor=white&label=django)](https://www.djangoproject.com/)

[![](https://img.shields.io/pypi/v/django-email-validators.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/django-email-validators/)
[![](https://static.pepy.tech/badge/django-email-validators/month)](https://pepy.tech/project/django-email-validators)
[![](https://img.shields.io/github/stars/fabiocaccamo/django-email-validators?logo=github&style=flat)](https://github.com/fabiocaccamo/django-email-validators/stargazers)
[![](https://img.shields.io/pypi/l/django-email-validators.svg?color=blue)](https://github.com/fabiocaccamo/django-email-validators/blob/main/LICENSE.txt)

[![](https://results.pre-commit.ci/badge/github/fabiocaccamo/django-email-validators/main.svg)](https://results.pre-commit.ci/latest/github/fabiocaccamo/django-email-validators/main)
[![](https://img.shields.io/github/actions/workflow/status/fabiocaccamo/django-email-validators/test-package.yml?branch=main&label=build&logo=github)](https://github.com/fabiocaccamo/django-email-validators)
[![](https://img.shields.io/codecov/c/gh/fabiocaccamo/django-email-validators?logo=codecov)](https://codecov.io/gh/fabiocaccamo/django-email-validators)
[![](https://img.shields.io/badge/code%20style-black-000000.svg?logo=python&logoColor=black)](https://github.com/psf/black)
[![](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

# django-email-validators
no more invalid or disposable emails in your database.

## Installation
-   Run `pip install django-email-validators`
-   Add `django_email_validators` to `settings.INSTALLED_APPS`
-   Restart your application server

## Usage

### Validators
- 🗑️ `validate_email_non_disposable`
- 🌐 `validate_email_mx`
- ✍️ `validate_email_provider_typo`
- 👤 `validate_email_unique_dot_insensitive`

#### `validate_email_non_disposable`
Validates that the email is not from a disposable email provider *(fast, offline check)*.

#### `validate_email_mx`
Validates that the email domain has valid MX records *(slow, requires network access)*.

#### `validate_email_provider_typo`
Validates that the email domain is not a likely typo of a common email provider.
Checks a one-character diff against 80+ common providers and verifies the domain has no valid MX records (prevents false positives).

**Examples that will be caught:**
- `user@gmai.com` -> suggests `user@gmail.com`
- `user@gmail.co` -> suggests `user@gmail.com`
- `user@yahooo.com` -> suggests `user@yahoo.com`

#### `validate_email_unique_dot_insensitive`
Validates that the email is unique in the database, accounting for dot-insensitive providers (e.g. Gmail treats dots in the local part as insignificant, so `fabio.caccamo@gmail.com` and `fabiocaccamo@gmail.com` are the same inbox).

Accepts an optional `exclude_pk` argument to exclude the current user when updating an existing account, and an optional `field` argument (default: `"email"`) to specify the model field name.

**Examples that will be caught:**
- `fabio.caccamo@gmail.com` already exists → `fabiocaccamo@gmail.com` is rejected

Since this validator requires access to the model instance (to exclude it on update), it cannot be used directly in a field's `validators=[...]`. Call it explicitly in a form or serializer:

```python
from django_email_validators import validate_email_unique_dot_insensitive

# Form example
class UserForm(forms.ModelForm):
    def clean_email(self):
        email = self.cleaned_data["email"]
        exclude_pk = self.instance.pk
        validate_email_unique_dot_insensitive(email, exclude_pk=exclude_pk)
        return email
```

Or via `validate_unique` on the model:

```python
class User(models.Model):
    email = models.EmailField()

    def validate_unique(self, exclude=None):
        super().validate_unique(exclude=exclude)
        validate_email_unique_dot_insensitive(self.email, exclude_pk=self.pk)
```

#### Usage

> **Note:** `validate_email_unique_dot_insensitive` requires access to the model instance and cannot be used in `validators=[...]`. See the [dedicated section above](#validate_email_unique_dot_insensitive) for usage examples.

```python
from django.db import models
from django_email_validators import (
    validate_email_non_disposable,
    validate_email_mx,
    validate_email_provider_typo,
)

class User(models.Model):
    email = models.EmailField(
        validators=[
            validate_email_non_disposable,
            validate_email_mx,
            validate_email_provider_typo,
        ]
    )
```

### Extending the providers list for typo check
You can extend the list of common email providers used by `validate_email_provider_typo` by adding your own list in Django settings:
```python
EMAIL_VALIDATORS_EXTEND_COMMON_PROVIDERS = [
    'hey.com',
]
```

### Extending the dot-insensitive domains list
You can extend the list of dot-insensitive domains used by `validate_email_unique_dot_insensitive` by adding your own list in Django settings:
```python
EMAIL_VALIDATORS_EXTEND_DOT_INSENSITIVE_DOMAINS = [
    'fastmail.com',
]
```

## Testing
```bash
# clone repository
git clone https://github.com/fabiocaccamo/django-email-validators.git && cd django-email-validators

# create virtualenv and activate it
python -m venv venv && . venv/bin/activate

# upgrade pip
python -m pip install --upgrade pip

# install requirements
pip install -r requirements.txt -r requirements-test.txt

# install pre-commit to run formatters and linters
pre-commit install --install-hooks

# run tests
tox
# or
pytest
```

## License
Released under [MIT License](LICENSE.txt).

---

## Supporting

- :star: Star this project on [GitHub](https://github.com/fabiocaccamo/django-email-validators)
- :octocat: Follow me on [GitHub](https://github.com/fabiocaccamo)
- :blue_heart: Follow me on [Bluesky](https://bsky.app/profile/fabiocaccamo.bsky.social)
- :moneybag: Sponsor me on [Github](https://github.com/sponsors/fabiocaccamo)

## See also

- [`django-admin-interface`](https://github.com/fabiocaccamo/django-admin-interface) - the default admin interface made customizable by the admin itself. popup windows replaced by modals. 🧙 ⚡

- [`django-cache-cleaner`](https://github.com/fabiocaccamo/django-cache-cleaner) - clear the entire cache or individual caches easily using the admin panel or management command. 🧹

- [`django-colorfield`](https://github.com/fabiocaccamo/django-colorfield) - simple color field for models with a nice color-picker in the admin. 🎨

- [`django-extra-settings`](https://github.com/fabiocaccamo/django-extra-settings) - config and manage typed extra settings using just the django admin. ⚙️

- [`django-maintenance-mode`](https://github.com/fabiocaccamo/django-maintenance-mode) - shows a 503 error page when maintenance-mode is on. 🚧 🛠️

- [`django-redirects`](https://github.com/fabiocaccamo/django-redirects) - redirects with full control. ↪️

- [`django-treenode`](https://github.com/fabiocaccamo/django-treenode) - probably the best abstract model / admin for your tree based stuff. 🌳

- [`python-benedict`](https://github.com/fabiocaccamo/python-benedict) - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. 📘

- [`python-codicefiscale`](https://github.com/fabiocaccamo/python-codicefiscale) - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. 🇮🇹 💳

- [`python-fontbro`](https://github.com/fabiocaccamo/python-fontbro) - friendly font operations. 🧢

- [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - file-system utilities for lazy devs. 🧟‍♂️
