[Fixed]-Django EmailField accepts invalid values

20👍

Indeed, name@mail.56 email is a valid email for django EmailValidator, see no errors:

>>> from django.core.validators import validate_email
>>> validate_email("name@mail.56")
>>>

Django (1.5.1) uses the following regular expression for validating email address:

r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
    # quoted-string, see also https://www.rfc-editor.org/rfc/rfc2822#section-3.2.5
    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"'
    r')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)$)'  # domain
    r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$'

And it actually follows RFC2822 standard.

If you want to make name@mail.56 fail during validation, you can create your own validator, and add it to EmailField validators with built-in validate_email validator, like this:

from django.core.validators import validate_email
from django.core.exceptions import ValidationError

def custom_validate_email(value):
    if <custom_check>:
        raise ValidationError('Email format is incorrect')
...
email = models.EmailField(max_length=254, blank=False, unique=True, validators=[validate_email, custom_validate_email)

And, FYI, you can always file a ticket in django ticket system or ask about the issue on django IRC channel (irc://irc.freenode.net/django).

See also: Writing validators.

Hope that helps.

👤alecxe

7👍

You can see the used regex here.

I think it doesn’t discard 100% of the wrong emails. That’s why in the docs it says:

Validates that the given value is a valid email address, using a
moderately complex regular expression.

What I understand from this is that it doesn’t do a perfect validation due to a design decision (it would be a performance trade-off).

Finally, I’m pretty sure that your example name@mail.56 is a valid email. The domain part of an email address can be an IP (both IPv4 and IPv6) or a hostname. See here for further info in the subject.

2👍

For DB level only validation you will have to call full_clean manually.

Three important citations from documentation:

How validators are run

See the form validation for more information on how validators are run
in forms, and Validating objects for how they’re run in models. Note
that validators will not be run automatically when you save a model,
but if you are using a ModelForm, it will run your validators on any
fields that are included in your form. See the ModelForm documentation
for information on how model validation interacts with forms.

Model.clean_fields

The second step full_clean() performs is to call Model.clean(). This
method should be overridden to perform custom validation on your
model.

Model.full_clean

Note that full_clean() will not be called automatically when you call
your model’s save() method. You’ll need to call it manually when you
want to run one-step model validation for your own manually created
models.

from django.db import models


class MyTable(models.Model):
    email = models.EmailField(unique=True)

    def save(self, *args, **kwargs):
        super().full_clean()
        super().save(*args, **kwargs)

Leave a comment