Skip to content

Instantly share code, notes, and snippets.

@akaihola
Created December 21, 2011 08:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save akaihola/1505228 to your computer and use it in GitHub Desktop.
Save akaihola/1505228 to your computer and use it in GitHub Desktop.
django-full-email

Full e-mail address validation for Django

Out of the box, Django e-mail fields for both database models and forms only accept plain e-mail addresses. For example, joe@hacker.com is accepted.

On the other hand, full e-mail addresses which include a human-readable name, for example the following address fails validation in Django:

Joe Hacker <joe@hacker.com>

This package adds support for validating full e-mail addresses.

Database model example

from django import models
from full_email.models import FullEmailField

class MyModel(models.Model):
    email = FullEmailField()

Forms example

from django import forms
from full_email.formfields import FullEmailField

class MyForm(forms.Form):
    email = FullEmailField(label='E-mail address')
from django import forms
from .validators import validate_full_email
class FullEmailField(forms.EmailField):
default_validators = [validate_full_email]
from django.db import models
from . import formfields
from .validators import validate_full_email
class FullEmailField(models.EmailField):
default_validators = [validate_full_email]
def formfield(self, **kwargs):
defaults = {'form_class': formfields.FullEmailField}
defaults.update(kwargs)
return super(FullEmailField, self).formfield(**defaults)
# -*- encoding: utf-8 -*-
from unittest import TestCase
from django.core.validators import email_re, EmailValidator, ValidationError
from . import validators
from nose.tools import raises
class ValidateFullEmail_Tests(TestCase):
def test_normal_valid_email(self):
"""A normal valid e-mail address validates correctly"""
validators.validate_full_email(u'john@doe.com')
def test_fullname(self):
"""A valid e-mail address with a full name validates correctly"""
validators.validate_full_email(u'John Doe <john@doe.com>')
def test_quoted_fullname(self):
"""A valid e-mail address with a quoted full name validates correctly"""
validators.validate_full_email(u'"Doe, John" <john@doe.com>')
def test_unicode_fullname(self):
"""A valid e-mail address with a Unicode name validates correctly"""
validators.validate_full_email(u'"Übergeek, Jörg" <joerg@ubergeek.com>')
@raises(ValidationError)
def test_incomplete_domain(self):
"""An incomplete domain in an e-mail address fails validation"""
validators.validate_full_email(u'joerg@ubergeek')
@raises(ValidationError)
def test_fullname_and_incomplete_domain(self):
"""An incomplete domain in a full e-mail address fails validation"""
validators.validate_full_email(u'Jörg <joerg@ubergeek>')
from django.core.validators import email_re, EmailValidator, ValidationError
from django.utils.translation import ugettext_lazy as _
class FullEmailValidator(EmailValidator):
def __call__(self, value):
try:
super(FullEmailValidator, self).__call__(value)
except ValidationError, e:
# Trivial case failed. Try for possible Full Name <email@address>
if value and u'<' in value and value.endswith(u'>'):
parts = value.rsplit(u'<', 1)
fullname_part = parts[0].rstrip()
email_part = parts[1][:-1]
super(EmailValidator, self).__call__(email_part)
else:
raise
validate_full_email = FullEmailValidator(email_re,
_(u'Enter a valid e-mail address.'),
'invalid')
@filipeximenes
Copy link

Python3/Django 1.9 compatibility:

validators.py

from django.core.validators import EmailValidator, ValidationError
from django.utils.html import simple_email_re
from django.utils.translation import ugettext_lazy as _

class FullEmailValidator(EmailValidator):
    def __call__(self, value):
        try:
            super().__call__(value)
        except ValidationError as e:
            # Trivial case failed. Try for possible Full Name <email@address>
            if value and u'<' in value and value.endswith(u'>'):
                parts = value.rsplit(u'<', 1)
                fullname_part = parts[0].rstrip()
                email_part = parts[1][:-1]
                super().__call__(email_part)
            else:
                raise

validate_full_email = FullEmailValidator(simple_email_re,
                                         _(u'Enter a valid e-mail address.'),
                                         'invalid')

formfields.py

from django import forms
from django.forms.widgets import EmailInput

from .validators import validate_full_email

class FullEmailInput(EmailInput):
    input_type = 'text'

class FullEmailField(forms.EmailField):
    default_validators = [validate_full_email]
    widget = FullEmailInput

@rafen
Copy link

rafen commented Jan 19, 2017

A simplified version for forms fields only:

fields.py

from django import forms
from django.core.validators import validate_email
from django.forms.fields import Field
from django.utils.translation import ugettext_lazy as _

class FullEmailField(Field):
    description = _(u"Full email ('Full Name <email@address>')")

    def clean(self, value):
        try:
            validate_email(value)
        except forms.ValidationError:
            # Trivial case failed. Try for possible Full Name <email@address>
            if value and u'<' in value and value.endswith(u'>'):
                parts = value.rsplit(u'<', 1)
                email_part = parts[1][:-1]
                validate_email(email_part)
            else:
                validate_email(value)
        return value

@akaihola
Copy link
Author

@JordanReiter has packaged this properly in his django-full-emali repository. Thanks Jordan!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment