Skip to content

email

validators.email.email(value, /, *, ipv6_address=False, ipv4_address=False, simple_host=False, rfc_1034=False, rfc_2782=False)

Validate an email address.

This was inspired from Django's email validator. Also ref: RFC 1034, RFC 5321 and RFC 5322.

Examples:

>>> email('someone@example.com')
True
>>> email('bogus@@')
ValidationError(func=email, args={'value': 'bogus@@'})

Parameters:

Name Type Description Default
value str

eMail string to validate.

required
ipv6_address bool

When the domain part is an IPv6 address.

False
ipv4_address bool

When the domain part is an IPv4 address.

False
simple_host bool

When the domain part is a simple hostname.

False
rfc_1034 bool

Allow trailing dot in domain name. Ref: RFC 1034.

False
rfc_2782 bool

Domain name is of type service record. Ref: RFC 2782.

False

Returns:

Type Description
Literal[True]

If value is a valid eMail.

ValidationError

If value is an invalid eMail.

Source code in src/validators/email.py
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
@validator
def email(
    value: str,
    /,
    *,
    ipv6_address: bool = False,
    ipv4_address: bool = False,
    simple_host: bool = False,
    rfc_1034: bool = False,
    rfc_2782: bool = False,
):
    """Validate an email address.

    This was inspired from [Django's email validator][1].
    Also ref: [RFC 1034][2], [RFC 5321][3] and [RFC 5322][4].

    [1]: https://github.com/django/django/blob/main/django/core/validators.py#L174
    [2]: https://www.rfc-editor.org/rfc/rfc1034
    [3]: https://www.rfc-editor.org/rfc/rfc5321
    [4]: https://www.rfc-editor.org/rfc/rfc5322

    Examples:
        >>> email('someone@example.com')
        True
        >>> email('bogus@@')
        ValidationError(func=email, args={'value': 'bogus@@'})

    Args:
        value:
            eMail string to validate.
        ipv6_address:
            When the domain part is an IPv6 address.
        ipv4_address:
            When the domain part is an IPv4 address.
        simple_host:
            When the domain part is a simple hostname.
        rfc_1034:
            Allow trailing dot in domain name.
            Ref: [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034).
        rfc_2782:
            Domain name is of type service record.
            Ref: [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782).

    Returns:
        (Literal[True]): If `value` is a valid eMail.
        (ValidationError): If `value` is an invalid eMail.
    """
    if not value or value.count("@") != 1:
        return False

    username_part, domain_part = value.rsplit("@", 1)

    if len(username_part) > 64 or len(domain_part) > 253:
        # ref: RFC 1034 and 5231
        return False

    if ipv6_address or ipv4_address:
        if domain_part.startswith("[") and domain_part.endswith("]"):
            # ref: RFC 5321
            domain_part = domain_part.lstrip("[").rstrip("]")
        else:
            return False

    return (
        bool(
            hostname(
                domain_part,
                skip_ipv6_addr=not ipv6_address,
                skip_ipv4_addr=not ipv4_address,
                may_have_port=False,
                maybe_simple=simple_host,
                rfc_1034=rfc_1034,
                rfc_2782=rfc_2782,
            )
        )
        if re.match(
            # extended latin
            r"(^[\u0100-\u017F\u0180-\u024F\u00A0-\u00FF]"
            # dot-atom
            + r"|[\u0100-\u017F\u0180-\u024F\u00A0-\u00FF0-9a-z!#$%&'*+/=?^_`{}|~\-]+"
            + r"(\.[\u0100-\u017F\u0180-\u024F\u00A0-\u00FF0-9a-z!#$%&'*+/=?^_`{}|~\-]+)*$"
            # quoted-string
            + r'|^"('
            + r"[\u0100-\u017F\u0180-\u024F\u00A0-\u00FF\001-\010\013\014\016-\037"
            + r"!#-\[\]-\177]|\\[\011.]"
            + r')*")$',
            username_part,
            re.IGNORECASE,
        )
        else False
    )