Skip to content

Commit 660cf55

Browse files
committed
maint: update email module
- email's domain part is now compliant to RFC 5321 - it can also accept simple hostname (like `localhost`) - fix missing `utf-8` comment **Related Items** *Issues* - Closes #108 - Closes #142
1 parent e05e967 commit 660cf55

File tree

4 files changed

+43
-5
lines changed

4 files changed

+43
-5
lines changed

validators/domain.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Domain."""
2+
# -*- coding: utf-8 -*-
23

34
# standard
45
import re

validators/email.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@
55
import re
66

77
# local
8+
from .hostname import hostname
89
from .utils import validator
9-
from .domain import domain
1010

1111

1212
@validator
13-
def email(value: str, /):
13+
def email(
14+
value: str,
15+
/,
16+
*,
17+
simple_host: bool = False,
18+
ip_address: bool = False,
19+
rfc_1034: bool = False,
20+
rfc_2782: bool = False,
21+
):
1422
"""Validate an email address.
1523
1624
This was inspired from [Django's email validator][1].
@@ -30,6 +38,16 @@ def email(value: str, /):
3038
Args:
3139
value:
3240
eMail string to validate.
41+
simple_host:
42+
When the domain part is a simple hostname.
43+
ip_address:
44+
When the domain part is an IP address.
45+
rfc_1034:
46+
Allow trailing dot in domain name.
47+
Ref: [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034).
48+
rfc_2782:
49+
Domain name is of type service record.
50+
Ref: [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782).
3351
3452
Returns:
3553
(Literal[True]):
@@ -48,14 +66,31 @@ def email(value: str, /):
4866
# ref: RFC 1034 and 5231
4967
return False
5068

69+
if ip_address:
70+
if domain_part.startswith("[") and domain_part.endswith("]"):
71+
# ref: RFC 5321
72+
domain_part = domain_part.lstrip("[").rstrip("]")
73+
else:
74+
return False
75+
5176
return (
52-
bool(domain(domain_part))
53-
if re.compile(
77+
bool(
78+
hostname(
79+
domain_part,
80+
skip_ip_addr=not ip_address,
81+
may_have_port=False,
82+
maybe_simple=simple_host,
83+
rfc_1034=rfc_1034,
84+
rfc_2782=rfc_2782,
85+
)
86+
)
87+
if re.match(
5488
# dot-atom
5589
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$"
5690
# quoted-string
5791
+ r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)',
92+
username_part,
5893
re.IGNORECASE,
59-
).match(username_part)
94+
)
6095
else False
6196
)

validators/ip_address.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""IP Address."""
2+
# -*- coding: utf-8 -*-
23

34
# standard
45
from ipaddress import (

validators/uuid.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""UUID."""
2+
# -*- coding: utf-8 -*-
23

34
# standard
45
from typing import Union

0 commit comments

Comments
 (0)