1
+ from dataclasses import dataclass
2
+ import unicodedata
3
+
4
+
1
5
class EmailNotValidError (ValueError ):
2
6
"""Parent class of all exceptions raised by this module."""
3
7
pass
@@ -8,6 +12,153 @@ class EmailSyntaxError(EmailNotValidError):
8
12
pass
9
13
10
14
15
+ class EmailSyntaxNoAtSignError (EmailSyntaxError ):
16
+ """Exception raised when an email address is missing an @-sign."""
17
+ def __str__ (self ):
18
+ return "An email address must have an @-sign."
19
+
20
+
21
+ @dataclass
22
+ class EmailSyntaxAtSignConfusedError (EmailSyntaxNoAtSignError ):
23
+ """Exception raised when an email address is missing an @-sign but a confusable character is present."""
24
+ character : str
25
+ def __str__ (self ):
26
+ return f"The email address has the { self .character } character instead of a regular at-sign."
27
+
28
+
29
+ def safe_character_display (c : str ) -> str :
30
+ # Return safely displayable characters in quotes.
31
+ if c == '\\ ' :
32
+ return f"\" { c } \" " # can't use repr because it escapes it
33
+ if unicodedata .category (c )[0 ] in ("L" , "N" , "P" , "S" ):
34
+ return repr (c )
35
+
36
+ # Construct a hex string in case the unicode name doesn't exist.
37
+ if ord (c ) < 0xFFFF :
38
+ h = f"U+{ ord (c ):04x} " .upper ()
39
+ else :
40
+ h = f"U+{ ord (c ):08x} " .upper ()
41
+
42
+ # Return the character name or, if it has no name, the hex string.
43
+ return unicodedata .name (c , h )
44
+
45
+
46
+ @dataclass
47
+ class EmailInvalidCharactersError (EmailSyntaxError ):
48
+ """Exception raised when an email address fails validation because it contains invalid characters."""
49
+ characters : list [str ]
50
+ def __str__ (self ):
51
+ return ", " .join (safe_character_display (c ) for c in self .characters )
52
+
53
+
54
+ class EmailInvalidCharactersAfterQuotedString (EmailInvalidCharactersError ):
55
+ """Exception raised when an email address fails validation because it contains invalid characters after a quoted string."""
56
+ def __str__ (self ):
57
+ return "Extra character(s) found after close quote: " + EmailInvalidCharactersError .__str__ (self ) + "."
58
+
59
+
60
+ class EmailInvalidCharactersInUnquotedDisplayName (EmailInvalidCharactersError ):
61
+ """Exception raised when an email address fails validation because it contains invalid characters after a quoted string."""
62
+ def __str__ (self ):
63
+ return "The display name contains invalid characters when not quoted: " + EmailInvalidCharactersError .__str__ (self ) + "."
64
+
65
+
66
+ class EmailIntlCharactersInLocalPart (EmailInvalidCharactersError ):
67
+ """Exception raised when an email address fails validation because it contains invalid characters after a quoted string."""
68
+ def __str__ (self ):
69
+ return "Internationalized characters before the @-sign are not supported: " + EmailInvalidCharactersError .__str__ (self ) + "."
70
+
71
+
72
+ class EmailInvalidCharactersInLocalPart (EmailInvalidCharactersError ):
73
+ """Exception raised when an email address fails validation because it contains invalid characters in the local part."""
74
+ def __str__ (self ):
75
+ return "The email address contains invalid characters before the @-sign: " + EmailInvalidCharactersError .__str__ (self ) + "."
76
+
77
+
78
+ class EmailUnsafeCharactersError (EmailInvalidCharactersError ):
79
+ """Exception raised when an email address fails validation because it contains invalid characters in the local part."""
80
+ def __str__ (self ):
81
+ return "The email address contains unsafe characters: " + EmailInvalidCharactersError .__str__ (self ) + "."
82
+
83
+
84
+ class EmailInvalidCharactersInDomainPart (EmailInvalidCharactersError ):
85
+ """Exception raised when an email address fails validation because it contains invalid characters after a quoted string."""
86
+ def __str__ (self ):
87
+ return f"The part after the @-sign contains invalid characters: " + EmailInvalidCharactersError .__str__ (self ) + "."
88
+
89
+
90
+ class EmailInvalidCharactersInDomainPartAfterUnicodeNormalization (EmailInvalidCharactersError ):
91
+ """Exception raised when an email address fails validation because it contains invalid characters after a quoted string."""
92
+ def __str__ (self ):
93
+ return f"The part after the @-sign contains invalid characters after Unicode normalization: " + EmailInvalidCharactersError .__str__ (self ) + "."
94
+
95
+
96
+ class EmailInvalidCharactersInDomainAddressLiteral (EmailInvalidCharactersError ):
97
+ """Exception raised when an email address fails validation because it contains invalid characters after a quoted string."""
98
+ def __str__ (self ):
99
+ return f"The part after the @-sign contains invalid characters in brackets: " + EmailInvalidCharactersError .__str__ (self ) + "."
100
+
101
+
102
+ class EmailBracketedAddressMissingCloseBracket (EmailSyntaxError ):
103
+ """Exception raised when an email address begins with an angle bracket but does not end with an angle bracket."""
104
+ def __str__ (self ):
105
+ return "An open angle bracket at the start of the email address has to be followed by a close angle bracket at the end."
106
+
107
+
108
+ class EmailBracketedAddressExtraneousText (EmailSyntaxError ):
109
+ """Exception raised when an email address in angle brackets has text after the angle brackets."""
110
+ def __str__ (self ):
111
+ return "There can't be anything after the email address."
112
+
113
+
114
+ class EmailNoLocalPartError (EmailSyntaxError ):
115
+ """Exception raised when an email address in angle brackets has text after the angle brackets."""
116
+ def __str__ (self ):
117
+ return "There must be something before the @-sign."
118
+
119
+
120
+ @dataclass
121
+ class EmailUnhandledSyntaxError (EmailSyntaxError ):
122
+ """Exception raised when an email address has an unhandled error."""
123
+ message : str
124
+ def __str__ (self ):
125
+ return self .message
126
+
127
+
128
+ @dataclass
11
129
class EmailUndeliverableError (EmailNotValidError ):
12
130
"""Exception raised when an email address fails validation because its domain name does not appear deliverable."""
13
- pass
131
+ domain : str
132
+
133
+
134
+ @dataclass
135
+ class EmailUndeliverableNullMxError (EmailUndeliverableError ):
136
+ """Exception raised when an email address fails validation because its domain name has a Null MX record indicating that it cannot receive mail."""
137
+ # See https://www.rfc-editor.org/rfc/rfc7505.
138
+ def __str__ (self ):
139
+ return f"The domain name { self .domain } does not accept email."
140
+
141
+ @dataclass
142
+ class EmailUndeliverableNoMxError (EmailUndeliverableError ):
143
+ """Exception raised when an email address fails validation because its domain name has no MX, A, or AAAA record indicating how to deliver mail."""
144
+ def __str__ (self ):
145
+ return f"The domain name { self .domain } does not accept email."
146
+
147
+ @dataclass
148
+ class EmailUndeliverableFallbackDeniesSendingMailError (EmailUndeliverableError ):
149
+ """Exception raised when an email address fails validation because its domain name has no MX record and it has a SPF record indicating it does not send mail."""
150
+ def __str__ (self ):
151
+ return f"The domain name { self .domain } does not send email."
152
+
153
+ @dataclass
154
+ class EmailUndeliverableNoDomainError (EmailUndeliverableError ):
155
+ """Exception raised when an email address fails validation because its domain name does not exist in DNS."""
156
+ def __str__ (self ):
157
+ return f"The domain name { self .domain } does not exist."
158
+
159
+
160
+ @dataclass
161
+ class EmailUndeliverableOtherError (EmailNotValidError ):
162
+ """Exception raised when an email address fails validation because of an unhandled exception."""
163
+ def __str__ (self ):
164
+ return "There was an error while checking if the domain name in the email address is deliverable."
0 commit comments