Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django EmailField accepts invalid values

I'm currently using the default EmailField attribute on my form. The issue I'm running into is that the form considers an invalid email such as [email protected] to be valid. Do I need to implement my own validators on this field to make it work correctly?

I was under the impression that having:

#models.py
email = models.EmailField(max_length=254, blank=False, unique=True,
        error_messages={'required': 'Please provide your email address.',
                        'unique': 'An account with this email exist.'},)

Or having:

#forms.py
email = forms.EmailField()

will take care of this type of validation for me but it doesn't seem so.

like image 745
Staccato Avatar asked Aug 21 '13 21:08

Staccato


3 Answers

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 [email protected] 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.

like image 194
Adrián Avatar answered Nov 18 '22 20:11

Adrián


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)
like image 41
Dušan Maďar Avatar answered Nov 18 '22 22:11

Dušan Maďar


Indeed, [email protected] email is a valid email for django EmailValidator, see no errors:

>>> from django.core.validators import validate_email
>>> validate_email("[email protected]")
>>>

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 [email protected] 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.

like image 28
alecxe Avatar answered Nov 18 '22 20:11

alecxe