Mail list validator

While working on a web application called CastAFile, which uses a list of email addresses as input, I had to write a Validator to format and validate each email address entered. Here is the code and the description of the validator.

The validator checks a comma separated list of email addresses. It also cleans up the string and removes the duplicates. This class inherits from validator.Email.

The method _to_python cleans up the string, and removes the empty email addresses and the duplicates.

Then validate_python calls validators.Email.validate_python for each email address to verify it.

Usage:
>>> v=MailListValidator()
>>> v.to_python('mike@domain.net, marc@exemple.com')
'marc@exemple.com,mike@domain.net'
# removes duplicates.
>>> v.to_python('mike@domain.net, marc@exemple.com, mike@domain.net')
'marc@exemple.com, mike@domain.net'
>>> v.to_python('mike@domain.net, marc')
Traceback (most recent call last):
...

>>> v=MailListValidator()
>>> v.to_python('mike@domain.net, marc@exemple.com')
'marc@exemple.com,mike@domain.net'
# removes duplicates.
>>> v.to_python('mike@domain.net, marc@exemple.com, mike@domain.net')
'marc@exemple.com, mike@domain.net'
>>> v.to_python('mike@domain.net, marc')
Traceback (most recent call last):
...


The code:
class MailListValidator(validators.Email):
    r"""
    Validate a list of email addresses.

    If you pass ``max_emails=<nb>``, then it will limit the length of
    the list to <nb> addresses. By default there is no limit to the
    number of email addresses in the list.

    """

    max_emails = None

    __unpackargs__ = ('max_emails',)

    messages = { 
        'max': _("You can only enter %(max)i email addresses (%(nb)i given)"),
        'err_s': _("The email address '%(email)s' is not valid"),
        'err_p': _("The email addresses '%(email)s' are not valid")
        }

    def __init__(self, *args, **kw):
        self.max_emails = kw.get('max_emails')
        validators.Email.__init__(self, *args, **kw)

    def __unique(self, data):
        S = {}
        for d in data:
            S[d] = 1
        return S.keys()

    def _to_python(self, value, state):
        value = value.lower()
        recipients = [r.strip() for r in value.split(',') if r.strip()]
        recipients = self.__unique(recipients)
        return ','.join(recipients)
    
    def validate_python(self, value, state):

        email_list = value.split(',')

        nb = len(email_list)
        if self.max_emails and nb > self.max_emails:
            raise validators.Invalid(
                self.message("max", state, max=self.max_emails, nb=nb),
                value, state)

        wrong_emails = []
        for v in email_list:
            try:
                validators.Email.validate_python(self, v, state)
            except:
                wrong_emails.append(v)

        if len(wrong_emails) == 1:
            raise validators.Invalid(
                self.message("err_s", state, email=', '.join(wrong_emails)),
                value, state)
        
        if len(wrong_emails) > 1:
            raise validators.Invalid(
                self.message("err_p", state, email=', '.join(wrong_emails)),
                value, state)

class MailListValidator(validators.Email):
r"""
Validate a list of email addresses.

If you pass ``max_emails=<nb>``, then it will limit the length of
the list to <nb> addresses. By default there is no limit to the
number of email addresses in the list.

"""

max_emails = None

__unpackargs__ = ('max_emails',)

messages = {
'max': _("You can only enter %(max)i email addresses (%(nb)i given)"),
'err_s': _("The email address '%(email)s' is not valid"),
'err_p': _("The email addresses '%(email)s' are not valid")
}

def __init__(self, *args, **kw):
self.max_emails = kw.get('max_emails')
validators.Email.__init__(self, *args, **kw)

def __unique(self, data):
S = {}
for d in data:
S[d] = 1
return S.keys()

def _to_python(self, value, state):
value = value.lower()
recipients = [r.strip() for r in value.split(',') if r.strip()]
recipients = self.__unique(recipients)
return ','.join(recipients)

def validate_python(self, value, state):

email_list = value.split(',')

nb = len(email_list)
if self.max_emails and nb > self.max_emails:
raise validators.Invalid(
self.message("max", state, max=self.max_emails, nb=nb),
value, state)

wrong_emails = []
for v in email_list:
try:
validators.Email.validate_python(self, v, state)
except:
wrong_emails.append(v)

if len(wrong_emails) == 1:
raise validators.Invalid(
self.message("err_s", state, email=', '.join(wrong_emails)),
value, state)

if len(wrong_emails) > 1:
raise validators.Invalid(
self.message("err_p", state, email=', '.join(wrong_emails)),
value, state)
 

Leave a message

(Required)
(Required and not displayed)
(Optional)
obfuscated letters Enter the text shown in the image