Wiseflow cold-outreach
Find local businesses on Google Maps, extract contact emails from their websites, generate personalized outreach emails with LLM, and send via SMTP. Full pipeline for B2B cold email campaigns.
install
source · Clone the upstream repo
git clone https://github.com/TeamWiseFlow/wiseflow
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/TeamWiseFlow/wiseflow "$T" && mkdir -p ~/.claude/skills && cp -r "$T/addons/officials/crew/business-developer/skills/cold-outreach" ~/.claude/skills/teamwiseflow-wiseflow-cold-outreach && rm -rf "$T"
manifest:
addons/officials/crew/business-developer/skills/cold-outreach/SKILL.mdsource content
Cold Outreach 技能
Use this skill when:
- User wants to find local businesses in a specific niche and location
- You need to extract business contact information from Google Maps
- You need to generate and send personalized cold outreach emails
Step 1 — Find Businesses on Google Maps
1. Warm up: navigate to https://www.google.com/maps 2. Perform the search: https://www.google.com/maps/search/{niche}+{location} Example: https://www.google.com/maps/search/餐厅+上海朝阳区 3. Wait 3 seconds for results to load 4. For each visible business card in the sidebar: Extract: - Business name (visible heading) - Rating (if shown) - Address (if shown) - Phone number (if shown) - Website URL (if a link icon is present → click to get URL, then go back) 5. Scroll down to load more results (up to the user-specified limit, default: 20) 6. If Google shows CAPTCHA or "unusual traffic" → stop immediately, report to user 7. Save collected data to: ./outreach_data/businesses_YYYY-MM-DD.csv
CSV format:
name,address,phone,website,email "上海味道餐厅","上海市朝阳区xxx路123号","010-12345678","https://example.com",""
Step 2 — Extract Emails from Websites
For each business that has a website URL:
Method A — xurl (fast, for static sites): Use xurl to GET the homepage Apply regex: \b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b If email found → record it Method B — browser (for JS-rendered sites, if Method A fails): Navigate to the homepage If no email found on homepage → try /contact and /about paths Search for "mailto:" links or visible email text If no email found after both methods → leave email column empty, log "no_email"
Pause 0.5–1 second between each website request to avoid rate limiting.
Step 3 — Generate Personalized Outreach Emails
For each business with a valid email address, generate a personalized email:
LLM Prompt: "Write a brief, personalized cold outreach email in [Chinese/English]. Business name: {business_name} Industry: {niche} Our offer: {user_provided_value_proposition} Rules: - Subject line: concise, specific to their business (NOT generic) - Body: 3–4 sentences max 1. Opening: reference their specific business (show you did research) 2. Value: what we can do for them (focus on their benefit, not our product) 3. CTA: one clear, low-friction ask (e.g., 'Would you be open to a 15-minute call?') - Plain text only (no HTML, no markdown) - No pushy sales language Return JSON: { 'subject': '...', 'body': '...' }"
Step 4 — Send Emails via SMTP
For each business with subject + body generated:
python3 {baseDir}/scripts/send_email.py \ --to "{business_email}" \ --subject "{subject}" \ --body "{body}"
Wait 2–3 seconds between each send.
Track results in real time:
- ✅ Sent successfully → log to
outreach_data/sent_YYYY-MM-DD.csv - ❌ Failed → log to
with error reasonoutreach_data/failed_YYYY-MM-DD.csv
send_email.py Usage
# Send with inline body text python3 {baseDir}/scripts/send_email.py \ --to "target@example.com" \ --subject "Subject line" \ --body "Email body text" # Send with body from file python3 {baseDir}/scripts/send_email.py \ --to "target@example.com" \ --subject "Subject line" \ --body-file ./outreach_data/template.txt
Returns JSON:
{"ok": true, "to": "target@example.com", "message": "sent"} {"ok": false, "to": "target@example.com", "error": "Connection refused"}
SMTP Environment Variables
| Variable | Description | Example |
|---|---|---|
| SMTP hostname | |
| Port (default: 587) | |
| Login / sender address | |
| Password or app password | |
| Display name + address | |
Gmail users: Must use App Passwords (Google Account → Security → App Passwords). Regular passwords will be rejected.
QQ Mail: use SMTP password from QQ mail settings → POP3/SMTP, server:
smtp.qq.com, port 587.
Error Handling
| Situation | Action |
|---|---|
| Google CAPTCHA | Stop collection, report to user |
| Business website returns 4xx/5xx | Log as "unreachable", skip email extraction |
| SMTP auth failure | Stop sending, check credentials with user |
| SMTP connection refused | Check SMTP_SERVER and SMTP_PORT |
spam rejection | Stop sending — email content flagged as spam, revise template |
Anti-Spam Best Practices
- Personalize each email (business name at minimum)
- Send no more than 50–100 emails per day from a single address
- Include a genuine unsubscribe note: "如不希望收到此类邮件,请直接回复告知,谢谢。"
- Use a real business email, not a free webmail (gmail.com for cold outreach has high spam rate)