namecheap-python 1.2.0__py3-none-any.whl → 1.3.0__py3-none-any.whl
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.
- namecheap/__init__.py +3 -1
- namecheap/_api/dns.py +38 -0
- namecheap/_api/domains.py +47 -1
- namecheap/models.py +11 -0
- namecheap_cli/__main__.py +97 -0
- {namecheap_python-1.2.0.dist-info → namecheap_python-1.3.0.dist-info}/METADATA +19 -5
- {namecheap_python-1.2.0.dist-info → namecheap_python-1.3.0.dist-info}/RECORD +10 -10
- {namecheap_python-1.2.0.dist-info → namecheap_python-1.3.0.dist-info}/WHEEL +0 -0
- {namecheap_python-1.2.0.dist-info → namecheap_python-1.3.0.dist-info}/entry_points.txt +0 -0
- {namecheap_python-1.2.0.dist-info → namecheap_python-1.3.0.dist-info}/licenses/LICENSE +0 -0
namecheap/__init__.py
CHANGED
|
@@ -18,12 +18,13 @@ from .models import (
|
|
|
18
18
|
DNSRecord,
|
|
19
19
|
Domain,
|
|
20
20
|
DomainCheck,
|
|
21
|
+
DomainContacts,
|
|
21
22
|
DomainInfo,
|
|
22
23
|
EmailForward,
|
|
23
24
|
Nameservers,
|
|
24
25
|
)
|
|
25
26
|
|
|
26
|
-
__version__ = "1.
|
|
27
|
+
__version__ = "1.3.0"
|
|
27
28
|
__all__ = [
|
|
28
29
|
"AccountBalance",
|
|
29
30
|
"ConfigurationError",
|
|
@@ -31,6 +32,7 @@ __all__ = [
|
|
|
31
32
|
"DNSRecord",
|
|
32
33
|
"Domain",
|
|
33
34
|
"DomainCheck",
|
|
35
|
+
"DomainContacts",
|
|
34
36
|
"DomainInfo",
|
|
35
37
|
"EmailForward",
|
|
36
38
|
"Namecheap",
|
namecheap/_api/dns.py
CHANGED
|
@@ -528,3 +528,41 @@ class DnsAPI(BaseAPI):
|
|
|
528
528
|
EmailForward(mailbox=f.get("@mailbox", ""), forward_to=f.get("#text", ""))
|
|
529
529
|
for f in forwards
|
|
530
530
|
]
|
|
531
|
+
|
|
532
|
+
def set_email_forwarding(
|
|
533
|
+
self, domain: str, rules: list[EmailForward] | list[dict[str, str]]
|
|
534
|
+
) -> bool:
|
|
535
|
+
"""
|
|
536
|
+
Set email forwarding rules for a domain. Replaces all existing rules.
|
|
537
|
+
|
|
538
|
+
Args:
|
|
539
|
+
domain: Domain name
|
|
540
|
+
rules: List of EmailForward or dicts with 'mailbox' and 'forward_to' keys
|
|
541
|
+
|
|
542
|
+
Returns:
|
|
543
|
+
True if successful
|
|
544
|
+
|
|
545
|
+
Examples:
|
|
546
|
+
>>> nc.dns.set_email_forwarding("example.com", [
|
|
547
|
+
... EmailForward(mailbox="info", forward_to="me@gmail.com"),
|
|
548
|
+
... EmailForward(mailbox="support", forward_to="help@gmail.com"),
|
|
549
|
+
... ])
|
|
550
|
+
"""
|
|
551
|
+
assert rules, "At least one forwarding rule is required"
|
|
552
|
+
|
|
553
|
+
params: dict[str, Any] = {"DomainName": domain}
|
|
554
|
+
for i, rule in enumerate(rules, 1):
|
|
555
|
+
if isinstance(rule, EmailForward):
|
|
556
|
+
params[f"MailBox{i}"] = rule.mailbox
|
|
557
|
+
params[f"ForwardTo{i}"] = rule.forward_to
|
|
558
|
+
else:
|
|
559
|
+
params[f"MailBox{i}"] = rule["mailbox"]
|
|
560
|
+
params[f"ForwardTo{i}"] = rule["forward_to"]
|
|
561
|
+
|
|
562
|
+
result: Any = self._request(
|
|
563
|
+
"namecheap.domains.dns.setEmailForwarding",
|
|
564
|
+
params,
|
|
565
|
+
path="DomainDNSSetEmailForwardingResult",
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
return bool(result and result.get("@IsSuccess", "false").lower() == "true")
|
namecheap/_api/domains.py
CHANGED
|
@@ -9,7 +9,7 @@ from typing import Any
|
|
|
9
9
|
import tldextract
|
|
10
10
|
|
|
11
11
|
from namecheap.logging import logger
|
|
12
|
-
from namecheap.models import Contact, Domain, DomainCheck, DomainInfo
|
|
12
|
+
from namecheap.models import Contact, Domain, DomainCheck, DomainContacts, DomainInfo
|
|
13
13
|
|
|
14
14
|
from .base import BaseAPI
|
|
15
15
|
|
|
@@ -156,6 +156,52 @@ class DomainsAPI(BaseAPI):
|
|
|
156
156
|
|
|
157
157
|
return DomainInfo.model_validate(flat)
|
|
158
158
|
|
|
159
|
+
def get_contacts(self, domain: str) -> DomainContacts:
|
|
160
|
+
"""
|
|
161
|
+
Get contact information for a domain.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
domain: Domain name
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
DomainContacts with registrant, tech, admin, and aux_billing contacts
|
|
168
|
+
|
|
169
|
+
Examples:
|
|
170
|
+
>>> contacts = nc.domains.get_contacts("example.com")
|
|
171
|
+
>>> print(contacts.registrant.email)
|
|
172
|
+
"""
|
|
173
|
+
result: Any = self._request(
|
|
174
|
+
"namecheap.domains.getContacts",
|
|
175
|
+
{"DomainName": domain},
|
|
176
|
+
path="DomainContactsResult",
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
assert result, f"API returned empty result for {domain} getContacts"
|
|
180
|
+
|
|
181
|
+
def parse_contact(data: dict[str, Any]) -> Contact:
|
|
182
|
+
return Contact.model_validate(
|
|
183
|
+
{
|
|
184
|
+
"FirstName": data.get("FirstName", ""),
|
|
185
|
+
"LastName": data.get("LastName", ""),
|
|
186
|
+
"Organization": data.get("Organization"),
|
|
187
|
+
"Address1": data.get("Address1", ""),
|
|
188
|
+
"Address2": data.get("Address2"),
|
|
189
|
+
"City": data.get("City", ""),
|
|
190
|
+
"StateProvince": data.get("StateProvince", ""),
|
|
191
|
+
"PostalCode": data.get("PostalCode", ""),
|
|
192
|
+
"Country": data.get("Country", ""),
|
|
193
|
+
"Phone": data.get("Phone", ""),
|
|
194
|
+
"EmailAddress": data.get("EmailAddress", ""),
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
return DomainContacts(
|
|
199
|
+
registrant=parse_contact(result.get("Registrant", {})),
|
|
200
|
+
tech=parse_contact(result.get("Tech", {})),
|
|
201
|
+
admin=parse_contact(result.get("Admin", {})),
|
|
202
|
+
aux_billing=parse_contact(result.get("AuxBilling", {})),
|
|
203
|
+
)
|
|
204
|
+
|
|
159
205
|
def register(
|
|
160
206
|
self,
|
|
161
207
|
domain: str,
|
namecheap/models.py
CHANGED
|
@@ -336,6 +336,17 @@ class Contact(BaseModel):
|
|
|
336
336
|
model_config = ConfigDict(populate_by_name=True)
|
|
337
337
|
|
|
338
338
|
|
|
339
|
+
class DomainContacts(BaseModel):
|
|
340
|
+
"""Contact information for all roles on a domain."""
|
|
341
|
+
|
|
342
|
+
registrant: Contact
|
|
343
|
+
tech: Contact
|
|
344
|
+
admin: Contact
|
|
345
|
+
aux_billing: Contact
|
|
346
|
+
|
|
347
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
348
|
+
|
|
349
|
+
|
|
339
350
|
class Config(BaseModel):
|
|
340
351
|
"""Client configuration with validation."""
|
|
341
352
|
|
namecheap_cli/__main__.py
CHANGED
|
@@ -919,6 +919,103 @@ def dns_email_forwarding(config: Config, domain: str) -> None:
|
|
|
919
919
|
sys.exit(1)
|
|
920
920
|
|
|
921
921
|
|
|
922
|
+
@dns_group.command("set-email-forwarding")
|
|
923
|
+
@click.argument("domain")
|
|
924
|
+
@click.argument("rules", nargs=-1, required=True)
|
|
925
|
+
@click.option("--yes", "-y", is_flag=True, help="Skip confirmation")
|
|
926
|
+
@pass_config
|
|
927
|
+
def dns_set_email_forwarding(
|
|
928
|
+
config: Config, domain: str, rules: tuple[str, ...], yes: bool
|
|
929
|
+
) -> None:
|
|
930
|
+
"""Set email forwarding rules. Replaces all existing rules.
|
|
931
|
+
|
|
932
|
+
Rules are in mailbox:forward_to format.
|
|
933
|
+
|
|
934
|
+
Example:
|
|
935
|
+
namecheap-cli dns set-email-forwarding example.com info:me@gmail.com support:help@gmail.com
|
|
936
|
+
"""
|
|
937
|
+
nc = config.init_client()
|
|
938
|
+
|
|
939
|
+
parsed = []
|
|
940
|
+
for rule in rules:
|
|
941
|
+
assert ":" in rule, f"Invalid rule format '{rule}', expected mailbox:forward_to"
|
|
942
|
+
mailbox, forward_to = rule.split(":", 1)
|
|
943
|
+
parsed.append({"mailbox": mailbox, "forward_to": forward_to})
|
|
944
|
+
|
|
945
|
+
try:
|
|
946
|
+
if not yes and not config.quiet:
|
|
947
|
+
console.print(f"\n[yellow]Setting email forwarding for {domain}:[/yellow]")
|
|
948
|
+
for p in parsed:
|
|
949
|
+
console.print(f" • {p['mailbox']}@{domain} → {p['forward_to']}")
|
|
950
|
+
console.print()
|
|
951
|
+
|
|
952
|
+
if not Confirm.ask("Continue?", default=True):
|
|
953
|
+
console.print("[yellow]Cancelled[/yellow]")
|
|
954
|
+
return
|
|
955
|
+
|
|
956
|
+
with Progress(
|
|
957
|
+
SpinnerColumn(),
|
|
958
|
+
TextColumn("[progress.description]{task.description}"),
|
|
959
|
+
transient=True,
|
|
960
|
+
) as progress:
|
|
961
|
+
progress.add_task(f"Setting email forwarding for {domain}...", total=None)
|
|
962
|
+
success = nc.dns.set_email_forwarding(domain, parsed)
|
|
963
|
+
|
|
964
|
+
if success:
|
|
965
|
+
console.print("[green]✅ Email forwarding updated successfully![/green]")
|
|
966
|
+
else:
|
|
967
|
+
console.print("[red]❌ Failed to update email forwarding[/red]")
|
|
968
|
+
sys.exit(1)
|
|
969
|
+
|
|
970
|
+
except NamecheapError as e:
|
|
971
|
+
console.print(f"[red]❌ Error: {e}[/red]")
|
|
972
|
+
sys.exit(1)
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
@domain_group.command("contacts")
|
|
976
|
+
@click.argument("domain")
|
|
977
|
+
@pass_config
|
|
978
|
+
def domain_contacts(config: Config, domain: str) -> None:
|
|
979
|
+
"""Show contact information for a domain."""
|
|
980
|
+
nc = config.init_client()
|
|
981
|
+
|
|
982
|
+
try:
|
|
983
|
+
with Progress(
|
|
984
|
+
SpinnerColumn(),
|
|
985
|
+
TextColumn("[progress.description]{task.description}"),
|
|
986
|
+
transient=True,
|
|
987
|
+
) as progress:
|
|
988
|
+
progress.add_task(f"Getting contacts for {domain}...", total=None)
|
|
989
|
+
contacts = nc.domains.get_contacts(domain)
|
|
990
|
+
|
|
991
|
+
if config.output_format == "table":
|
|
992
|
+
for role, contact in [
|
|
993
|
+
("Registrant", contacts.registrant),
|
|
994
|
+
("Tech", contacts.tech),
|
|
995
|
+
("Admin", contacts.admin),
|
|
996
|
+
("Billing", contacts.aux_billing),
|
|
997
|
+
]:
|
|
998
|
+
console.print(f"\n[bold cyan]{role}[/bold cyan]")
|
|
999
|
+
console.print(f" {contact.first_name} {contact.last_name}")
|
|
1000
|
+
if contact.organization:
|
|
1001
|
+
console.print(f" {contact.organization}")
|
|
1002
|
+
console.print(f" {contact.email}")
|
|
1003
|
+
console.print(f" {contact.phone}")
|
|
1004
|
+
console.print(f" {contact.address1}")
|
|
1005
|
+
if contact.address2:
|
|
1006
|
+
console.print(f" {contact.address2}")
|
|
1007
|
+
console.print(
|
|
1008
|
+
f" {contact.city}, {contact.state_province} {contact.postal_code}"
|
|
1009
|
+
)
|
|
1010
|
+
console.print(f" {contact.country}")
|
|
1011
|
+
else:
|
|
1012
|
+
output_formatter(contacts.model_dump(), config.output_format)
|
|
1013
|
+
|
|
1014
|
+
except NamecheapError as e:
|
|
1015
|
+
console.print(f"[red]❌ Error: {e}[/red]")
|
|
1016
|
+
sys.exit(1)
|
|
1017
|
+
|
|
1018
|
+
|
|
922
1019
|
@cli.group("account")
|
|
923
1020
|
def account_group() -> None:
|
|
924
1021
|
"""Account management commands."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: namecheap-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: A friendly Python SDK for Namecheap API
|
|
5
5
|
Project-URL: Homepage, https://github.com/adriangalilea/namecheap-python
|
|
6
6
|
Project-URL: Repository, https://github.com/adriangalilea/namecheap-python
|
|
@@ -380,9 +380,24 @@ print(bal.funds_required_for_auto_renew) # Decimal('20.16')
|
|
|
380
380
|
### Email Forwarding
|
|
381
381
|
|
|
382
382
|
```python
|
|
383
|
+
# Read
|
|
383
384
|
rules = nc.dns.get_email_forwarding("example.com")
|
|
384
385
|
for r in rules:
|
|
385
386
|
print(f"{r.mailbox} -> {r.forward_to}")
|
|
387
|
+
|
|
388
|
+
# Write (replaces all existing rules)
|
|
389
|
+
nc.dns.set_email_forwarding("example.com", [
|
|
390
|
+
EmailForward(mailbox="info", forward_to="me@gmail.com"),
|
|
391
|
+
EmailForward(mailbox="support", forward_to="help@gmail.com"),
|
|
392
|
+
])
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Domain Contacts
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
contacts = nc.domains.get_contacts("example.com")
|
|
399
|
+
print(f"{contacts.registrant.first_name} {contacts.registrant.last_name}")
|
|
400
|
+
print(contacts.registrant.email)
|
|
386
401
|
```
|
|
387
402
|
|
|
388
403
|
### Domain Management
|
|
@@ -462,11 +477,10 @@ nc.dns.builder().a("www", "192.0.2.1", ttl=1800) # Shows as "30 min"
|
|
|
462
477
|
|
|
463
478
|
| API | Status | Methods |
|
|
464
479
|
|-----|--------|---------|
|
|
465
|
-
| `namecheap.domains.*` | ✅ Done | `check`, `list`, `getInfo`, `register`, `renew`, `setContacts`, `lock`/`unlock` |
|
|
466
|
-
| `namecheap.domains.dns.*` | ✅ Done | `getHosts`, `setHosts` (builder pattern), `add`, `delete`, `export`, `getList`, `setCustom`, `setDefault`, `getEmailForwarding` |
|
|
480
|
+
| `namecheap.domains.*` | ✅ Done | `check`, `list`, `getInfo`, `getContacts`, `register`, `renew`, `setContacts`, `lock`/`unlock` |
|
|
481
|
+
| `namecheap.domains.dns.*` | ✅ Done | `getHosts`, `setHosts` (builder pattern), `add`, `delete`, `export`, `getList`, `setCustom`, `setDefault`, `getEmailForwarding`, `setEmailForwarding` |
|
|
467
482
|
| `namecheap.users.*` | ⚠️ Partial | `getBalances`, `getPricing` (needs debugging). Planned: `changePassword`, `update`, `create`, `login`, `resetPassword` |
|
|
468
|
-
| `namecheap.domains.*` | 🚧 Planned | `
|
|
469
|
-
| `namecheap.domains.dns.*` | 🚧 Planned | `setEmailForwarding` |
|
|
483
|
+
| `namecheap.domains.*` | 🚧 Planned | `getTldList`, `reactivate` |
|
|
470
484
|
| `namecheap.users.address.*` | 🚧 Planned | `create`, `delete`, `getInfo`, `getList`, `setDefault`, `update` |
|
|
471
485
|
| `namecheap.ssl.*` | 🚧 Planned | `create`, `activate`, `renew`, `revoke`, `getList`, `getInfo`, `parseCSR`, `reissue`, and more |
|
|
472
486
|
| `namecheap.domains.transfer.*` | 🚧 Planned | `create`, `getStatus`, `updateStatus`, `getList` |
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
namecheap/__init__.py,sha256=
|
|
1
|
+
namecheap/__init__.py,sha256=sUX2-G_o6k1POjfJ9oV32Hi08zaPNL4WwfgrLr_2Qak,879
|
|
2
2
|
namecheap/client.py,sha256=KesIaZVa9HpXvlp-hc3nr2x-sqzMPiHEa8NibiPq580,6644
|
|
3
3
|
namecheap/errors.py,sha256=5bGbV1e4_jkK8YXZXbLF6GJCVUTKw1CtMl9-mz7ogZg,5010
|
|
4
4
|
namecheap/logging.py,sha256=lMR1fr1dWWz3z2NFEY-vl8b52FmmhH76R2NjyifSdYA,3396
|
|
5
|
-
namecheap/models.py,sha256=
|
|
5
|
+
namecheap/models.py,sha256=0Fhni7yKd84bBopPURIvhwmOCYMzw8tlZwHWzRRZphY,14494
|
|
6
6
|
namecheap/_api/__init__.py,sha256=ymQxKCySphoeoo4s_J0tLziXttLNhOQ8AZbCzFcuAHs,36
|
|
7
7
|
namecheap/_api/base.py,sha256=FoczO1Q860PaFUFv-S3IoIV2xaGVJAlchkWnmTI6dlw,6121
|
|
8
|
-
namecheap/_api/dns.py,sha256=
|
|
9
|
-
namecheap/_api/domains.py,sha256=
|
|
8
|
+
namecheap/_api/dns.py,sha256=Hny5TsVWmmG-3rF6kb8JwboGFt2wKsd4-Z6T8GannBM,17213
|
|
9
|
+
namecheap/_api/domains.py,sha256=txikTYACM82-3IXg2Gqagh9fRZ8aIZiu05unNpy2Zqs,20039
|
|
10
10
|
namecheap/_api/users.py,sha256=CCXSZJiPkQiLHYRAlYKTBCDG3-JSPdNkNWWww71JXV0,795
|
|
11
11
|
namecheap_cli/README.md,sha256=liduIiGr8DHXGTht5swrYnvtAlcdCMQOnSdCD61g4Vw,7337
|
|
12
12
|
namecheap_cli/__init__.py,sha256=nGRHc_CkO4xKhSQdAVG-koEffP8VS0TvbfbZkg7Jg4k,108
|
|
13
|
-
namecheap_cli/__main__.py,sha256=
|
|
13
|
+
namecheap_cli/__main__.py,sha256=0vHk5aAhEzPKQ-UQOQdYqsolCF13DG3k9_z3pUbZXwk,40020
|
|
14
14
|
namecheap_cli/completion.py,sha256=JTEMnceQli7TombjZkHh-IcZKW4RFRI8Yk5VynxPsEA,2777
|
|
15
15
|
namecheap_dns_tui/README.md,sha256=It16ZiZh0haEeaENfF5HX0Ec4dBawdTYiAi-TiG9wi0,1690
|
|
16
16
|
namecheap_dns_tui/__init__.py,sha256=-yL_1Ha41FlQcmjG-raUrZP9CjTJD3d0w2BW2X-twJg,106
|
|
@@ -19,8 +19,8 @@ namecheap_dns_tui/assets/screenshot1.png,sha256=OXO2P80ll5WRzLYgaakcNnzos8svlJoX
|
|
|
19
19
|
namecheap_dns_tui/assets/screenshot2.png,sha256=5VN_qDMNhWEyrOqKw7vxl1h-TgmZQ_V9aph3Xmf_AFg,279194
|
|
20
20
|
namecheap_dns_tui/assets/screenshot3.png,sha256=h39wSKxx1JCkgeAB7Q3_JlBcAtX1vsRFKtWtOwbBVso,220625
|
|
21
21
|
namecheap_dns_tui/assets/screenshot4.png,sha256=J4nCOW16z3vaRiPbcMiiIRgV7q3XFbi_1N1ivD1Pa4Y,238068
|
|
22
|
-
namecheap_python-1.
|
|
23
|
-
namecheap_python-1.
|
|
24
|
-
namecheap_python-1.
|
|
25
|
-
namecheap_python-1.
|
|
26
|
-
namecheap_python-1.
|
|
22
|
+
namecheap_python-1.3.0.dist-info/METADATA,sha256=phjrSgjok2JzRDjOQsEit1eb9Z7WF7Da5beLiKSEbGA,18802
|
|
23
|
+
namecheap_python-1.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
24
|
+
namecheap_python-1.3.0.dist-info/entry_points.txt,sha256=AyhiXroLUpM0Vdo_-RvH0S8o4XDPsDlsEl_65vm6DEk,96
|
|
25
|
+
namecheap_python-1.3.0.dist-info/licenses/LICENSE,sha256=pemTblFP6BBje3bBv_yL_sr2iAqB2H0-LdWMvVIR42o,1062
|
|
26
|
+
namecheap_python-1.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|