1+ import requests
2+ from ..config import get_base_url
3+ from ..utils .decorators import deprecated
4+ from typing import Optional , Dict , Any , List
5+ from ..exceptions import APIError , BadRequestError
6+
7+ @deprecated ("is_valid_data_raw" )
8+ def is_valid_data (token , data ):
9+ if not any ([key in list (data .keys ()) for key in ["url" , "email" , "phone" , "domain" , "creditCard" , "ip" , "wallet" , "userAgent" , "iban" ]]): raise BadRequestError ("You must provide at least one parameter." )
10+ try :
11+ response = requests .post (f"{ get_base_url ()} /v1/private/secure/verify" , json = data , headers = {"User-Agent" : "DymoAPISDK/1.0.0" , "X-Dymo-SDK-Env" : "Python" , "X-Dymo-SDK-Version" : "0.0.68" , "Authorization" : token })
12+ response .raise_for_status ()
13+ return response .json ()
14+ except requests .RequestException as e : raise APIError (str (e ))
15+
16+ def is_valid_data_raw (token , data ):
17+ if not any ([key in list (data .keys ()) for key in ["url" , "email" , "phone" , "domain" , "creditCard" , "ip" , "wallet" , "userAgent" , "iban" ]]): raise BadRequestError ("You must provide at least one parameter." )
18+ try :
19+ response = requests .post (f"{ get_base_url ()} /v1/private/secure/verify" , json = data , headers = {"User-Agent" : "DymoAPISDK/1.0.0" , "X-Dymo-SDK-Env" : "Python" , "X-Dymo-SDK-Version" : "0.0.68" , "Authorization" : token })
20+ response .raise_for_status ()
21+ return response .json ()
22+ except requests .RequestException as e : raise APIError (str (e ))
23+
24+ def is_valid_email (token : Optional [str ], email : str , rules : Optional [Dict [str , List [str ]]] = None ) -> Dict [str , Any ]:
25+ """
26+ Validates the given email against the configured deny rules.
27+
28+ Args:
29+ token (str | None): Authentication token (required).
30+ email (str): Email to validate.
31+ rules (dict | None): Optional rules dict with 'deny' list. Defaults to
32+ ["FRAUD", "INVALID", "NO_MX_RECORDS", "NO_REPLY_EMAIL"].
33+ ⚠️ "NO_MX_RECORDS", "HIGH_RISK_SCORE", "NO_GRAVATAR" and "NO_REACHABLE" are PREMIUM.
34+
35+ Returns:
36+ bool: True if the email passes all deny rules, False otherwise.
37+
38+ Raises:
39+ APIError: If token is None or the request fails.
40+ """
41+ if token is None : raise APIError ("Invalid private token." )
42+
43+ if rules is None : rules = {"deny" : ["FRAUD" , "INVALID" , "NO_MX_RECORDS" , "NO_REPLY_EMAIL" ]}
44+
45+ plugins = [
46+ "mxRecords" if "NO_MX_RECORDS" in rules ["deny" ] else None ,
47+ "reachable" if "NO_REACHABLE" in rules ["deny" ] else None ,
48+ "riskScore" if "HIGH_RISK_SCORE" in rules ["deny" ] else None ,
49+ "gravatar" if "NO_GRAVATAR" in rules ["deny" ] else None
50+ ]
51+ plugins = [p for p in plugins if p is not None ]
52+
53+ try :
54+ resp = requests .post (
55+ f"{ get_base_url ()} /v1/private/secure/verify" ,
56+ json = {"email" : email , "plugins" : plugins },
57+ headers = {"User-Agent" : "DymoAPISDK/1.0.0" , "X-Dymo-SDK-Env" : "Python" , "X-Dymo-SDK-Version" : "0.0.68" , "Authorization" : token }
58+ )
59+ resp .raise_for_status ()
60+ data = resp .json ().get ("email" , {})
61+
62+ deny = rules .get ("deny" , [])
63+ reasons : List [str ] = []
64+
65+ if "INVALID" in deny and not data .get ("valid" , True ):
66+ return {
67+ "email" : email ,
68+ "allow" : False ,
69+ "reasons" : ["INVALID" ],
70+ "response" : data
71+ }
72+ if "FRAUD" in deny and data .get ("fraud" , False ): reasons .append ("FRAUD" )
73+ if "PROXIED_EMAIL" in deny and data .get ("proxiedEmail" , False ): reasons .append ("PROXIED_EMAIL" )
74+ if "FREE_SUBDOMAIN" in deny and data .get ("freeSubdomain" , False ): reasons .append ("FREE_SUBDOMAIN" )
75+ if "PERSONAL_EMAIL" in deny and not data .get ("corporate" , False ): reasons .append ("PERSONAL_EMAIL" )
76+ if "CORPORATE_EMAIL" in deny and data .get ("corporate" , False ): reasons .append ("CORPORATE_EMAIL" )
77+ if "NO_MX_RECORDS" in deny and len (data .get ("plugins" , {}).get ("mxRecords" , [])) == 0 : reasons .append ("NO_MX_RECORDS" )
78+ if "NO_REPLY_EMAIL" in deny and data .get ("noReply" , False ): reasons .append ("NO_REPLY_EMAIL" )
79+ if "ROLE_ACCOUNT" in deny and data .get ("plugins" , {}).get ("roleAccount" , False ): reasons .append ("ROLE_ACCOUNT" )
80+ reachable = data .get ("plugins" , {}).get ("reachable" )
81+ if "NO_REACHABLE" in deny and isinstance (reachable , dict ) and reachable .get ("reachability" ) == "invalid" : reasons .append ("NO_REACHABLE" )
82+ if "HIGH_RISK_SCORE" in deny and data .get ("plugins" , {}).get ("riskScore" , 0 ) >= 80 : reasons .append ("HIGH_RISK_SCORE" )
83+ if "NO_GRAVATAR" in deny and isinstance (data .get ("plugins" , {}).get ("gravatarUrl" ), str ): reasons .append ("NO_GRAVATAR" )
84+
85+ return {
86+ "email" : email ,
87+ "allow" : len (reasons ) == 0 ,
88+ "reasons" : reasons ,
89+ "response" : data
90+ }
91+
92+ except requests .RequestException as e : raise APIError (f"[Dymo API] { str (e )} " )
93+
94+ def is_valid_ip (token : Optional [str ], ip : str , rules : Optional [Dict [str , List [str ]]] = None ) -> Dict [str , Any ]:
95+ """
96+ Validates the given IP against the configured deny rules.
97+
98+ Args:
99+ token (str | None): Authentication token (required).
100+ email (str): IP to validate.
101+ rules (dict | None): Optional rules dict with 'deny' list. Defaults to
102+ ["FRAUD", "INVALID", "TOR_NETWORK"].
103+ ⚠️ "TOR_NETWORK" and "HIGH_RISK_SCORE" are PREMIUM.
104+
105+ Returns:
106+ bool: True if the IP passes all deny rules, False otherwise.
107+
108+ Raises:
109+ APIError: If token is None or the request fails.
110+ """
111+ if token is None : raise APIError ("Invalid private token." )
112+
113+ if rules is None : rules = {"deny" : ["FRAUD" , "INVALID" , "TOR_NETWORK" ]}
114+
115+ plugins = [
116+ "torNetwork" if "TOR_NETWORK" in rules ["deny" ] else None ,
117+ "riskScore" if "HIGH_RISK_SCORE" in rules ["deny" ] else None
118+ ]
119+ plugins = [p for p in plugins if p is not None ]
120+
121+ try :
122+ resp = requests .post (
123+ f"{ get_base_url ()} /v1/private/secure/verify" ,
124+ json = {"ip" : ip , "plugins" : plugins },
125+ headers = {"User-Agent" : "DymoAPISDK/1.0.0" , "X-Dymo-SDK-Env" : "Python" , "X-Dymo-SDK-Version" : "0.0.68" , "Authorization" : token }
126+ )
127+ resp .raise_for_status ()
128+ data = resp .json ().get ("ip" , {})
129+
130+ deny = rules .get ("deny" , [])
131+ reasons : List [str ] = []
132+
133+ if "INVALID" in deny and not data .get ("valid" , True ):
134+ return {
135+ "ip" : ip ,
136+ "allow" : False ,
137+ "reasons" : ["INVALID" ],
138+ "response" : data
139+ }
140+ if "FRAUD" in deny and data .get ("fraud" , False ): reasons .append ("FRAUD" )
141+ if "TOR_NETWORK" in deny and data .get ("plugins" , {}).get ("torNetwork" , False ): reasons .append ("TOR_NETWORK" )
142+ if "HIGH_RISK_SCORE" in deny and data .get ("plugins" , {}).get ("riskScore" , 0 ) >= 80 : reasons .append ("HIGH_RISK_SCORE" )
143+
144+ # Country block rules.
145+ for rule in rules ["deny" ]:
146+ if rule .startswith ("COUNTRY:" ):
147+ block = rule .split (":" )[1 ] # Extract country code.
148+ if data .get ("countryCode" ) == block : reasons .append (f"COUNTRY:{ block } " )
149+
150+ return {
151+ "ip" : ip ,
152+ "allow" : len (reasons ) == 0 ,
153+ "reasons" : reasons ,
154+ "response" : data
155+ }
156+
157+ except requests .RequestException as e : raise APIError (f"[Dymo API] { str (e )} " )
158+
159+ def is_valid_phone (token : Optional [str ], phone : str , rules : Optional [Dict [str , List [str ]]] = None ) -> Dict [str , Any ]:
160+ """
161+ Validates the given phone against the configured deny rules.
162+
163+ Args:
164+ token (str | None): Authentication token (required).
165+ phone (str): Phone to validate.
166+ rules (dict | None): Optional rules dict with 'deny' list. Defaults to
167+ ["FRAUD", "INVALID"].
168+ ⚠️ "HIGH_RISK_SCORE" is PREMIUM.
169+
170+ Returns:
171+ bool: True if the phone passes all deny rules, False otherwise.
172+
173+ Raises:
174+ APIError: If token is None or the request fails.
175+ """
176+ if token is None : raise APIError ("Invalid private token." )
177+
178+ if rules is None : rules = {"deny" : ["FRAUD" , "INVALID" ]}
179+
180+ plugins = [
181+ "riskScore" if "HIGH_RISK_SCORE" in rules ["deny" ] else None
182+ ]
183+ plugins = [p for p in plugins if p is not None ]
184+
185+ try :
186+ resp = requests .post (
187+ f"{ get_base_url ()} /v1/private/secure/verify" ,
188+ json = {"phone" : phone , "plugins" : plugins },
189+ headers = {"User-Agent" : "DymoAPISDK/1.0.0" , "X-Dymo-SDK-Env" : "Python" , "X-Dymo-SDK-Version" : "0.0.68" , "Authorization" : token }
190+ )
191+ resp .raise_for_status ()
192+ data = resp .json ().get ("phone" , {})
193+
194+ deny = rules .get ("deny" , [])
195+ reasons : List [str ] = []
196+
197+ if "INVALID" in deny and not data .get ("valid" , True ):
198+ return {
199+ "phone" : phone ,
200+ "allow" : False ,
201+ "reasons" : ["INVALID" ],
202+ "response" : data
203+ }
204+ if "FRAUD" in deny and data .get ("fraud" , False ): reasons .append ("FRAUD" )
205+ if "HIGH_RISK_SCORE" in deny and data .get ("plugins" , {}).get ("riskScore" , 0 ) >= 80 : reasons .append ("HIGH_RISK_SCORE" )
206+
207+ # Country block rules.
208+ for rule in rules ["deny" ]:
209+ if rule .startswith ("COUNTRY:" ):
210+ block = rule .split (":" )[1 ] # Extract country code.
211+ if data .get ("countryCode" ) == block : reasons .append (f"COUNTRY:{ block } " )
212+
213+ return {
214+ "phone" : phone ,
215+ "allow" : len (reasons ) == 0 ,
216+ "reasons" : reasons ,
217+ "response" : data
218+ }
219+
220+ except requests .RequestException as e : raise APIError (f"[Dymo API] { str (e )} " )
221+
222+ def send_email (token , data ):
223+ if not data .get ("from" ): raise BadRequestError ("You must provide an email address from which the following will be sent." )
224+ if not data .get ("to" ): raise BadRequestError ("You must provide an email to be sent to." )
225+ if not data .get ("subject" ): raise BadRequestError ("You must provide a subject for the email to be sent." )
226+ if not data .get ("html" ): raise BadRequestError ("You must provide HTML." )
227+ try :
228+ response = requests .post (f"{ get_base_url ()} /v1/private/sender/sendEmail" , json = data , headers = {"User-Agent" : "DymoAPISDK/1.0.0" , "X-Dymo-SDK-Env" : "Python" , "X-Dymo-SDK-Version" : "0.0.68" , "Authorization" : token })
229+ response .raise_for_status ()
230+ return response .json ()
231+ except requests .RequestException as e : raise APIError (str (e ))
232+
233+ def get_random (token , data ):
234+ if not data .get ("min" ) and data .get ("min" ) != 0 : raise BadRequestError ("Both 'min' and 'max' parameters must be defined." )
235+ if not data .get ("max" ) and data .get ("max" ) != 0 : raise BadRequestError ("Both 'min' and 'max' parameters must be defined." )
236+ if data .get ("min" ) >= data .get ("max" ): raise BadRequestError ("'min' must be less than 'max'." )
237+ if data .get ("min" ) < - 1000000000 or data .get ("min" ) > 1000000000 : raise BadRequestError ("'min' must be an integer in the interval [-1000000000, 1000000000]." )
238+ if data .get ("max" ) < - 1000000000 or data .get ("max" ) > 1000000000 : raise BadRequestError ("'max' must be an integer in the interval [-1000000000, 1000000000]." )
239+ try :
240+ response = requests .post (f"{ get_base_url ()} /v1/private/srng" , json = data , headers = {"User-Agent" : "DymoAPISDK/1.0.0" , "X-Dymo-SDK-Env" : "Python" , "X-Dymo-SDK-Version" : "0.0.68" , "Authorization" : token })
241+ response .raise_for_status ()
242+ return response .json ()
243+ except requests .RequestException as e : raise APIError (str (e ))
244+
245+
246+ def extract_with_textly (token : str , data : dict ) -> dict :
247+ if not data .get ("data" ): raise BadRequestError ("No data provided." )
248+ if not data .get ("format" ): raise BadRequestError ("No format provided." )
249+
250+ try :
251+ response = requests .post (
252+ f"{ get_base_url ()} /v1/private/textly/extract" ,
253+ json = data ,
254+ headers = {
255+ "Content-Type" : "application/json" ,
256+ "User-Agent" : "DymoAPISDK/1.0.0" ,
257+ "X-Dymo-SDK-Env" : "Python" ,
258+ "X-Dymo-SDK-Version" : "0.0.68" ,
259+ "Authorization" : token
260+ }
261+ )
262+ response .raise_for_status ()
263+ return response .json ()
264+ except requests .RequestException as e : raise APIError (str (e ))
0 commit comments