openleads 2.0.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.
- openleads-2.0.0/LICENSE +133 -0
- openleads-2.0.0/PKG-INFO +256 -0
- openleads-2.0.0/README.md +217 -0
- openleads-2.0.0/automation.py +14 -0
- openleads-2.0.0/lead_engine.py +48 -0
- openleads-2.0.0/openleads/__init__.py +22 -0
- openleads-2.0.0/openleads/__main__.py +5 -0
- openleads-2.0.0/openleads/_http.py +54 -0
- openleads-2.0.0/openleads/cache/__init__.py +4 -0
- openleads-2.0.0/openleads/cache/store.py +85 -0
- openleads-2.0.0/openleads/campaign.py +283 -0
- openleads-2.0.0/openleads/chat.py +291 -0
- openleads-2.0.0/openleads/cli.py +211 -0
- openleads-2.0.0/openleads/config.py +59 -0
- openleads-2.0.0/openleads/emails/__init__.py +15 -0
- openleads-2.0.0/openleads/emails/mx.py +84 -0
- openleads-2.0.0/openleads/emails/permute.py +87 -0
- openleads-2.0.0/openleads/emails/resolve.py +156 -0
- openleads-2.0.0/openleads/emails/smtp_verify.py +68 -0
- openleads-2.0.0/openleads/engine.py +83 -0
- openleads-2.0.0/openleads/intent.py +208 -0
- openleads-2.0.0/openleads/models.py +160 -0
- openleads-2.0.0/openleads/sources/__init__.py +88 -0
- openleads-2.0.0/openleads/sources/base.py +42 -0
- openleads-2.0.0/openleads/sources/github.py +92 -0
- openleads-2.0.0/openleads/sources/npi.py +100 -0
- openleads-2.0.0/openleads/sources/openalex.py +92 -0
- openleads-2.0.0/openleads/sources/producthunt.py +90 -0
- openleads-2.0.0/openleads/sources/yc.py +160 -0
- openleads-2.0.0/openleads/ui.py +43 -0
- openleads-2.0.0/openleads/writers.py +67 -0
- openleads-2.0.0/openleads.egg-info/PKG-INFO +256 -0
- openleads-2.0.0/openleads.egg-info/SOURCES.txt +46 -0
- openleads-2.0.0/openleads.egg-info/dependency_links.txt +1 -0
- openleads-2.0.0/openleads.egg-info/entry_points.txt +2 -0
- openleads-2.0.0/openleads.egg-info/requires.txt +20 -0
- openleads-2.0.0/openleads.egg-info/top_level.txt +3 -0
- openleads-2.0.0/pyproject.toml +57 -0
- openleads-2.0.0/setup.cfg +4 -0
- openleads-2.0.0/tests/test_cache.py +38 -0
- openleads-2.0.0/tests/test_campaign.py +45 -0
- openleads-2.0.0/tests/test_chat.py +67 -0
- openleads-2.0.0/tests/test_emails.py +125 -0
- openleads-2.0.0/tests/test_engine.py +111 -0
- openleads-2.0.0/tests/test_intent.py +56 -0
- openleads-2.0.0/tests/test_new_sources.py +112 -0
- openleads-2.0.0/tests/test_openleads.py +89 -0
- openleads-2.0.0/tests/test_sources.py +87 -0
openleads-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# PolyForm Noncommercial License 1.0.0
|
|
2
|
+
|
|
3
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
4
|
+
|
|
5
|
+
## Acceptance
|
|
6
|
+
|
|
7
|
+
In order to get any license under these terms, you must agree
|
|
8
|
+
to them as both strict obligations and conditions to all your
|
|
9
|
+
licenses.
|
|
10
|
+
|
|
11
|
+
## Copyright License
|
|
12
|
+
|
|
13
|
+
The licensor grants you a copyright license for the software to
|
|
14
|
+
do everything you might do with the software that would
|
|
15
|
+
otherwise infringe the licensor's copyright in it for any
|
|
16
|
+
permitted purpose. However, you may only distribute the software
|
|
17
|
+
according to [Distribution License](#distribution-license) and
|
|
18
|
+
make changes or new works based on the software according to
|
|
19
|
+
[Changes and New Works License](#changes-and-new-works-license).
|
|
20
|
+
|
|
21
|
+
## Distribution License
|
|
22
|
+
|
|
23
|
+
The licensor grants you an additional copyright license to
|
|
24
|
+
distribute copies of the software. Your license to distribute
|
|
25
|
+
covers distributing the software with changes and new works
|
|
26
|
+
permitted by [Changes and New Works
|
|
27
|
+
License](#changes-and-new-works-license).
|
|
28
|
+
|
|
29
|
+
## Notices
|
|
30
|
+
|
|
31
|
+
You must ensure that anyone who gets a copy of any part of the
|
|
32
|
+
software from you also gets a copy of these terms or the URL for
|
|
33
|
+
them above, as well as copies of any plain-text lines beginning
|
|
34
|
+
with `Required Notice:` that the licensor provided with the
|
|
35
|
+
software. For example:
|
|
36
|
+
|
|
37
|
+
> Required Notice: Copyright 2026 Samyar Shafiee / NGN Hacks (https://ngnhacks.ca)
|
|
38
|
+
|
|
39
|
+
## Changes and New Works License
|
|
40
|
+
|
|
41
|
+
The licensor grants you an additional copyright license to make
|
|
42
|
+
changes and new works based on the software for any permitted
|
|
43
|
+
purpose.
|
|
44
|
+
|
|
45
|
+
## Patent License
|
|
46
|
+
|
|
47
|
+
The licensor grants you a patent license for the software that
|
|
48
|
+
covers patent claims the licensor can license, or becomes able to
|
|
49
|
+
license, that you would infringe by using the software.
|
|
50
|
+
|
|
51
|
+
## Noncommercial Purposes
|
|
52
|
+
|
|
53
|
+
Any noncommercial purpose is a permitted purpose.
|
|
54
|
+
|
|
55
|
+
## Personal Uses
|
|
56
|
+
|
|
57
|
+
Personal use for research, experiment, and testing for the
|
|
58
|
+
benefit of public knowledge, personal study, private
|
|
59
|
+
entertainment, hobby projects, amateur pursuits, or religious
|
|
60
|
+
observance, without any anticipated commercial application, is
|
|
61
|
+
use for a permitted purpose.
|
|
62
|
+
|
|
63
|
+
## Noncommercial Organizations
|
|
64
|
+
|
|
65
|
+
Use by any charitable organization, educational institution,
|
|
66
|
+
public research organization, public safety or health
|
|
67
|
+
organization, environmental protection organization, or
|
|
68
|
+
government institution is use for a permitted purpose regardless
|
|
69
|
+
of the source of funding or obligations resulting from the
|
|
70
|
+
funding.
|
|
71
|
+
|
|
72
|
+
## Fair Use
|
|
73
|
+
|
|
74
|
+
You may have "fair use" rights for the software under the law.
|
|
75
|
+
These terms do not limit them.
|
|
76
|
+
|
|
77
|
+
## No Other Rights
|
|
78
|
+
|
|
79
|
+
These terms do not allow you to sublicense or transfer any of
|
|
80
|
+
your licenses to anyone else, or prevent the licensor from
|
|
81
|
+
granting licenses to anyone else. These terms do not imply any
|
|
82
|
+
other licenses.
|
|
83
|
+
|
|
84
|
+
## Patent Defense
|
|
85
|
+
|
|
86
|
+
If you make any written claim that the software infringes or
|
|
87
|
+
contributes to infringement of any patent, your patent license
|
|
88
|
+
for the software granted under these terms ends immediately. If
|
|
89
|
+
your company makes such a claim, your patent license ends
|
|
90
|
+
immediately for work on behalf of your company.
|
|
91
|
+
|
|
92
|
+
## Violations
|
|
93
|
+
|
|
94
|
+
The first time you are notified in writing that you have violated
|
|
95
|
+
any of these terms, or done anything with the software not
|
|
96
|
+
covered by your licenses, your licenses can nonetheless continue
|
|
97
|
+
if you come into full compliance with these terms, and take
|
|
98
|
+
practical steps to correct past violations, within 32 days of
|
|
99
|
+
receiving notice. Otherwise, all your licenses end immediately.
|
|
100
|
+
|
|
101
|
+
## No Liability
|
|
102
|
+
|
|
103
|
+
***As far as the law allows, the software comes as is, without
|
|
104
|
+
any warranty or condition, and the licensor will not be liable to
|
|
105
|
+
you for any damages arising out of these terms or the use or
|
|
106
|
+
nature of the software, under any kind of legal claim.***
|
|
107
|
+
|
|
108
|
+
## Definitions
|
|
109
|
+
|
|
110
|
+
The **licensor** is the individual or entity offering these
|
|
111
|
+
terms, and the **software** is the software the licensor makes
|
|
112
|
+
available under these terms.
|
|
113
|
+
|
|
114
|
+
**You** refers to the individual or entity agreeing to these
|
|
115
|
+
terms.
|
|
116
|
+
|
|
117
|
+
**Your company** is any legal entity, sole proprietorship, or
|
|
118
|
+
other kind of organization that you work for, plus all
|
|
119
|
+
organizations that have control over, are under the control of,
|
|
120
|
+
or are under common control with that organization. **Control**
|
|
121
|
+
means ownership of substantially all the assets of an entity, or
|
|
122
|
+
the power to direct its management and policies by vote,
|
|
123
|
+
contract, or otherwise. Control can be direct or indirect.
|
|
124
|
+
|
|
125
|
+
**Your licenses** are all the licenses granted to you for the
|
|
126
|
+
software under these terms.
|
|
127
|
+
|
|
128
|
+
**Use** means anything you do with the software requiring one of
|
|
129
|
+
your licenses.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
Required Notice: Copyright 2026 Samyar Shafiee / NGN Hacks (https://ngnhacks.ca)
|
openleads-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openleads
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Free, open-source Apollo alternative: a universal entityβverified-email engine with pluggable free data sources (founders, developers, doctors, researchers) and an interactive chat CLI.
|
|
5
|
+
Author: Samyar Shafiee
|
|
6
|
+
License: PolyForm-Noncommercial-1.0.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/Samyrrrrrr990/openleads
|
|
8
|
+
Project-URL: Repository, https://github.com/Samyrrrrrr990/openleads
|
|
9
|
+
Project-URL: Issues, https://github.com/Samyrrrrrr990/openleads/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/Samyrrrrrr990/openleads/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: lead-generation,email-finder,apollo-alternative,sales,cli,prospecting,cold-email,smtp-verification,yc,founders,osint,doctors,researchers,developers,data-enrichment
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Office/Business
|
|
17
|
+
Classifier: Topic :: Communications :: Email
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Provides-Extra: chat
|
|
23
|
+
Requires-Dist: rich>=13.0; extra == "chat"
|
|
24
|
+
Requires-Dist: prompt_toolkit>=3.0; extra == "chat"
|
|
25
|
+
Provides-Extra: campaign
|
|
26
|
+
Requires-Dist: requests>=2.31.0; extra == "campaign"
|
|
27
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == "campaign"
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
31
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
32
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
33
|
+
Provides-Extra: all
|
|
34
|
+
Requires-Dist: rich>=13.0; extra == "all"
|
|
35
|
+
Requires-Dist: prompt_toolkit>=3.0; extra == "all"
|
|
36
|
+
Requires-Dist: requests>=2.31.0; extra == "all"
|
|
37
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == "all"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
<div align="center">
|
|
41
|
+
|
|
42
|
+
# π§² OpenLeads
|
|
43
|
+
|
|
44
|
+
### The free, open-source Apollo alternative β for *everyone*.
|
|
45
|
+
|
|
46
|
+
**Find founders, developers, doctors, researchers β anyone β and verify their emails, using only free, public data. No paid APIs. No API keys. No seat fees. Now with an interactive chat CLI.**
|
|
47
|
+
|
|
48
|
+
[](./LICENSE)
|
|
49
|
+
[](https://www.python.org/)
|
|
50
|
+
[](#-how-it-works)
|
|
51
|
+
[](https://pypi.org/project/openleads/)
|
|
52
|
+
[](https://github.com/Samyrrrrrr990/openleads/actions/workflows/ci.yml)
|
|
53
|
+
[](./CONTRIBUTING.md)
|
|
54
|
+
[](https://github.com/Samyrrrrrr990/openleads/stargazers)
|
|
55
|
+
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
Apollo, Hunter, RocketReach, and ZoomInfo all sell the same two things: **a contact database** and **email verification**. Their moat is the database. **OpenLeads inverts it.**
|
|
61
|
+
|
|
62
|
+
> OpenLeads is a **universal `entity β verified email` engine**, fed by a registry of **pluggable, free, keyless public data sources.**
|
|
63
|
+
|
|
64
|
+
The email engine doesn't care *who* you're looking for. So coverage grows by adding small **source plugins**, not by paying for a database. v2.0 ships sources for **startup founders, open-source developers, U.S. doctors, and academic researchers** β and you can add any vertical (lawyers, podcasters, real-estate agentsβ¦) by dropping a single `.py` file in a folder.
|
|
65
|
+
|
|
66
|
+
All for **$0**, in code you can read in one sitting.
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
openleads> find 25 AI founders, verified emails only
|
|
70
|
+
plan source=yc count=25 filter=AI verified-only parser=rule
|
|
71
|
+
βββββ³βββββ³ββββββββββββββββββ³βββββββββββββββ³ββββββββββ³ββββββββββ³ββββββββ
|
|
72
|
+
β # β β β Email β Name β Title β Org β Score β
|
|
73
|
+
β‘ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ©
|
|
74
|
+
β 1 β OK β ada@acme.ai β Ada Lovelace β Founder β Acme β 96 β
|
|
75
|
+
β 2 β ~CAβ grace@cobol.dev β Grace Hopper β CEO β COBOLwx β 71 β
|
|
76
|
+
βββββ΄βββββ΄ββββββββββββββββββ΄βββββββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββ
|
|
77
|
+
25 leads Β· 18 verified Β· /export FILE to save
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
> `OK` = SMTP-verified Β· `~CA` = catch-all best-guess Β· `~PG` = MX-only pattern guess Β· **Score** = 0β100 confidence
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## β¨ Why OpenLeads
|
|
85
|
+
|
|
86
|
+
| | OpenLeads | Apollo / Hunter (free tier) |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| **Cost** | $0, forever | Credit-limited, then paid |
|
|
89
|
+
| **API key required** | β None | β
Required |
|
|
90
|
+
| **Who you can find** | Founders, devs, doctors, researchers, **+ any vertical you plug in** | Their database only |
|
|
91
|
+
| **Email verification** | β
Live SMTP `RCPT` + 0β100 score | Paid feature |
|
|
92
|
+
| **Catch-all detection** | β
Yes | Sometimes |
|
|
93
|
+
| **Interactive chat CLI** | β
Yes (`openleads chat`) | β |
|
|
94
|
+
| **You own the code** | β
Readable, hackable, extensible | β Black box |
|
|
95
|
+
| **Output** | β
CSV / JSON / NDJSON | Often gated |
|
|
96
|
+
| **Core dependencies** | **Zero** (stdlib only) | β |
|
|
97
|
+
|
|
98
|
+
## π Install
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Python (recommended) β zero-dependency engine + plain CLI
|
|
102
|
+
pip install openleads
|
|
103
|
+
|
|
104
|
+
# β¦with the pretty interactive chat TUI
|
|
105
|
+
pip install "openleads[chat]"
|
|
106
|
+
|
|
107
|
+
# β¦with the cold-email companion too
|
|
108
|
+
pip install "openleads[all]"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Prefer Node? A thin wrapper lets you run it with **npx** (it installs the Python package on first use):
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npx openleads find "50 fintech founders verified only"
|
|
115
|
+
# or: npm i -g openleads
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## β‘ Quickstart
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# Launch the interactive chat β just type what you want
|
|
122
|
+
openleads
|
|
123
|
+
|
|
124
|
+
# Or go one-shot, non-interactive:
|
|
125
|
+
openleads find "50 fintech founders, verified only" --out leads.csv
|
|
126
|
+
openleads find --source npi --keyword pediatric --location CA --format json
|
|
127
|
+
openleads find "rust developers in Berlin" --source github --format ndjson --out devs.ndjson
|
|
128
|
+
|
|
129
|
+
# Verify specific addresses
|
|
130
|
+
openleads verify ada@acme.io grace@cobol.dev
|
|
131
|
+
|
|
132
|
+
# See what you can search
|
|
133
|
+
openleads sources
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
No signup, no key, no database fees.
|
|
137
|
+
|
|
138
|
+
## π¬ The chat CLI
|
|
139
|
+
|
|
140
|
+
`openleads chat` (or just `openleads`) opens a Claude-Code-style REPL. Type requests in plain English and refine conversationally:
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
openleads> pediatricians in California
|
|
144
|
+
openleads> only verified
|
|
145
|
+
openleads> /source github
|
|
146
|
+
openleads> machine learning researchers as ndjson
|
|
147
|
+
openleads> /export leads.ndjson
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- **Works fully offline.** A rule-based intent parser understands counts, verticals, locations, filters, and `verified only` β **no API key needed.**
|
|
151
|
+
- **Optionally smarter.** Set `OPENROUTER_API_KEY` (a free model works) and free-form input is parsed by an LLM. The active mode is always shown.
|
|
152
|
+
- **Slash commands** for precision: `/source`, `/count`, `/verified`, `/format`, `/export`, `/sources`, `/cache`, `/help`, `/quit`.
|
|
153
|
+
|
|
154
|
+
## π§© Sources (and adding your own)
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
$ openleads sources
|
|
158
|
+
github [people ] developers & open-source orgs
|
|
159
|
+
npi [people ] U.S. doctors & healthcare providers
|
|
160
|
+
openalex [people ] researchers & academics
|
|
161
|
+
producthunt [company] trending products & startups
|
|
162
|
+
yc [company] startup founders (Y Combinator)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
All are **keyless and free**. Want a vertical we don't ship β recruiters, lawyers, real-estate agents, your CRM export? Drop a `*.py` file in `~/.openleads/sources/`:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from openleads.sources.base import Source
|
|
169
|
+
from openleads.models import Entity, Query
|
|
170
|
+
|
|
171
|
+
class LawyersSource(Source):
|
|
172
|
+
name = "lawyers"
|
|
173
|
+
kind = "people"
|
|
174
|
+
vertical = "attorneys"
|
|
175
|
+
description = "State bar directory."
|
|
176
|
+
|
|
177
|
+
def search(self, query: Query):
|
|
178
|
+
for row in fetch_from_some_free_directory(query):
|
|
179
|
+
yield Entity(full_name=row["name"], organization=row["firm"],
|
|
180
|
+
domain=row["firm_domain"], source=self.name)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Run `openleads sources` and it's there. The email engine handles the rest. Full guide: [`docs/sources.md`](./docs/sources.md).
|
|
184
|
+
|
|
185
|
+
## π¦ Output formats
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
openleads find "20 founders" --format csv # default; CRM/mail-merge ready
|
|
189
|
+
openleads find "20 founders" --format json # array, includes score + signals
|
|
190
|
+
openleads find "20 founders" --format ndjson # one lead per line, streamable
|
|
191
|
+
openleads find "20 founders" --format json --out - # write to stdout
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The CSV schema is a superset of v1's, so the cold-email companion and any existing tooling keep working.
|
|
195
|
+
|
|
196
|
+
## π How it works
|
|
197
|
+
|
|
198
|
+
```mermaid
|
|
199
|
+
flowchart LR
|
|
200
|
+
Q[Your request<br/>chat or CLI] --> I[Intent parser<br/>rule-based Β± LLM]
|
|
201
|
+
I --> S[Source plugin<br/>yc Β· github Β· npi Β· openalex Β· β¦]
|
|
202
|
+
S --> E[Email engine<br/>multi-resolver MX β permutations β SMTP RCPT]
|
|
203
|
+
E --> C[Confidence score 0β100<br/>+ honest label]
|
|
204
|
+
C --> O[CSV Β· JSON Β· NDJSON]
|
|
205
|
+
E <--> K[(SQLite cache<br/>MX Β· SMTP Β· datasets)]
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
The crown jewel is the **email engine** ([deep dive](./docs/how-it-works.md)): MX cross-checked across **two DNS-over-HTTPS resolvers**, common name permutations, and a real SMTP `RCPT` probe (no message is ever sent) with **catch-all detection**. Results carry an explainable **0β100 score**. A **SQLite cache** avoids re-probing domains and mail servers between runs.
|
|
209
|
+
|
|
210
|
+
> π‘ SMTP verification needs outbound **port 25**. Works on most servers; some home ISPs block it, in which case OpenLeads gracefully falls back to MX-validated pattern guesses.
|
|
211
|
+
|
|
212
|
+
## π¨ Bonus: cold-email companion
|
|
213
|
+
|
|
214
|
+
`openleads campaign` turns `leads.csv` into personalized outreach β LLM-drafted (free OpenRouter models supported), clean formatting, placeholder guards, sends over **your own** SMTP, and saves a copy to Sent. Dry-run by default; `--live` to send.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pip install "openleads[campaign]"
|
|
218
|
+
cp .env.example .env # add your SMTP + OpenRouter creds
|
|
219
|
+
openleads campaign # dry run (preview)
|
|
220
|
+
openleads campaign --live # send for real
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
> β οΈ This is the only part that touches your mailbox. The lead engine never sends anything.
|
|
224
|
+
|
|
225
|
+
## π§ Responsible use
|
|
226
|
+
|
|
227
|
+
OpenLeads is for legitimate outreach, recruiting, research, and prospecting. Some verticals carry extra weight β e.g. healthcare providers (NPI) and academics β so please read [`docs/responsible-use.md`](./docs/responsible-use.md). **You** are responsible for anti-spam law (CAN-SPAM, GDPR, CASL) and each source's terms.
|
|
228
|
+
|
|
229
|
+
## πΊοΈ What's new in v2.0
|
|
230
|
+
|
|
231
|
+
- β
Installable package + **`openleads` CLI** (pip & npx)
|
|
232
|
+
- β
**Interactive chat REPL** (rule-based, LLM-optional)
|
|
233
|
+
- β
**Pluggable sources** + 4 new keyless verticals (GitHub, NPI, OpenAlex, ProductHunt)
|
|
234
|
+
- β
**Confidence scoring (0β100)** with multi-resolver MX cross-checks
|
|
235
|
+
- β
**SQLite caching** layer
|
|
236
|
+
- β
**`--format json/ndjson`** output
|
|
237
|
+
|
|
238
|
+
See the full [CHANGELOG](./CHANGELOG.md).
|
|
239
|
+
|
|
240
|
+
## π€ Contributing
|
|
241
|
+
|
|
242
|
+
PRs very welcome β see [CONTRIBUTING.md](./CONTRIBUTING.md). The easiest high-impact contribution is **a new source plugin** ([guide](./docs/sources.md)) β that's literally how OpenLeads becomes "Apollo for everyone."
|
|
243
|
+
|
|
244
|
+
## π License
|
|
245
|
+
|
|
246
|
+
[PolyForm Noncommercial 1.0.0](./LICENSE) β free for personal, research, educational, and nonprofit use. Commercial use? See [COMMERCIAL-LICENSE.md](./COMMERCIAL-LICENSE.md).
|
|
247
|
+
|
|
248
|
+
## π Acknowledgements
|
|
249
|
+
|
|
250
|
+
[`yc-oss/api`](https://github.com/yc-oss/api) Β· [OpenAlex](https://openalex.org) Β· [NPI Registry](https://npiregistry.cms.hhs.gov/) Β· GitHub & ProductHunt public data Β· and everyone who has ever rage-quit a "request a demo" button.
|
|
251
|
+
|
|
252
|
+
<div align="center">
|
|
253
|
+
|
|
254
|
+
**If OpenLeads saved you a subscription, consider leaving a β β it genuinely helps.**
|
|
255
|
+
|
|
256
|
+
</div>
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# π§² OpenLeads
|
|
4
|
+
|
|
5
|
+
### The free, open-source Apollo alternative β for *everyone*.
|
|
6
|
+
|
|
7
|
+
**Find founders, developers, doctors, researchers β anyone β and verify their emails, using only free, public data. No paid APIs. No API keys. No seat fees. Now with an interactive chat CLI.**
|
|
8
|
+
|
|
9
|
+
[](./LICENSE)
|
|
10
|
+
[](https://www.python.org/)
|
|
11
|
+
[](#-how-it-works)
|
|
12
|
+
[](https://pypi.org/project/openleads/)
|
|
13
|
+
[](https://github.com/Samyrrrrrr990/openleads/actions/workflows/ci.yml)
|
|
14
|
+
[](./CONTRIBUTING.md)
|
|
15
|
+
[](https://github.com/Samyrrrrrr990/openleads/stargazers)
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
Apollo, Hunter, RocketReach, and ZoomInfo all sell the same two things: **a contact database** and **email verification**. Their moat is the database. **OpenLeads inverts it.**
|
|
22
|
+
|
|
23
|
+
> OpenLeads is a **universal `entity β verified email` engine**, fed by a registry of **pluggable, free, keyless public data sources.**
|
|
24
|
+
|
|
25
|
+
The email engine doesn't care *who* you're looking for. So coverage grows by adding small **source plugins**, not by paying for a database. v2.0 ships sources for **startup founders, open-source developers, U.S. doctors, and academic researchers** β and you can add any vertical (lawyers, podcasters, real-estate agentsβ¦) by dropping a single `.py` file in a folder.
|
|
26
|
+
|
|
27
|
+
All for **$0**, in code you can read in one sitting.
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
openleads> find 25 AI founders, verified emails only
|
|
31
|
+
plan source=yc count=25 filter=AI verified-only parser=rule
|
|
32
|
+
βββββ³βββββ³ββββββββββββββββββ³βββββββββββββββ³ββββββββββ³ββββββββββ³ββββββββ
|
|
33
|
+
β # β β β Email β Name β Title β Org β Score β
|
|
34
|
+
β‘ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ©
|
|
35
|
+
β 1 β OK β ada@acme.ai β Ada Lovelace β Founder β Acme β 96 β
|
|
36
|
+
β 2 β ~CAβ grace@cobol.dev β Grace Hopper β CEO β COBOLwx β 71 β
|
|
37
|
+
βββββ΄βββββ΄ββββββββββββββββββ΄βββββββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββ
|
|
38
|
+
25 leads Β· 18 verified Β· /export FILE to save
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> `OK` = SMTP-verified Β· `~CA` = catch-all best-guess Β· `~PG` = MX-only pattern guess Β· **Score** = 0β100 confidence
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## β¨ Why OpenLeads
|
|
46
|
+
|
|
47
|
+
| | OpenLeads | Apollo / Hunter (free tier) |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| **Cost** | $0, forever | Credit-limited, then paid |
|
|
50
|
+
| **API key required** | β None | β
Required |
|
|
51
|
+
| **Who you can find** | Founders, devs, doctors, researchers, **+ any vertical you plug in** | Their database only |
|
|
52
|
+
| **Email verification** | β
Live SMTP `RCPT` + 0β100 score | Paid feature |
|
|
53
|
+
| **Catch-all detection** | β
Yes | Sometimes |
|
|
54
|
+
| **Interactive chat CLI** | β
Yes (`openleads chat`) | β |
|
|
55
|
+
| **You own the code** | β
Readable, hackable, extensible | β Black box |
|
|
56
|
+
| **Output** | β
CSV / JSON / NDJSON | Often gated |
|
|
57
|
+
| **Core dependencies** | **Zero** (stdlib only) | β |
|
|
58
|
+
|
|
59
|
+
## π Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Python (recommended) β zero-dependency engine + plain CLI
|
|
63
|
+
pip install openleads
|
|
64
|
+
|
|
65
|
+
# β¦with the pretty interactive chat TUI
|
|
66
|
+
pip install "openleads[chat]"
|
|
67
|
+
|
|
68
|
+
# β¦with the cold-email companion too
|
|
69
|
+
pip install "openleads[all]"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Prefer Node? A thin wrapper lets you run it with **npx** (it installs the Python package on first use):
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx openleads find "50 fintech founders verified only"
|
|
76
|
+
# or: npm i -g openleads
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## β‘ Quickstart
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Launch the interactive chat β just type what you want
|
|
83
|
+
openleads
|
|
84
|
+
|
|
85
|
+
# Or go one-shot, non-interactive:
|
|
86
|
+
openleads find "50 fintech founders, verified only" --out leads.csv
|
|
87
|
+
openleads find --source npi --keyword pediatric --location CA --format json
|
|
88
|
+
openleads find "rust developers in Berlin" --source github --format ndjson --out devs.ndjson
|
|
89
|
+
|
|
90
|
+
# Verify specific addresses
|
|
91
|
+
openleads verify ada@acme.io grace@cobol.dev
|
|
92
|
+
|
|
93
|
+
# See what you can search
|
|
94
|
+
openleads sources
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
No signup, no key, no database fees.
|
|
98
|
+
|
|
99
|
+
## π¬ The chat CLI
|
|
100
|
+
|
|
101
|
+
`openleads chat` (or just `openleads`) opens a Claude-Code-style REPL. Type requests in plain English and refine conversationally:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
openleads> pediatricians in California
|
|
105
|
+
openleads> only verified
|
|
106
|
+
openleads> /source github
|
|
107
|
+
openleads> machine learning researchers as ndjson
|
|
108
|
+
openleads> /export leads.ndjson
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- **Works fully offline.** A rule-based intent parser understands counts, verticals, locations, filters, and `verified only` β **no API key needed.**
|
|
112
|
+
- **Optionally smarter.** Set `OPENROUTER_API_KEY` (a free model works) and free-form input is parsed by an LLM. The active mode is always shown.
|
|
113
|
+
- **Slash commands** for precision: `/source`, `/count`, `/verified`, `/format`, `/export`, `/sources`, `/cache`, `/help`, `/quit`.
|
|
114
|
+
|
|
115
|
+
## π§© Sources (and adding your own)
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
$ openleads sources
|
|
119
|
+
github [people ] developers & open-source orgs
|
|
120
|
+
npi [people ] U.S. doctors & healthcare providers
|
|
121
|
+
openalex [people ] researchers & academics
|
|
122
|
+
producthunt [company] trending products & startups
|
|
123
|
+
yc [company] startup founders (Y Combinator)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
All are **keyless and free**. Want a vertical we don't ship β recruiters, lawyers, real-estate agents, your CRM export? Drop a `*.py` file in `~/.openleads/sources/`:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from openleads.sources.base import Source
|
|
130
|
+
from openleads.models import Entity, Query
|
|
131
|
+
|
|
132
|
+
class LawyersSource(Source):
|
|
133
|
+
name = "lawyers"
|
|
134
|
+
kind = "people"
|
|
135
|
+
vertical = "attorneys"
|
|
136
|
+
description = "State bar directory."
|
|
137
|
+
|
|
138
|
+
def search(self, query: Query):
|
|
139
|
+
for row in fetch_from_some_free_directory(query):
|
|
140
|
+
yield Entity(full_name=row["name"], organization=row["firm"],
|
|
141
|
+
domain=row["firm_domain"], source=self.name)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Run `openleads sources` and it's there. The email engine handles the rest. Full guide: [`docs/sources.md`](./docs/sources.md).
|
|
145
|
+
|
|
146
|
+
## π¦ Output formats
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
openleads find "20 founders" --format csv # default; CRM/mail-merge ready
|
|
150
|
+
openleads find "20 founders" --format json # array, includes score + signals
|
|
151
|
+
openleads find "20 founders" --format ndjson # one lead per line, streamable
|
|
152
|
+
openleads find "20 founders" --format json --out - # write to stdout
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The CSV schema is a superset of v1's, so the cold-email companion and any existing tooling keep working.
|
|
156
|
+
|
|
157
|
+
## π How it works
|
|
158
|
+
|
|
159
|
+
```mermaid
|
|
160
|
+
flowchart LR
|
|
161
|
+
Q[Your request<br/>chat or CLI] --> I[Intent parser<br/>rule-based Β± LLM]
|
|
162
|
+
I --> S[Source plugin<br/>yc Β· github Β· npi Β· openalex Β· β¦]
|
|
163
|
+
S --> E[Email engine<br/>multi-resolver MX β permutations β SMTP RCPT]
|
|
164
|
+
E --> C[Confidence score 0β100<br/>+ honest label]
|
|
165
|
+
C --> O[CSV Β· JSON Β· NDJSON]
|
|
166
|
+
E <--> K[(SQLite cache<br/>MX Β· SMTP Β· datasets)]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The crown jewel is the **email engine** ([deep dive](./docs/how-it-works.md)): MX cross-checked across **two DNS-over-HTTPS resolvers**, common name permutations, and a real SMTP `RCPT` probe (no message is ever sent) with **catch-all detection**. Results carry an explainable **0β100 score**. A **SQLite cache** avoids re-probing domains and mail servers between runs.
|
|
170
|
+
|
|
171
|
+
> π‘ SMTP verification needs outbound **port 25**. Works on most servers; some home ISPs block it, in which case OpenLeads gracefully falls back to MX-validated pattern guesses.
|
|
172
|
+
|
|
173
|
+
## π¨ Bonus: cold-email companion
|
|
174
|
+
|
|
175
|
+
`openleads campaign` turns `leads.csv` into personalized outreach β LLM-drafted (free OpenRouter models supported), clean formatting, placeholder guards, sends over **your own** SMTP, and saves a copy to Sent. Dry-run by default; `--live` to send.
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
pip install "openleads[campaign]"
|
|
179
|
+
cp .env.example .env # add your SMTP + OpenRouter creds
|
|
180
|
+
openleads campaign # dry run (preview)
|
|
181
|
+
openleads campaign --live # send for real
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
> β οΈ This is the only part that touches your mailbox. The lead engine never sends anything.
|
|
185
|
+
|
|
186
|
+
## π§ Responsible use
|
|
187
|
+
|
|
188
|
+
OpenLeads is for legitimate outreach, recruiting, research, and prospecting. Some verticals carry extra weight β e.g. healthcare providers (NPI) and academics β so please read [`docs/responsible-use.md`](./docs/responsible-use.md). **You** are responsible for anti-spam law (CAN-SPAM, GDPR, CASL) and each source's terms.
|
|
189
|
+
|
|
190
|
+
## πΊοΈ What's new in v2.0
|
|
191
|
+
|
|
192
|
+
- β
Installable package + **`openleads` CLI** (pip & npx)
|
|
193
|
+
- β
**Interactive chat REPL** (rule-based, LLM-optional)
|
|
194
|
+
- β
**Pluggable sources** + 4 new keyless verticals (GitHub, NPI, OpenAlex, ProductHunt)
|
|
195
|
+
- β
**Confidence scoring (0β100)** with multi-resolver MX cross-checks
|
|
196
|
+
- β
**SQLite caching** layer
|
|
197
|
+
- β
**`--format json/ndjson`** output
|
|
198
|
+
|
|
199
|
+
See the full [CHANGELOG](./CHANGELOG.md).
|
|
200
|
+
|
|
201
|
+
## π€ Contributing
|
|
202
|
+
|
|
203
|
+
PRs very welcome β see [CONTRIBUTING.md](./CONTRIBUTING.md). The easiest high-impact contribution is **a new source plugin** ([guide](./docs/sources.md)) β that's literally how OpenLeads becomes "Apollo for everyone."
|
|
204
|
+
|
|
205
|
+
## π License
|
|
206
|
+
|
|
207
|
+
[PolyForm Noncommercial 1.0.0](./LICENSE) β free for personal, research, educational, and nonprofit use. Commercial use? See [COMMERCIAL-LICENSE.md](./COMMERCIAL-LICENSE.md).
|
|
208
|
+
|
|
209
|
+
## π Acknowledgements
|
|
210
|
+
|
|
211
|
+
[`yc-oss/api`](https://github.com/yc-oss/api) Β· [OpenAlex](https://openalex.org) Β· [NPI Registry](https://npiregistry.cms.hhs.gov/) Β· GitHub & ProductHunt public data Β· and everyone who has ever rage-quit a "request a demo" button.
|
|
212
|
+
|
|
213
|
+
<div align="center">
|
|
214
|
+
|
|
215
|
+
**If OpenLeads saved you a subscription, consider leaving a β β it genuinely helps.**
|
|
216
|
+
|
|
217
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Back-compat shim. The outreach companion moved to ``openleads.campaign`` in v2.0.
|
|
3
|
+
|
|
4
|
+
python automation.py # dry-run preview (was the old behavior)
|
|
5
|
+
python automation.py --live # send
|
|
6
|
+
|
|
7
|
+
Prefer: ``openleads campaign`` / ``openleads campaign --live``.
|
|
8
|
+
"""
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from openleads.campaign import main
|
|
12
|
+
|
|
13
|
+
if __name__ == "__main__":
|
|
14
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Back-compat shim for OpenLeads v1.
|
|
3
|
+
|
|
4
|
+
The engine moved into the installable ``openleads`` package in v2.0. This module
|
|
5
|
+
re-exports the v1 public helpers and forwards the old CLI to ``openleads find``
|
|
6
|
+
so existing scripts keep working. Prefer the new entry point:
|
|
7
|
+
|
|
8
|
+
openleads find "20 founders" # or: python -m openleads find ...
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
# Re-export the v1 public API from its new homes (behavior unchanged).
|
|
15
|
+
from openleads.emails.permute import ( # noqa: F401
|
|
16
|
+
candidate_emails,
|
|
17
|
+
domain_of,
|
|
18
|
+
name_parts,
|
|
19
|
+
)
|
|
20
|
+
from openleads.emails.resolve import find_email # noqa: F401
|
|
21
|
+
from openleads.sources.yc import ( # noqa: F401
|
|
22
|
+
pick_exec,
|
|
23
|
+
split_location,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _translate(argv: list[str]) -> list[str]:
|
|
28
|
+
"""Map v1 flags onto the new ``find`` subcommand."""
|
|
29
|
+
out: list[str] = []
|
|
30
|
+
for a in argv:
|
|
31
|
+
if a == "--no-write":
|
|
32
|
+
out += ["--out", "-"] # v1 'print only' β write CSV to stdout
|
|
33
|
+
else:
|
|
34
|
+
out.append(a)
|
|
35
|
+
return out
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def main() -> int:
|
|
39
|
+
sys.stderr.write(
|
|
40
|
+
"[deprecation] `lead_engine.py` is now a shim. Use `openleads find ...` "
|
|
41
|
+
"(or `python -m openleads find ...`).\n"
|
|
42
|
+
)
|
|
43
|
+
from openleads.cli import main as cli_main
|
|
44
|
+
return cli_main(["find"] + _translate(sys.argv[1:]))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
raise SystemExit(main())
|