Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/validators/email.py: 80%
15 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:08 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:08 +0000
1"""eMail."""
2# -*- coding: utf-8 -*-
4# standard
5import re
7# local
8from .hostname import hostname
9from .utils import validator
12@validator
13def email(
14 value: str,
15 /,
16 *,
17 ipv6_address: bool = False,
18 ipv4_address: bool = False,
19 simple_host: bool = False,
20 rfc_1034: bool = False,
21 rfc_2782: bool = False,
22):
23 """Validate an email address.
25 This was inspired from [Django's email validator][1].
26 Also ref: [RFC 1034][2], [RFC 5321][3] and [RFC 5322][4].
28 [1]: https://github.com/django/django/blob/main/django/core/validators.py#L174
29 [2]: https://www.rfc-editor.org/rfc/rfc1034
30 [3]: https://www.rfc-editor.org/rfc/rfc5321
31 [4]: https://www.rfc-editor.org/rfc/rfc5322
33 Examples:
34 >>> email('someone@example.com')
35 # Output: True
36 >>> email('bogus@@')
37 # Output: ValidationFailure(email=email, args={'value': 'bogus@@'})
39 Args:
40 value:
41 eMail string to validate.
42 ipv6_address:
43 When the domain part is an IPv6 address.
44 ipv4_address:
45 When the domain part is an IPv4 address.
46 simple_host:
47 When the domain part is a simple hostname.
48 rfc_1034:
49 Allow trailing dot in domain name.
50 Ref: [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034).
51 rfc_2782:
52 Domain name is of type service record.
53 Ref: [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782).
55 Returns:
56 (Literal[True]):
57 If `value` is a valid eMail.
58 (ValidationFailure):
59 If `value` is an invalid eMail.
61 > *New in version 0.1.0*.
62 """
63 if not value or value.count("@") != 1:
64 return False
66 username_part, domain_part = value.rsplit("@", 1)
68 if len(username_part) > 64 or len(domain_part) > 253:
69 # ref: RFC 1034 and 5231
70 return False
72 if ipv6_address or ipv4_address:
73 if domain_part.startswith("[") and domain_part.endswith("]"):
74 # ref: RFC 5321
75 domain_part = domain_part.lstrip("[").rstrip("]")
76 else:
77 return False
79 return (
80 bool(
81 hostname(
82 domain_part,
83 skip_ipv6_addr=not ipv6_address,
84 skip_ipv4_addr=not ipv4_address,
85 may_have_port=False,
86 maybe_simple=simple_host,
87 rfc_1034=rfc_1034,
88 rfc_2782=rfc_2782,
89 )
90 )
91 if re.match(
92 # dot-atom
93 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$"
94 # quoted-string
95 + r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)',
96 username_part,
97 re.IGNORECASE,
98 )
99 else False
100 )