Outreach factory
Run personalized cold outreach from the user's own email + API keys. Use when the user wants to cold-email companies/people at scale for a job search, sales, recruiting, or fundraising - find verified contacts, write a tailored email per recipient, dedup against past sends, send from their own SMTP/Gmail, and track reply-rate. Triggers on "cold outreach", "email these companies", "job-search outreach", "find emails and send", "outreach campaign".From its SKILL.md
npx -y skills add yashs33244/outreach-factory --skill outreach-factoryAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
3.8 KB, as published. Nobody here has run it
Outreach Factory
A local-first outreach engine. Everything runs on the user's machine with THEIR
credentials (SMTP/Gmail app password + optional Apollo key). Nothing routes through a
third party. The bundled Python engine lives at ${CLAUDE_PLUGIN_ROOT}/scripts.
Golden rules (never break these)
- Never send without a dry-run the user approves. Print the rendered emails first, get an explicit "send", then send. Sending cold email is irreversible and outward-facing.
- Never send to an address
already_contacted()returns true for. Hard dedup. - Never ship a literal
{token}. Use strict render; excluded contacts are reported, not sent broken. - Never print or echo the user's secrets. The Apollo key is read only inside
enrich_contact.py. - Respect the daily cap and throttle. Warn about deliverability + CAN-SPAM/GDPR.
First run: onboarding
If ~/.outreach-factory/credentials.env is missing, walk the user through setup:
- Sending creds: Gmail app password is easiest - see
${CLAUDE_PLUGIN_ROOT}/docs/smtp.md. Collect SMTP_HOST/PORT/USER/PASSWORD (+ IMAP_* for reply tracking). Write them withsecrets.write_secrets({...})(creates the file at 0600). - Apollo key (optional, for finding verified emails): apollo.io -> Settings -> API.
- Campaign config: set
from_name,from_email,attachments(e.g. resume path),daily_cap, and the messagetemplate+required_fields+optional_fallbacksviaconfig.save_config(...). - Message Studio: ask what email TYPE and writing STYLE they want, draft 2-3 template
options, render a sample of each, let them pick, then derive the
required_fields(the{tokens}the template needs per contact).
Full walkthrough with copy-paste snippets: ${CLAUDE_PLUGIN_ROOT}/docs/USAGE.md.
Find a verified contact for a company
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/enrich_contact.py "<Company>" "<domain>" --location "<geo>"
Returns JSON with a verified email or {}. Only verified emails (no guessing).
Research many companies (optional, agent-driven)
When the user wants a list, fan out subagents to find companies with a live, relevant
signal (e.g. hiring a junior engineer) in their target geography, dedup against the
store, then call enrich_contact.py for the top-K by fit. Write results as a list of
contact dicts with the template's dynamic fields (greet, personalized_opener, ...).
Render + dedup + dry-run + send
Drive the engine (add ${CLAUDE_PLUGIN_ROOT}/scripts to sys.path):
store.already_contacted / contacted_domain for dedup, render_batch for strict
render, get_sender(cfg, secrets) + sender.verify(), then dry-run print, then on
approval loop sender.send(Message(...)) and store.record_send(...), throttled and
capped. The exact code is in ${CLAUDE_PLUGIN_ROOT}/docs/USAGE.md sections 5.
Status / reply-rate
store.reply_rate() -> {sent, replies, reply_rate}. store.export_xlsx(path) for a
human sheet. Reply-rate is the metric that matters - surface it after every campaign.
Notes
- Engine is stdlib-only except optional
openpyxl(xlsx export). - Providers: SMTP today; SendGrid/SES are documented fast-follow.
- IMAP reply auto-detection is on the roadmap; until then replies can be recorded with
store.record_reply(message_id=..., from_addr=...).