langchain-verifly 0.1.0__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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Verifly
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-verifly
3
+ Version: 0.1.0
4
+ Summary: An integration package connecting Verifly (agent-native email verification) and LangChain
5
+ Author-email: Verifly <support@verifly.email>
6
+ License: MIT
7
+ Project-URL: Homepage, https://verifly.email
8
+ Project-URL: Repository, https://github.com/james-sib/langchain-verifly
9
+ Project-URL: Source Code, https://github.com/james-sib/langchain-verifly/tree/master/langchain_verifly
10
+ Keywords: langchain,verifly,email-verification,email-validation,deliverability,agents,tools
11
+ Classifier: Development Status :: 4 - Beta
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
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: langchain-core<0.4,>=0.3
25
+ Requires-Dist: httpx>=0.27
26
+ Provides-Extra: test
27
+ Requires-Dist: pytest>=7.4; extra == "test"
28
+ Requires-Dist: pytest-asyncio>=0.23; extra == "test"
29
+ Dynamic: license-file
30
+
31
+ # langchain-verifly
32
+
33
+ LangChain integration for [Verifly](https://verifly.email) — **agent-native email verification**.
34
+
35
+ `langchain-verifly` gives any LangChain agent a single, well-described tool to
36
+ check whether an email address is real and deliverable *before* it sends a
37
+ message or accepts a signup. It wraps the Verifly verification API and returns a
38
+ clean, structured verdict (deliverable / undeliverable / risky), the reason, a
39
+ confidence score, and an actionable send-or-reject recommendation.
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ pip install -U langchain-verifly
45
+ ```
46
+
47
+ ## Setup
48
+
49
+ Set your Verifly API key in the environment. You can self-onboard for a key
50
+ (with free credits) at [verifly.email](https://verifly.email).
51
+
52
+ ```bash
53
+ export VERIFLY_API_KEY="vf_..."
54
+ ```
55
+
56
+ ## Tool: `VeriflyEmailVerifier`
57
+
58
+ A LangChain `BaseTool` with both sync and async support.
59
+
60
+ ```python
61
+ from langchain_verifly import VeriflyEmailVerifier
62
+
63
+ verifier = VeriflyEmailVerifier() # reads VERIFLY_API_KEY from the environment
64
+
65
+ verifier.invoke({"email": "lead@example.com"})
66
+ ```
67
+
68
+ ```python
69
+ {
70
+ "email": "lead@example.com",
71
+ "result": "deliverable",
72
+ "reason": "Mailbox exists",
73
+ "confidence": 95,
74
+ "is_valid": True,
75
+ "recommendation": "send",
76
+ "did_you_mean": None,
77
+ "details": {
78
+ "syntax_valid": True,
79
+ "domain_exists": True,
80
+ "mx_records": True,
81
+ "smtp_valid": True,
82
+ "is_disposable": False,
83
+ "is_role_account": False,
84
+ "is_catch_all": False,
85
+ "is_free_provider": False,
86
+ "provider": "example.com",
87
+ },
88
+ }
89
+ ```
90
+
91
+ Async works too:
92
+
93
+ ```python
94
+ await verifier.ainvoke({"email": "lead@example.com"})
95
+ ```
96
+
97
+ You can also pass the key explicitly instead of using the environment variable:
98
+
99
+ ```python
100
+ verifier = VeriflyEmailVerifier(api_key="vf_...")
101
+ ```
102
+
103
+ ## Use it in an agent
104
+
105
+ ```python
106
+ from langchain.agents import create_react_agent # or any agent constructor
107
+ from langchain_verifly import VeriflyEmailVerifier
108
+
109
+ tools = [VeriflyEmailVerifier()]
110
+ # ... wire `tools` into your agent / model.bind_tools(tools) as usual
111
+ ```
112
+
113
+ The agent can now verify an address on its own — for example, scrubbing a lead
114
+ list, validating a user-supplied email at signup, or confirming a contact
115
+ before drafting an outreach email.
116
+
117
+ ## Verdict fields
118
+
119
+ | Field | Meaning |
120
+ |-------|---------|
121
+ | `result` | `deliverable`, `undeliverable`, or `risky` |
122
+ | `reason` | Human-readable explanation of the verdict |
123
+ | `confidence` | Confidence score, 0–100 |
124
+ | `is_valid` | Whether the address is considered valid/usable |
125
+ | `recommendation` | `send`, `do_not_send`, or `risky` |
126
+ | `did_you_mean` | A suggested correction for likely typos, if any |
127
+ | `details` | Syntax / domain / MX / SMTP / disposable / role / catch-all / free-provider flags |
128
+
129
+ ## License
130
+
131
+ MIT
@@ -0,0 +1,101 @@
1
+ # langchain-verifly
2
+
3
+ LangChain integration for [Verifly](https://verifly.email) — **agent-native email verification**.
4
+
5
+ `langchain-verifly` gives any LangChain agent a single, well-described tool to
6
+ check whether an email address is real and deliverable *before* it sends a
7
+ message or accepts a signup. It wraps the Verifly verification API and returns a
8
+ clean, structured verdict (deliverable / undeliverable / risky), the reason, a
9
+ confidence score, and an actionable send-or-reject recommendation.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install -U langchain-verifly
15
+ ```
16
+
17
+ ## Setup
18
+
19
+ Set your Verifly API key in the environment. You can self-onboard for a key
20
+ (with free credits) at [verifly.email](https://verifly.email).
21
+
22
+ ```bash
23
+ export VERIFLY_API_KEY="vf_..."
24
+ ```
25
+
26
+ ## Tool: `VeriflyEmailVerifier`
27
+
28
+ A LangChain `BaseTool` with both sync and async support.
29
+
30
+ ```python
31
+ from langchain_verifly import VeriflyEmailVerifier
32
+
33
+ verifier = VeriflyEmailVerifier() # reads VERIFLY_API_KEY from the environment
34
+
35
+ verifier.invoke({"email": "lead@example.com"})
36
+ ```
37
+
38
+ ```python
39
+ {
40
+ "email": "lead@example.com",
41
+ "result": "deliverable",
42
+ "reason": "Mailbox exists",
43
+ "confidence": 95,
44
+ "is_valid": True,
45
+ "recommendation": "send",
46
+ "did_you_mean": None,
47
+ "details": {
48
+ "syntax_valid": True,
49
+ "domain_exists": True,
50
+ "mx_records": True,
51
+ "smtp_valid": True,
52
+ "is_disposable": False,
53
+ "is_role_account": False,
54
+ "is_catch_all": False,
55
+ "is_free_provider": False,
56
+ "provider": "example.com",
57
+ },
58
+ }
59
+ ```
60
+
61
+ Async works too:
62
+
63
+ ```python
64
+ await verifier.ainvoke({"email": "lead@example.com"})
65
+ ```
66
+
67
+ You can also pass the key explicitly instead of using the environment variable:
68
+
69
+ ```python
70
+ verifier = VeriflyEmailVerifier(api_key="vf_...")
71
+ ```
72
+
73
+ ## Use it in an agent
74
+
75
+ ```python
76
+ from langchain.agents import create_react_agent # or any agent constructor
77
+ from langchain_verifly import VeriflyEmailVerifier
78
+
79
+ tools = [VeriflyEmailVerifier()]
80
+ # ... wire `tools` into your agent / model.bind_tools(tools) as usual
81
+ ```
82
+
83
+ The agent can now verify an address on its own — for example, scrubbing a lead
84
+ list, validating a user-supplied email at signup, or confirming a contact
85
+ before drafting an outreach email.
86
+
87
+ ## Verdict fields
88
+
89
+ | Field | Meaning |
90
+ |-------|---------|
91
+ | `result` | `deliverable`, `undeliverable`, or `risky` |
92
+ | `reason` | Human-readable explanation of the verdict |
93
+ | `confidence` | Confidence score, 0–100 |
94
+ | `is_valid` | Whether the address is considered valid/usable |
95
+ | `recommendation` | `send`, `do_not_send`, or `risky` |
96
+ | `did_you_mean` | A suggested correction for likely typos, if any |
97
+ | `details` | Syntax / domain / MX / SMTP / disposable / role / catch-all / free-provider flags |
98
+
99
+ ## License
100
+
101
+ MIT
@@ -0,0 +1,18 @@
1
+ """LangChain integration for Verifly — agent-native email verification.
2
+
3
+ Exposes :class:`VeriflyEmailVerifier`, a LangChain ``BaseTool`` that verifies
4
+ the deliverability of an email address through the Verifly API
5
+ (https://verifly.email) and returns a structured verdict (result, reason,
6
+ confidence, and deliverability flags).
7
+ """
8
+
9
+ from importlib import metadata
10
+
11
+ from langchain_verifly.tool import VeriflyEmailVerifier, VeriflyToolInput
12
+
13
+ try:
14
+ __version__ = metadata.version(__package__)
15
+ except metadata.PackageNotFoundError: # pragma: no cover - local source tree
16
+ __version__ = ""
17
+
18
+ __all__ = ["VeriflyEmailVerifier", "VeriflyToolInput", "__version__"]
File without changes
@@ -0,0 +1,156 @@
1
+ """Verifly email-verification tool for LangChain."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from typing import Any, Dict, Optional
7
+
8
+ import httpx
9
+ from langchain_core.callbacks import (
10
+ AsyncCallbackManagerForToolRun,
11
+ CallbackManagerForToolRun,
12
+ )
13
+ from langchain_core.tools import BaseTool
14
+ from pydantic import BaseModel, Field
15
+
16
+ DEFAULT_BASE_URL = "https://verifly.email"
17
+ _VERIFY_PATH = "/api/v1/verify"
18
+ _DEFAULT_TIMEOUT = 30.0
19
+
20
+
21
+ class VeriflyToolInput(BaseModel):
22
+ """Input schema for :class:`VeriflyEmailVerifier`."""
23
+
24
+ email: str = Field(
25
+ ...,
26
+ description="The email address to verify, e.g. 'lead@example.com'.",
27
+ )
28
+
29
+
30
+ class VeriflyEmailVerifier(BaseTool):
31
+ """Verify the deliverability of an email address with Verifly.
32
+
33
+ Agent-native email verification: given a single email address, this tool
34
+ calls the Verifly API (``GET /api/v1/verify``) and returns a structured
35
+ verdict describing whether the address is deliverable, undeliverable, or
36
+ risky, along with the reason, a confidence score, and the actionable
37
+ send/reject recommendation. Use it to validate a lead or signup before
38
+ sending mail.
39
+
40
+ Setup:
41
+ Install the package and set your Verifly API key in the environment.
42
+
43
+ .. code-block:: bash
44
+
45
+ pip install -U langchain-verifly
46
+ export VERIFLY_API_KEY="vf_..."
47
+
48
+ A key (with free credits) can be obtained at https://verifly.email.
49
+
50
+ Instantiate:
51
+ .. code-block:: python
52
+
53
+ from langchain_verifly import VeriflyEmailVerifier
54
+
55
+ verifier = VeriflyEmailVerifier()
56
+ # or pass the key explicitly:
57
+ verifier = VeriflyEmailVerifier(api_key="vf_...")
58
+
59
+ Invoke directly:
60
+ .. code-block:: python
61
+
62
+ verifier.invoke({"email": "lead@example.com"})
63
+
64
+ The tool returns a dict such as::
65
+
66
+ {
67
+ "email": "lead@example.com",
68
+ "result": "deliverable",
69
+ "reason": "Mailbox exists",
70
+ "confidence": 95,
71
+ "is_valid": True,
72
+ "recommendation": "send",
73
+ "details": {...},
74
+ }
75
+ """
76
+
77
+ name: str = "verifly_email_verifier"
78
+ description: str = (
79
+ "Verify whether a single email address is deliverable using Verifly. "
80
+ "Input is one email address. Returns the verdict (deliverable, "
81
+ "undeliverable, or risky), the reason, a confidence score (0-100), "
82
+ "and a send/reject recommendation. Use before emailing a lead or "
83
+ "accepting a signup to avoid bounces and bad addresses."
84
+ )
85
+ args_schema: type[BaseModel] = VeriflyToolInput
86
+
87
+ api_key: Optional[str] = Field(
88
+ default=None,
89
+ description=(
90
+ "Verifly API key. Falls back to the VERIFLY_API_KEY environment "
91
+ "variable when not set."
92
+ ),
93
+ )
94
+ base_url: str = Field(
95
+ default=DEFAULT_BASE_URL,
96
+ description="Base URL of the Verifly API.",
97
+ )
98
+ timeout: float = Field(
99
+ default=_DEFAULT_TIMEOUT,
100
+ description="HTTP request timeout in seconds.",
101
+ )
102
+
103
+ def _resolve_key(self) -> str:
104
+ key = self.api_key or os.environ.get("VERIFLY_API_KEY")
105
+ if not key:
106
+ raise ValueError(
107
+ "A Verifly API key is required. Pass api_key=... or set the "
108
+ "VERIFLY_API_KEY environment variable. Get a free key at "
109
+ "https://verifly.email."
110
+ )
111
+ return key
112
+
113
+ @staticmethod
114
+ def _shape(payload: Dict[str, Any]) -> Dict[str, Any]:
115
+ """Reduce the raw API response to the relevant verdict fields."""
116
+ return {
117
+ "email": payload.get("email"),
118
+ "result": payload.get("result"),
119
+ "reason": payload.get("reason"),
120
+ "confidence": payload.get("confidence"),
121
+ "is_valid": payload.get("is_valid"),
122
+ "recommendation": payload.get("recommendation"),
123
+ "did_you_mean": payload.get("did_you_mean"),
124
+ "details": payload.get("details"),
125
+ }
126
+
127
+ def _request_args(self, email: str) -> Dict[str, Any]:
128
+ return {
129
+ "url": f"{self.base_url.rstrip('/')}{_VERIFY_PATH}",
130
+ "params": {"email": email},
131
+ "headers": {
132
+ "Authorization": f"Bearer {self._resolve_key()}",
133
+ "Accept": "application/json",
134
+ },
135
+ "timeout": self.timeout,
136
+ }
137
+
138
+ def _run(
139
+ self,
140
+ email: str,
141
+ run_manager: Optional[CallbackManagerForToolRun] = None,
142
+ ) -> Dict[str, Any]:
143
+ with httpx.Client() as client:
144
+ response = client.get(**self._request_args(email))
145
+ response.raise_for_status()
146
+ return self._shape(response.json())
147
+
148
+ async def _arun(
149
+ self,
150
+ email: str,
151
+ run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
152
+ ) -> Dict[str, Any]:
153
+ async with httpx.AsyncClient() as client:
154
+ response = await client.get(**self._request_args(email))
155
+ response.raise_for_status()
156
+ return self._shape(response.json())
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-verifly
3
+ Version: 0.1.0
4
+ Summary: An integration package connecting Verifly (agent-native email verification) and LangChain
5
+ Author-email: Verifly <support@verifly.email>
6
+ License: MIT
7
+ Project-URL: Homepage, https://verifly.email
8
+ Project-URL: Repository, https://github.com/james-sib/langchain-verifly
9
+ Project-URL: Source Code, https://github.com/james-sib/langchain-verifly/tree/master/langchain_verifly
10
+ Keywords: langchain,verifly,email-verification,email-validation,deliverability,agents,tools
11
+ Classifier: Development Status :: 4 - Beta
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
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: langchain-core<0.4,>=0.3
25
+ Requires-Dist: httpx>=0.27
26
+ Provides-Extra: test
27
+ Requires-Dist: pytest>=7.4; extra == "test"
28
+ Requires-Dist: pytest-asyncio>=0.23; extra == "test"
29
+ Dynamic: license-file
30
+
31
+ # langchain-verifly
32
+
33
+ LangChain integration for [Verifly](https://verifly.email) — **agent-native email verification**.
34
+
35
+ `langchain-verifly` gives any LangChain agent a single, well-described tool to
36
+ check whether an email address is real and deliverable *before* it sends a
37
+ message or accepts a signup. It wraps the Verifly verification API and returns a
38
+ clean, structured verdict (deliverable / undeliverable / risky), the reason, a
39
+ confidence score, and an actionable send-or-reject recommendation.
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ pip install -U langchain-verifly
45
+ ```
46
+
47
+ ## Setup
48
+
49
+ Set your Verifly API key in the environment. You can self-onboard for a key
50
+ (with free credits) at [verifly.email](https://verifly.email).
51
+
52
+ ```bash
53
+ export VERIFLY_API_KEY="vf_..."
54
+ ```
55
+
56
+ ## Tool: `VeriflyEmailVerifier`
57
+
58
+ A LangChain `BaseTool` with both sync and async support.
59
+
60
+ ```python
61
+ from langchain_verifly import VeriflyEmailVerifier
62
+
63
+ verifier = VeriflyEmailVerifier() # reads VERIFLY_API_KEY from the environment
64
+
65
+ verifier.invoke({"email": "lead@example.com"})
66
+ ```
67
+
68
+ ```python
69
+ {
70
+ "email": "lead@example.com",
71
+ "result": "deliverable",
72
+ "reason": "Mailbox exists",
73
+ "confidence": 95,
74
+ "is_valid": True,
75
+ "recommendation": "send",
76
+ "did_you_mean": None,
77
+ "details": {
78
+ "syntax_valid": True,
79
+ "domain_exists": True,
80
+ "mx_records": True,
81
+ "smtp_valid": True,
82
+ "is_disposable": False,
83
+ "is_role_account": False,
84
+ "is_catch_all": False,
85
+ "is_free_provider": False,
86
+ "provider": "example.com",
87
+ },
88
+ }
89
+ ```
90
+
91
+ Async works too:
92
+
93
+ ```python
94
+ await verifier.ainvoke({"email": "lead@example.com"})
95
+ ```
96
+
97
+ You can also pass the key explicitly instead of using the environment variable:
98
+
99
+ ```python
100
+ verifier = VeriflyEmailVerifier(api_key="vf_...")
101
+ ```
102
+
103
+ ## Use it in an agent
104
+
105
+ ```python
106
+ from langchain.agents import create_react_agent # or any agent constructor
107
+ from langchain_verifly import VeriflyEmailVerifier
108
+
109
+ tools = [VeriflyEmailVerifier()]
110
+ # ... wire `tools` into your agent / model.bind_tools(tools) as usual
111
+ ```
112
+
113
+ The agent can now verify an address on its own — for example, scrubbing a lead
114
+ list, validating a user-supplied email at signup, or confirming a contact
115
+ before drafting an outreach email.
116
+
117
+ ## Verdict fields
118
+
119
+ | Field | Meaning |
120
+ |-------|---------|
121
+ | `result` | `deliverable`, `undeliverable`, or `risky` |
122
+ | `reason` | Human-readable explanation of the verdict |
123
+ | `confidence` | Confidence score, 0–100 |
124
+ | `is_valid` | Whether the address is considered valid/usable |
125
+ | `recommendation` | `send`, `do_not_send`, or `risky` |
126
+ | `did_you_mean` | A suggested correction for likely typos, if any |
127
+ | `details` | Syntax / domain / MX / SMTP / disposable / role / catch-all / free-provider flags |
128
+
129
+ ## License
130
+
131
+ MIT
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ langchain_verifly/__init__.py
5
+ langchain_verifly/py.typed
6
+ langchain_verifly/tool.py
7
+ langchain_verifly.egg-info/PKG-INFO
8
+ langchain_verifly.egg-info/SOURCES.txt
9
+ langchain_verifly.egg-info/dependency_links.txt
10
+ langchain_verifly.egg-info/requires.txt
11
+ langchain_verifly.egg-info/top_level.txt
12
+ tests/test_tool.py
@@ -0,0 +1,6 @@
1
+ langchain-core<0.4,>=0.3
2
+ httpx>=0.27
3
+
4
+ [test]
5
+ pytest>=7.4
6
+ pytest-asyncio>=0.23
@@ -0,0 +1 @@
1
+ langchain_verifly
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "langchain-verifly"
7
+ version = "0.1.0"
8
+ description = "An integration package connecting Verifly (agent-native email verification) and LangChain"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Verifly", email = "support@verifly.email" }]
13
+ keywords = [
14
+ "langchain",
15
+ "verifly",
16
+ "email-verification",
17
+ "email-validation",
18
+ "deliverability",
19
+ "agents",
20
+ "tools",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Intended Audience :: Developers",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.9",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Topic :: Communications :: Email",
32
+ "Topic :: Software Development :: Libraries :: Python Modules",
33
+ ]
34
+ dependencies = [
35
+ "langchain-core>=0.3,<0.4",
36
+ "httpx>=0.27",
37
+ ]
38
+
39
+ [project.urls]
40
+ Homepage = "https://verifly.email"
41
+ Repository = "https://github.com/james-sib/langchain-verifly"
42
+ "Source Code" = "https://github.com/james-sib/langchain-verifly/tree/master/langchain_verifly"
43
+
44
+ [project.optional-dependencies]
45
+ test = [
46
+ "pytest>=7.4",
47
+ "pytest-asyncio>=0.23",
48
+ ]
49
+
50
+ [tool.setuptools]
51
+ packages = ["langchain_verifly"]
52
+
53
+ [tool.setuptools.package-data]
54
+ langchain_verifly = ["py.typed"]
55
+
56
+ [tool.pytest.ini_options]
57
+ asyncio_mode = "auto"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,114 @@
1
+ """Unit tests for VeriflyEmailVerifier (no network calls)."""
2
+
3
+ import httpx
4
+ import pytest
5
+
6
+ from langchain_core.tools import BaseTool
7
+
8
+ from langchain_verifly import VeriflyEmailVerifier, VeriflyToolInput
9
+
10
+ _SAMPLE_RESPONSE = {
11
+ "success": True,
12
+ "email": "lead@example.com",
13
+ "is_valid": True,
14
+ "result": "deliverable",
15
+ "reason": "Mailbox exists",
16
+ "confidence": 95,
17
+ "recommendation": "send",
18
+ "did_you_mean": None,
19
+ "details": {
20
+ "syntax_valid": True,
21
+ "domain_exists": True,
22
+ "mx_records": True,
23
+ "smtp_valid": True,
24
+ "is_disposable": False,
25
+ "is_role_account": False,
26
+ "is_catch_all": False,
27
+ "is_free_provider": False,
28
+ "provider": "example.com",
29
+ },
30
+ "credits": {"used": 1, "remaining": 99},
31
+ "request_id": "abc-123",
32
+ }
33
+
34
+
35
+ def _mock_transport() -> httpx.MockTransport:
36
+ def handler(request: httpx.Request) -> httpx.Response:
37
+ assert request.url.path == "/api/v1/verify"
38
+ assert request.url.params.get("email") == "lead@example.com"
39
+ assert request.headers["Authorization"] == "Bearer vf_test"
40
+ return httpx.Response(200, json=_SAMPLE_RESPONSE)
41
+
42
+ return httpx.MockTransport(handler)
43
+
44
+
45
+ def test_is_a_langchain_tool():
46
+ tool = VeriflyEmailVerifier(api_key="vf_test")
47
+ assert isinstance(tool, BaseTool)
48
+ assert tool.name == "verifly_email_verifier"
49
+ assert tool.args_schema is VeriflyToolInput
50
+
51
+
52
+ def test_input_schema_requires_email():
53
+ with pytest.raises(Exception):
54
+ VeriflyToolInput() # type: ignore[call-arg]
55
+ assert VeriflyToolInput(email="a@b.com").email == "a@b.com"
56
+
57
+
58
+ def test_missing_key_raises(monkeypatch):
59
+ monkeypatch.delenv("VERIFLY_API_KEY", raising=False)
60
+ tool = VeriflyEmailVerifier()
61
+ with pytest.raises(ValueError, match="VERIFLY_API_KEY"):
62
+ tool.invoke({"email": "lead@example.com"})
63
+
64
+
65
+ def test_run_shapes_verdict(monkeypatch):
66
+ tool = VeriflyEmailVerifier(api_key="vf_test")
67
+ real_client = httpx.Client
68
+
69
+ def patched_client(*args, **kwargs):
70
+ kwargs["transport"] = _mock_transport()
71
+ return real_client(*args, **kwargs)
72
+
73
+ monkeypatch.setattr(httpx, "Client", patched_client)
74
+
75
+ result = tool.invoke({"email": "lead@example.com"})
76
+ assert result["result"] == "deliverable"
77
+ assert result["reason"] == "Mailbox exists"
78
+ assert result["confidence"] == 95
79
+ assert result["is_valid"] is True
80
+ assert result["recommendation"] == "send"
81
+ assert result["details"]["provider"] == "example.com"
82
+ # raw-only fields should be stripped out
83
+ assert "credits" not in result
84
+ assert "request_id" not in result
85
+
86
+
87
+ def test_key_from_env(monkeypatch):
88
+ monkeypatch.setenv("VERIFLY_API_KEY", "vf_test")
89
+ tool = VeriflyEmailVerifier()
90
+ real_client = httpx.Client
91
+
92
+ def patched_client(*args, **kwargs):
93
+ kwargs["transport"] = _mock_transport()
94
+ return real_client(*args, **kwargs)
95
+
96
+ monkeypatch.setattr(httpx, "Client", patched_client)
97
+ result = tool.invoke({"email": "lead@example.com"})
98
+ assert result["email"] == "lead@example.com"
99
+
100
+
101
+ @pytest.mark.asyncio
102
+ async def test_arun_shapes_verdict(monkeypatch):
103
+ tool = VeriflyEmailVerifier(api_key="vf_test")
104
+ real_async_client = httpx.AsyncClient
105
+
106
+ def patched_async_client(*args, **kwargs):
107
+ kwargs["transport"] = _mock_transport()
108
+ return real_async_client(*args, **kwargs)
109
+
110
+ monkeypatch.setattr(httpx, "AsyncClient", patched_async_client)
111
+
112
+ result = await tool.ainvoke({"email": "lead@example.com"})
113
+ assert result["result"] == "deliverable"
114
+ assert result["confidence"] == 95