python-disposable 0.0.2__tar.gz → 0.0.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-disposable
3
+ Version: 0.0.11
4
+ Summary: Check if an email address or domain belongs to a disposable/temporary email service. Bundles 72k+ domains from disposable/disposable-email-domains.
5
+ Project-URL: Homepage, https://github.com/pescheckit/python-disposable
6
+ Project-URL: Source, https://github.com/pescheckit/python-disposable
7
+ Project-URL: Issues, https://github.com/pescheckit/python-disposable/issues
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: disposable,email,spam,validation
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Communications :: Email
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.9
22
+ Provides-Extra: test
23
+ Requires-Dist: pytest>=7; extra == 'test'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # python-disposable
27
+
28
+ A lightweight Python package to detect disposable/temporary email addresses. Bundles **72,000+ domains** from [disposable/disposable-email-domains](https://github.com/disposable/disposable-email-domains), updated daily — no network calls at runtime.
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install python-disposable
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### Basic check
39
+
40
+ ```python
41
+ from disposable_email import is_disposable, is_valid
42
+
43
+ is_disposable("user@mailinator.com") # True
44
+ is_disposable("user@gmail.com") # False
45
+
46
+ # Works with bare domains too
47
+ is_disposable("guerrillamail.com") # True
48
+
49
+ # Inverse
50
+ is_valid("user@gmail.com") # True
51
+ ```
52
+
53
+ ### Strict mode
54
+
55
+ Strict mode also flags greylisted domains — services that allow anonymous signups but aren't purely disposable (e.g. some free email providers).
56
+
57
+ ```python
58
+ is_disposable("example.com", strict=True)
59
+ is_valid("example.com", strict=True)
60
+ ```
61
+
62
+ ### Subdomain handling
63
+
64
+ Subdomains are automatically resolved to their parent domain.
65
+
66
+ ```python
67
+ is_disposable("mail.mailinator.com") # True
68
+ is_disposable("a.b.guerrillamail.com") # True
69
+ ```
70
+
71
+ ### Get the full domain set
72
+
73
+ ```python
74
+ from disposable_email import get_domains
75
+
76
+ domains = get_domains() # frozenset of 72k+ domains
77
+ domains_strict = get_domains(strict=True) # frozenset of strict list
78
+ ```
79
+
80
+ ### Domain count
81
+
82
+ ```python
83
+ from disposable_email import domain_count
84
+
85
+ domain_count() # 72170
86
+ domain_count(strict=True) # 26468
87
+ ```
88
+
89
+ ## Django example
90
+
91
+ ```python
92
+ from django import forms
93
+ from disposable_email import is_disposable
94
+
95
+ class RegisterForm(forms.Form):
96
+ email = forms.EmailField()
97
+
98
+ def clean_email(self):
99
+ email = self.cleaned_data["email"]
100
+ if is_disposable(email):
101
+ raise forms.ValidationError("Disposable email addresses are not allowed.")
102
+ return email
103
+ ```
104
+
105
+ ## API reference
106
+
107
+ | Function | Description |
108
+ |----------|-------------|
109
+ | `is_disposable(email_or_domain, strict=False)` | Returns `True` if the email/domain is disposable |
110
+ | `is_valid(email_or_domain, strict=False)` | Returns `True` if the email/domain is **not** disposable |
111
+ | `get_domains(strict=False)` | Returns the full `frozenset` of known disposable domains |
112
+ | `domain_count(strict=False)` | Returns the number of bundled domains |
113
+
114
+ ## Data source
115
+
116
+ Domain lists are sourced from [disposable/disposable-email-domains](https://github.com/disposable/disposable-email-domains) and bundled at release time. The upstream list is updated daily via automated scraping of 40+ sources.
117
+
118
+ This package checks for upstream updates every 4 hours and automatically publishes a new version to PyPI when changes are detected.
119
+
120
+ ## License
121
+
122
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,97 @@
1
+ # python-disposable
2
+
3
+ A lightweight Python package to detect disposable/temporary email addresses. Bundles **72,000+ domains** from [disposable/disposable-email-domains](https://github.com/disposable/disposable-email-domains), updated daily — no network calls at runtime.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install python-disposable
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic check
14
+
15
+ ```python
16
+ from disposable_email import is_disposable, is_valid
17
+
18
+ is_disposable("user@mailinator.com") # True
19
+ is_disposable("user@gmail.com") # False
20
+
21
+ # Works with bare domains too
22
+ is_disposable("guerrillamail.com") # True
23
+
24
+ # Inverse
25
+ is_valid("user@gmail.com") # True
26
+ ```
27
+
28
+ ### Strict mode
29
+
30
+ Strict mode also flags greylisted domains — services that allow anonymous signups but aren't purely disposable (e.g. some free email providers).
31
+
32
+ ```python
33
+ is_disposable("example.com", strict=True)
34
+ is_valid("example.com", strict=True)
35
+ ```
36
+
37
+ ### Subdomain handling
38
+
39
+ Subdomains are automatically resolved to their parent domain.
40
+
41
+ ```python
42
+ is_disposable("mail.mailinator.com") # True
43
+ is_disposable("a.b.guerrillamail.com") # True
44
+ ```
45
+
46
+ ### Get the full domain set
47
+
48
+ ```python
49
+ from disposable_email import get_domains
50
+
51
+ domains = get_domains() # frozenset of 72k+ domains
52
+ domains_strict = get_domains(strict=True) # frozenset of strict list
53
+ ```
54
+
55
+ ### Domain count
56
+
57
+ ```python
58
+ from disposable_email import domain_count
59
+
60
+ domain_count() # 72170
61
+ domain_count(strict=True) # 26468
62
+ ```
63
+
64
+ ## Django example
65
+
66
+ ```python
67
+ from django import forms
68
+ from disposable_email import is_disposable
69
+
70
+ class RegisterForm(forms.Form):
71
+ email = forms.EmailField()
72
+
73
+ def clean_email(self):
74
+ email = self.cleaned_data["email"]
75
+ if is_disposable(email):
76
+ raise forms.ValidationError("Disposable email addresses are not allowed.")
77
+ return email
78
+ ```
79
+
80
+ ## API reference
81
+
82
+ | Function | Description |
83
+ |----------|-------------|
84
+ | `is_disposable(email_or_domain, strict=False)` | Returns `True` if the email/domain is disposable |
85
+ | `is_valid(email_or_domain, strict=False)` | Returns `True` if the email/domain is **not** disposable |
86
+ | `get_domains(strict=False)` | Returns the full `frozenset` of known disposable domains |
87
+ | `domain_count(strict=False)` | Returns the number of bundled domains |
88
+
89
+ ## Data source
90
+
91
+ Domain lists are sourced from [disposable/disposable-email-domains](https://github.com/disposable/disposable-email-domains) and bundled at release time. The upstream list is updated daily via automated scraping of 40+ sources.
92
+
93
+ This package checks for upstream updates every 4 hours and automatically publishes a new version to PyPI when changes are detected.
94
+
95
+ ## License
96
+
97
+ MIT — see [LICENSE](LICENSE).
@@ -7,17 +7,23 @@ _domains: Optional[frozenset[str]] = None
7
7
  _domains_strict: Optional[frozenset[str]] = None
8
8
 
9
9
 
10
+ def _load_custom() -> frozenset[str]:
11
+ data = files("disposable_email").joinpath("domains_custom.txt").read_text(encoding="utf-8")
12
+ return frozenset(line.strip().lower() for line in data.splitlines() if line.strip())
13
+
14
+
10
15
  def _load(strict: bool = False) -> frozenset[str]:
11
16
  global _domains, _domains_strict
17
+ custom = _load_custom()
12
18
  if strict:
13
19
  if _domains_strict is None:
14
20
  data = files("disposable_email").joinpath("domains_strict.txt").read_text(encoding="utf-8")
15
- _domains_strict = frozenset(line.strip().lower() for line in data.splitlines() if line.strip())
21
+ _domains_strict = frozenset(line.strip().lower() for line in data.splitlines() if line.strip()) | custom
16
22
  return _domains_strict
17
23
  else:
18
24
  if _domains is None:
19
25
  data = files("disposable_email").joinpath("domains.txt").read_text(encoding="utf-8")
20
- _domains = frozenset(line.strip().lower() for line in data.splitlines() if line.strip())
26
+ _domains = frozenset(line.strip().lower() for line in data.splitlines() if line.strip()) | custom
21
27
  return _domains
22
28
 
23
29
 
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '0.0.11'
22
+ __version_tuple__ = version_tuple = (0, 0, 11)
23
+
24
+ __commit_id__ = commit_id = None