@@ -51,8 +51,11 @@ from email_validator import validate_email, EmailNotValidError
51
51
email = " my+address@mydomain.tld"
52
52
53
53
try :
54
- v = validate_email(email) # validate and get info
55
- email = v[" email" ] # replace with normalized form
54
+ # Validate.
55
+ valid = validate_email(email)
56
+
57
+ # Update with the normalized form.
58
+ email = valid.email
56
59
except EmailNotValidError as e:
57
60
# email is not valid, exception message is human-readable
58
61
print (str (e))
@@ -72,7 +75,7 @@ server. If you know ahead of time that SMTPUTF8 is not supported then
72
75
addresses that would require SMTPUTF8** :
73
76
74
77
``` python
75
- v = validate_email(email, allow_smtputf8 = False )
78
+ valid = validate_email(email, allow_smtputf8 = False )
76
79
```
77
80
78
81
Overview
@@ -83,17 +86,18 @@ takes an email address (either a `str` or ASCII `bytes`) and:
83
86
84
87
- Raises a ` EmailNotValidError ` with a helpful, human-readable error
85
88
message explaining why the email address is not valid, or
86
- - Returns a dict with information about the deliverability of the
87
- email address .
89
+ - Returns an object with a normalized form of the email address and
90
+ other information about it .
88
91
89
92
When an email address is not valid, ` validate_email ` raises either an
90
93
` EmailSyntaxError ` if the form of the address is invalid or an
91
94
` EmailUndeliverableError ` if the domain name does not resolve. Both
92
95
exception classes are subclasses of ` EmailNotValidError ` , which in turn
93
96
is a subclass of ` ValueError ` .
94
97
95
- But when an email address is valid, a dict is returned containing
96
- information that might aid deliverability (see below).
98
+ But when an email address is valid, an object is returned containing
99
+ a normalized form of the email address (which you should use!) and
100
+ other information.
97
101
98
102
The validator doesn't permit obsoleted forms of email addresses that no
99
103
one uses anymore even though they are still valid and deliverable, since
@@ -167,17 +171,17 @@ This will cause the validation function to raise a `EmailSyntaxError` if
167
171
delivery would require SMTPUTF8. That's just in those cases where
168
172
non-ASCII characters appear before the @-sign. If you do not set
169
173
` allow_smtputf8=False ` , you can also check the value of the ` smtputf8 `
170
- field in the returned dict .
174
+ field in the returned object .
171
175
172
176
If your mail submission library doesn't support Unicode at all --- even
173
177
in the domain part of the address --- then immediately prior to mail
174
178
submission you must replace the email address with its ASCII-ized form.
175
- This library gives you back the ASCII-ized form in the ` email_ascii `
176
- field in the returned dict , which you can get like this:
179
+ This library gives you back the ASCII-ized form in the ` ascii_email `
180
+ field in the returned object , which you can get like this:
177
181
178
182
``` python
179
- v = validate_email(email, allow_smtputf8 = False )
180
- email = v[ ' email_ascii ' ]
183
+ valid = validate_email(email, allow_smtputf8 = False )
184
+ email = valid.ascii_email
181
185
```
182
186
183
187
The local part is left alone (if it has internationalized characters
@@ -204,8 +208,10 @@ validation provides the correctly normalized form of the given email
204
208
address:
205
209
206
210
``` python
207
- v = validate_email(email)
208
- email = v[' email' ]
211
+ valid = validate_email(" me@Domain.com" )
212
+ email = valid.ascii_email
213
+ print (email)
214
+ # prints: me@domain.com
209
215
```
210
216
211
217
Because you may get an email address in a variety of forms, you ought to
@@ -233,132 +239,112 @@ in the domain part, and possibly other
233
239
Examples
234
240
--------
235
241
236
- For the email address ` test@example.org ` , the returned dict is:
242
+ For the email address ` test@joshdata.me ` , the returned object is:
237
243
238
244
``` python
239
- {
240
- " email" : " test@example.org" ,
241
- " email_ascii" : " test@example.org" ,
242
- " local" : " test" ,
243
- " domain" : " example.org" ,
244
- " domain_i18n" : " example.org" ,
245
-
246
- " smtputf8" : false,
247
-
248
- " mx" : [
249
- [
250
- 0 ,
251
- " 93.184.216.34"
252
- ]
253
- ],
254
- " mx-fallback" : " A"
255
- }
245
+ ValidatedEmail(
246
+ email = ' test@joshdata.me' ,
247
+ local_part = ' test' ,
248
+ domain = ' joshdata.me' ,
249
+ ascii_email = ' test@joshdata.me' ,
250
+ ascii_local_part = ' test' ,
251
+ ascii_domain = ' joshdata.me' ,
252
+ smtputf8 = False ,
253
+ mx = [(10 , ' box.occams.info' )],
254
+ mx_fallback_type = None )
256
255
```
257
256
258
- For the fictitious address ` example@良好Mail.中国 ` , which has an
259
- internationalized domain but ASCII local part, the returned dict is:
257
+ For the fictitious address ` example@ツ.life ` , which has an
258
+ internationalized domain but ASCII local part, the returned object is:
260
259
261
260
``` python
262
- {
263
- " email" : " example@良好mail.中国" ,
264
- " email_ascii" : " example@xn--mail-p86gl01s.xn--fiqs8s" ,
265
- " local" : " example" ,
266
- " domain" : " xn--mail-p86gl01s.xn--fiqs8s" ,
267
- " domain_i18n" : " 良好mail.中国" ,
268
-
269
- " smtputf8" : false,
270
-
271
- " mx" : [
272
- [
273
- 0 ,
274
- " 218.241.116.40"
275
- ]
276
- ],
277
- " mx-fallback" : " A"
278
- }
261
+ ValidatedEmail(
262
+ email = ' example@ツ.life' ,
263
+ local_part = ' example' ,
264
+ domain = ' ツ.life' ,
265
+ ascii_email = ' example@xn--bdk.life' ,
266
+ ascii_local_part = ' example' ,
267
+ ascii_domain = ' xn--bdk.life' ,
268
+ smtputf8 = False )
269
+
279
270
```
280
271
281
272
Note that ` smtputf8 ` is ` False ` even though the domain part is
282
273
internationalized because
283
274
[ SMTPUTF8] ( https://tools.ietf.org/html/rfc6531 ) is only needed if the
284
275
local part of the address is internationalized (the domain part can be
285
- converted to IDNA ASCII). Also note that the ` email ` and ` domain_i18n `
276
+ converted to IDNA ASCII). Also note that the ` email ` and ` domain `
286
277
fields provide a normalized form of the email address and domain name
287
278
(casefolding and Unicode normalization as required by IDNA 2008).
288
279
289
- For the fictitious address ` 树大@occams.info ` , which has an
290
- internationalized local part, the returned dict is:
280
+ For the fictitious address ` ツ-test@joshdata.me ` , which has an
281
+ internationalized local part, the returned object is:
291
282
292
283
``` python
293
- {
294
- " email" : " 树大@occams.info" ,
295
- " local" : " 树大" ,
296
- " domain" : " occams.info" ,
297
- " domain_i18n" : " occams.info" ,
298
-
299
- " smtputf8" : true,
300
-
301
- " mx" : [
302
- [
303
- 10 ,
304
- " box.occams.info"
305
- ]
306
- ],
307
- " mx-fallback" : false
308
- }
284
+ ValidatedEmail(
285
+ email = ' ツ-test@joshdata.me' ,
286
+ local_part = ' ツ-test' ,
287
+ domain = ' joshdata.me' ,
288
+ ascii_email = None ,
289
+ ascii_local_part = None ,
290
+ ascii_domain = ' joshdata.me' ,
291
+ smtputf8 = True )
309
292
```
310
293
311
- Now ` smtputf8 ` is ` True ` and ` email_ascii ` is missing because the local
312
- part of the address is internationalized. The ` local ` and ` email ` fields
294
+ Now ` smtputf8 ` is ` True ` and ` ascii_email ` is ` None ` because the local
295
+ part of the address is internationalized. The ` local_part ` and ` email ` fields
313
296
return the normalized form of the address: certain Unicode characters
314
297
(such as angstrom and ohm) may be replaced by other equivalent code
315
298
points (a-with-ring and omega).
316
299
317
300
Return value
318
301
------------
319
302
320
- When an email address passes validation, the fields in the returned dict
303
+ When an email address passes validation, the fields in the returned object
321
304
are:
322
305
323
306
` email ` : The canonical form of the email address, mostly useful for
324
- display purposes. This merely combines the ` local ` and ` domain_i18n `
307
+ display purposes. This merely combines the ` local_part ` and ` domain `
325
308
fields (see below).
326
309
327
- ` email_ascii ` : If present , an ASCII-only form of the email address by replacing the
310
+ ` ascii_email ` : If set , an ASCII-only form of the email address by replacing the
328
311
domain part with [ IDNA ASCII] ( https://tools.ietf.org/html/rfc5891 ) .
329
312
This field will be present when an ASCII-only form of the email
330
313
address exists (including if the email address is already ASCII). If
331
314
the local part of the email address contains internationalized
332
- characters, ` email_ascii ` will not be present.
315
+ characters, ` ascii_email ` will be ` None ` . If set, it merely combines
316
+ ` ascii_local_part ` and ` ascii_domain ` .
333
317
334
- ` local ` : The local part of the given email address (before the @-sign) with
318
+ ` local_part ` : The local part of the given email address (before the @-sign) with
335
319
Unicode NFC normalization applied.
336
320
337
- ` domain ` : The [ IDNA ASCII] ( https://tools.ietf.org/html/rfc5891 ) -encoded form
338
- of the domain part of the given email address (after the @-sign), as
339
- it would be transmitted on the wire.
321
+ ` ascii_local_part ` : If set, the local part, which is composed of ASCII characters only.
340
322
341
- ` domain_i18n ` : The canonical internationalized form of the domain part of the
323
+ ` domain ` : The canonical internationalized form of the domain part of the
342
324
address, by round-tripping through IDNA ASCII. If the returned
343
325
string contains non-ASCII characters, either the
344
- [ SMTPUTF8] ( https://tools.ietf.org/html/rfc6531 ) feature of MTAs will
345
- be required to transmit the message or else the email address's
346
- domain part must be converted to IDNA ASCII first (given in the
347
- returned ` domain ` field).
326
+ [ SMTPUTF8] ( https://tools.ietf.org/html/rfc6531 ) feature of your
327
+ mail relay will be required to transmit the message or else the
328
+ email address's domain part must be converted to IDNA ASCII first
329
+ (given in the returned ` domain ` field).
330
+
331
+ ` ascii_domain ` : The [ IDNA ASCII] ( https://tools.ietf.org/html/rfc5891 ) -encoded form
332
+ of the domain part of the given email address (after the @-sign), as
333
+ it would be transmitted on the wire.
348
334
349
335
` smtputf8 ` : A boolean indicating that the
350
- [ SMTPUTF8] ( https://tools.ietf.org/html/rfc6531 ) feature of MTAs will
351
- be required to transmit messages to this address because the local
352
- part of the address has non-ASCII characters (the local part cannot
353
- be IDNA-encoded). If ` allow_smtputf8=False ` is passed as an
354
- argument, this flag will always be false because an exception is
355
- raised if it would have been true.
336
+ [ SMTPUTF8] ( https://tools.ietf.org/html/rfc6531 ) feature of your
337
+ mail relay will be required to transmit messages to this address
338
+ because the local part of the address has non-ASCII characters (the
339
+ local part cannot be IDNA-encoded). If ` allow_smtputf8=False ` is
340
+ passed as an argument, this flag will always be false because an
341
+ exception is raised if it would have been true.
356
342
357
343
` mx ` : A list of (priority, domain) tuples of MX records specified in the
358
344
DNS for the domain (see [ RFC 5321 section
359
345
5] ( https://tools.ietf.org/html/rfc5321#section-5 ) ).
360
346
361
- ` mx-fallback ` : ` None ` if an ` MX ` record is found. If no MX records are actually
347
+ ` mx_fallback_type ` : ` None ` if an ` MX ` record is found. If no MX records are actually
362
348
specified in DNS and instead are inferred, through an obsolete
363
349
mechanism, from A or AAAA records, the value is the type of DNS
364
350
record used instead (` A ` or ` AAAA ` ).
@@ -406,5 +392,5 @@ To release:
406
392
rm -rf dist
407
393
python3 setup.py bdist_wheel
408
394
twine upload dist/*
409
- git tag v1.0.XXX
395
+ git tag v1.0.XXX # replace with version in setup.py
410
396
git push --tags
0 commit comments