Skip to content

Commit 8243bd2

Browse files
committed
Change the return value to an object instead of a dict
1 parent 630ca34 commit 8243bd2

File tree

4 files changed

+358
-253
lines changed

4 files changed

+358
-253
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ install:
88

99
.PHONY: lint
1010
lint:
11-
python setup.py check -rms
11+
#python setup.py check -rms
1212
flake8 email_validator tests
1313

1414
.PHONY: test

README.md

Lines changed: 79 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,11 @@ from email_validator import validate_email, EmailNotValidError
5151
email = "my+address@mydomain.tld"
5252

5353
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
5659
except EmailNotValidError as e:
5760
# email is not valid, exception message is human-readable
5861
print(str(e))
@@ -72,7 +75,7 @@ server. If you know ahead of time that SMTPUTF8 is not supported then
7275
addresses that would require SMTPUTF8**:
7376

7477
```python
75-
v = validate_email(email, allow_smtputf8=False)
78+
valid = validate_email(email, allow_smtputf8=False)
7679
```
7780

7881
Overview
@@ -83,17 +86,18 @@ takes an email address (either a `str` or ASCII `bytes`) and:
8386

8487
- Raises a `EmailNotValidError` with a helpful, human-readable error
8588
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.
8891

8992
When an email address is not valid, `validate_email` raises either an
9093
`EmailSyntaxError` if the form of the address is invalid or an
9194
`EmailUndeliverableError` if the domain name does not resolve. Both
9295
exception classes are subclasses of `EmailNotValidError`, which in turn
9396
is a subclass of `ValueError`.
9497

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.
97101

98102
The validator doesn't permit obsoleted forms of email addresses that no
99103
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
167171
delivery would require SMTPUTF8. That's just in those cases where
168172
non-ASCII characters appear before the @-sign. If you do not set
169173
`allow_smtputf8=False`, you can also check the value of the `smtputf8`
170-
field in the returned dict.
174+
field in the returned object.
171175

172176
If your mail submission library doesn't support Unicode at all --- even
173177
in the domain part of the address --- then immediately prior to mail
174178
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:
177181

178182
```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
181185
```
182186

183187
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
204208
address:
205209

206210
```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
209215
```
210216

211217
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
233239
Examples
234240
--------
235241

236-
For the email address `test@example.org`, the returned dict is:
242+
For the email address `test@joshdata.me`, the returned object is:
237243

238244
```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)
256255
```
257256

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:
260259

261260
```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+
279270
```
280271

281272
Note that `smtputf8` is `False` even though the domain part is
282273
internationalized because
283274
[SMTPUTF8](https://tools.ietf.org/html/rfc6531) is only needed if the
284275
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`
286277
fields provide a normalized form of the email address and domain name
287278
(casefolding and Unicode normalization as required by IDNA 2008).
288279

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:
291282

292283
```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)
309292
```
310293

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
313296
return the normalized form of the address: certain Unicode characters
314297
(such as angstrom and ohm) may be replaced by other equivalent code
315298
points (a-with-ring and omega).
316299

317300
Return value
318301
------------
319302

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
321304
are:
322305

323306
`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`
325308
fields (see below).
326309

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
328311
domain part with [IDNA ASCII](https://tools.ietf.org/html/rfc5891).
329312
This field will be present when an ASCII-only form of the email
330313
address exists (including if the email address is already ASCII). If
331314
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`.
333317

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
335319
Unicode NFC normalization applied.
336320

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.
340322

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
342324
address, by round-tripping through IDNA ASCII. If the returned
343325
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.
348334

349335
`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.
356342

357343
`mx`: A list of (priority, domain) tuples of MX records specified in the
358344
DNS for the domain (see [RFC 5321 section
359345
5](https://tools.ietf.org/html/rfc5321#section-5)).
360346

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
362348
specified in DNS and instead are inferred, through an obsolete
363349
mechanism, from A or AAAA records, the value is the type of DNS
364350
record used instead (`A` or `AAAA`).
@@ -406,5 +392,5 @@ To release:
406392
rm -rf dist
407393
python3 setup.py bdist_wheel
408394
twine upload dist/*
409-
git tag v1.0.XXX
395+
git tag v1.0.XXX # replace with version in setup.py
410396
git push --tags

0 commit comments

Comments
 (0)