Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/validators/email.py: 81%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

16 statements  

1"""eMail.""" 

2 

3# standard 

4import re 

5 

6# local 

7from .hostname import hostname 

8from .utils import validator 

9 

10 

11@validator 

12def email( 

13 value: str, 

14 /, 

15 *, 

16 ipv6_address: bool = False, 

17 ipv4_address: bool = False, 

18 simple_host: bool = False, 

19 rfc_1034: bool = False, 

20 rfc_2782: bool = False, 

21): 

22 """Validate an email address. 

23 

24 This was inspired from [Django's email validator][1]. 

25 Also ref: [RFC 1034][2], [RFC 5321][3] and [RFC 5322][4]. 

26 

27 [1]: https://github.com/django/django/blob/main/django/core/validators.py#L174 

28 [2]: https://www.rfc-editor.org/rfc/rfc1034 

29 [3]: https://www.rfc-editor.org/rfc/rfc5321 

30 [4]: https://www.rfc-editor.org/rfc/rfc5322 

31 

32 Examples: 

33 >>> email('someone@example.com') 

34 True 

35 >>> email('bogus@@') 

36 ValidationError(func=email, args={'value': 'bogus@@'}) 

37 

38 Args: 

39 value: 

40 eMail string to validate. 

41 ipv6_address: 

42 When the domain part is an IPv6 address. 

43 ipv4_address: 

44 When the domain part is an IPv4 address. 

45 simple_host: 

46 When the domain part is a simple hostname. 

47 rfc_1034: 

48 Allow trailing dot in domain name. 

49 Ref: [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034). 

50 rfc_2782: 

51 Domain name is of type service record. 

52 Ref: [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782). 

53 

54 Returns: 

55 (Literal[True]): If `value` is a valid eMail. 

56 (ValidationError): If `value` is an invalid eMail. 

57 """ 

58 if not value or value.count("@") != 1: 

59 return False 

60 

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

62 

63 if len(username_part) > 64 or len(domain_part) > 253: 

64 # ref: RFC 1034 and 5231 

65 return False 

66 

67 if ipv6_address or ipv4_address: 

68 if domain_part.startswith("[") and domain_part.endswith("]"): 

69 # ref: RFC 5321 

70 domain_part = domain_part.lstrip("[").rstrip("]") 

71 else: 

72 return False 

73 

74 return ( 

75 bool( 

76 hostname( 

77 domain_part, 

78 skip_ipv6_addr=not ipv6_address, 

79 skip_ipv4_addr=not ipv4_address, 

80 may_have_port=False, 

81 maybe_simple=simple_host, 

82 rfc_1034=rfc_1034, 

83 rfc_2782=rfc_2782, 

84 ) 

85 ) 

86 if re.match( 

87 # extended latin 

88 r"(^[\u0100-\u017F\u0180-\u024F\u00A0-\u00FF]" 

89 # dot-atom 

90 + r"|[\u0100-\u017F\u0180-\u024F\u00A0-\u00FF0-9a-z!#$%&'*+/=?^_`{}|~\-]+" 

91 + r"(\.[\u0100-\u017F\u0180-\u024F\u00A0-\u00FF0-9a-z!#$%&'*+/=?^_`{}|~\-]+)*$" 

92 # quoted-string 

93 + r'|^"(' 

94 + r"[\u0100-\u017F\u0180-\u024F\u00A0-\u00FF\001-\010\013\014\016-\037" 

95 + r"!#-\[\]-\177]|\\[\011.]" 

96 + r')*")$', 

97 username_part, 

98 re.IGNORECASE, 

99 ) 

100 else False 

101 )