← 返回
未分类 Key 中文

mailgo-coldmail-marketing

Complete cold email campaign suite for Mailgo — verify recipients, claim free mailbox, generate & optimize content, create campaigns, manage lifecycle, and v...
完整的冷邮件活动套件(Mailgo)——验证收件人、领取免费邮箱、生成与优化内容、创建活动、管理生命周期等。
leadsnavideveloper leadsnavideveloper 来源
未分类 clawhub v1.1.2 1 版本 100000 Key: 需要
★ 0
Stars
📥 377
下载
💾 0
安装
1
版本
#latest

概述

Mailgo Campaign Suite

One skill, complete cold email pipeline. From recipient verification to campaign reporting — everything runs through bundled scripts with zero third-party dependencies.


Step 0 — Authentication Setup

Required: MAILGO_API_KEY environment variable must be set before any other step.

Quick check

# Confirm the variable is set (shows first 5 characters only)
echo "${MAILGO_API_KEY:0:5}"

If output is non-empty → proceed to Step 1. If empty → follow the setup flow below.

Setup Flow

Sub-step 0.1 — Register or Log In

New users:

  1. Go to https://app.mailgo.ai
  2. Click "Sign Up" and complete registration

Existing users:

  1. Go to https://app.mailgo.ai
  2. Log in with your credentials

Sub-step 0.2 — Create Personal Token

Once logged in:

  1. Click your avatar in the bottom-left corner
  2. Select Personal Tokens from the menu
  3. Click Create Token
  4. Give your token a descriptive name (e.g., "Claude Code")
  5. Copy the generated token

> SECURITY: Never paste the token into chat. It must only be set as a local environment variable.

Sub-step 0.3 — Set Environment Variable

# macOS / Linux (permanent)
echo 'export MAILGO_API_KEY="YOUR_TOKEN"' >> ~/.zshrc && source ~/.zshrc

# Windows PowerShell (permanent)
[System.Environment]::SetEnvironmentVariable('MAILGO_API_KEY', 'YOUR_TOKEN', 'User')

Replace YOUR_TOKEN with the copied value.

Sub-step 0.4 — Verify

# macOS / Linux — shows first 5 characters to confirm without exposing the token
echo "${MAILGO_API_KEY:0:5}"

# Windows PowerShell
$k = $env:MAILGO_API_KEY; if ($k) { $k.Substring(0, [Math]::Min(5, $k.Length)) } else { "" }

If output is non-empty, you're ready. If empty, run source ~/.zshrc or open a new terminal.

Key Facts

ItemValue
-------------
Token sourceapp.mailgo.ai → Avatar → Personal Tokens
Env variable nameMAILGO_API_KEY
API headerX-API-Key: {MAILGO_API_KEY}
Token scopeYour Mailgo account (mailboxes, campaigns, reports)
Revoke tokenapp.mailgo.ai → Avatar → Personal Tokens → Delete

Auth Error Handling

IssueFix
------------
Empty after source ~/.zshrcOpen a new terminal window
401 UnauthorizedToken may be invalid or deleted — create a new one in Personal Tokens
403 ForbiddenEnsure User-Agent header is set (scripts handle this automatically)

Step 0.5 — Upfront Information Gathering

Collect all required information in a single interaction before starting the pipeline.

Ask all questions at once. Do not ask in separate rounds. The user fills in what they know; mark anything skipped as "not provided".

> When to run: Only when the user intends to create a new campaign. Skip for report/manage/replies tasks.


Group A — Your Information (for email signature & credibility)

Ask all of these together in one message:

#QuestionFieldRequired?
-------------------------------
1What is your company name?sender_companyYes
2What is your name (for the signature)?sender_nameYes
3What does your company offer (products / services)?sender_offeringsYes
4What is your job title?sender_titleRecommended
5What is your company website?sender_websiteRecommended
6Any notable clients, certifications, or metrics to mention?sender_proofOptional

Group B — Your Recipients

Ask all of these together in the same message as Group A:

#QuestionField
--------------------
7Who are you sending to? Paste emails, or provide a file path (CSV / XLSX / TXT).recipients
8What is the goal of this campaign? (one sentence)campaign_purpose
9Do your recipients have names available? (column name or yes/no)has_name
10Do you have recipients' company names? (column name or yes/no)has_company
11Do you have recipients' job titles? (column name or yes/no)has_title
12Do you have recipients' company websites / domains? (column name or yes/no)has_domain

> If the user provides a file, auto-detect columns after reading the file headers — then mark fields 9–12 automatically without asking again.

>

> ⚠ Header Warning: Column detection relies entirely on header names. Files without headers (e.g. a bare two-column XLSX with email + company but no row of column names) will only have col_0, col_1, … as synthetic headers — none of which match any known field name. As a result, only the email column can be identified by content scanning; all other columns (company, name, title, domain) will be silently discarded.

> Whenever a user provides a headerless file and you can see that extra columns exist (e.g. "two-column spreadsheet"), proactively warn them:

> _"Your file appears to have no header row. Only email addresses were imported — company names and other fields were not recognized. Add a header row (e.g. email, company, name) and re-upload to include that data."_


Auto-Derive Name from Email Prefix (CRITICAL)

Immediately after receiving the recipient list, check whether name data is available.

If has_name is false (no name column detected, no names provided inline):

  1. Extract name from each email's local-part (the portion before @):
    • Split on ., -, _ → capitalize each segment → join with space
    • Examples: alice.smith@co.com"Alice Smith", john_doe@co.com"John Doe", jdoe@co.com"Jdoe"
  2. Store the derived name into each recipient entry in session_context.recipients
  3. Set recipient_fields.name = true with source noted as "auto-derived from email prefix"
  4. Do this silently — do not ask the user, do not announce it; just note it in the Step 3 change summary

This ensures #{Name} is always available as long as there are valid email addresses.


Handling Partial Answers

SituationAction
-------------------
User skips a required field (1, 2, 3, 7, 8)Ask once more specifically for that field only
User skips a recommended field (4, 5)Mark as not provided, do not ask again
User skips an optional field (6)Mark as not provided, move on
User says "I'll send to a file I haven't uploaded yet"Ask for file path, then detect columns
User provides inline recipients with no extra dataAuto-derive names from email prefixes (see above); mark fields 10–12 as not provided
User provides a file without a header row and extra columns are presentWarn: only emails were imported; other columns were discarded. Ask user to add a header row (email, company, name, etc.) and re-upload

Carry Forward

Store all answers as session context. Every subsequent step uses this context directly — never ask for the same information again.

session_context = {
  sender_company:   "...",   # or null
  sender_name:      "...",   # or null
  sender_title:     "...",   # or null
  sender_website:   "...",   # or null
  sender_offerings: "...",   # or null
  sender_proof:     "...",   # or null
  recipients: [              # each entry always has a name (user-provided or auto-derived)
    { email: "...", name: "...", company: "...", title: "...", domain: "..." },
    ...
  ],
  campaign_purpose: "...",
  recipient_fields: {
    name:    true,           # ALWAYS true — either user-provided or auto-derived from email prefix
    company: true/false,
    title:   true/false,
    domain:  true/false,
  }
}

Step 1 — Verify Recipient Emails

Always verify before sending to >10 recipients.

Use the bundled script (MANDATORY)

source ~/.zshrc

# Option A: inline emails
python3 scripts/verify_emails.py alice@example.com bob@gmail.com

# Option B: from file (TXT/CSV/JSON)
python3 scripts/verify_emails.py --file leads.csv

# Option C: override column detection
python3 scripts/verify_emails.py --file leads.csv --email-column "Email Address"

Script flags:

FlagDefaultDescription
----------------------------
emailsSpace-separated email addresses
--fileRead from TXT/CSV/JSON file
--email-columnauto-detectOverride email column name
--timeout180Poll timeout in seconds
--interval5Poll interval in seconds

Output: JSON on stdout with categorized results:

{
  "total": 5,
  "valid": [{"email": "...", "status": "VALID"}],
  "invalid": [...],
  "domain_error": [...],
  "unknown": [...],
  "unchecked": [...]
}

Email Status Values

StatusMeaningRecommendation
---------------------------------
VALIDConfirmed deliverableSend
UNKNOWNCatch-all or greylistingSend with caution
DOMAIN_ERRORNo MX recordsDo not send
INVALIDMalformed or SMTP-rejectedDo not send
UNCHECKEDStill processingWait or re-poll

Filtering guidance: Conservative = VALID only. Aggressive = VALID + UNKNOWN.

Behavior Rules

  • Never report results while UNCHECKED entries remain (unless timeout)
  • Show progress during polls: "Verifying... X/total processed"
  • Ask before filtering: "Found N undeliverable addresses. Remove them?"
  • Credit error = stop immediately
  • UNKNOWN is not a hard block — explain the tradeoff

API Details (edge cases only)

  • Submit: POST /sirius/api/biz/email/verification — body: {"emails": [...]}
  • Poll: GET /sirius/api/biz/email/verification/task/{taskId}
  • Max 10,000 emails per task; script auto-batches larger lists
  • 120 req/min rate limit; on 429 wait 60s

Step 2 — Claim Free Pre-Warmed Mailbox

Run before creating any campaign. Each user gets one free mailbox (60 days, 90+ sender score).

Use the bundled script (MANDATORY)

source ~/.zshrc

# Claim (idempotent — safe to run multiple times)
python3 scripts/claim_free_mailbox.py

# JSON output for scripting
python3 scripts/claim_free_mailbox.py --json

What you get:

  • Pre-warmed mailbox with 90+ sender score
  • 60-day validity, no credit card required
  • Idempotent: re-running returns the same mailbox
  • stdout outputs just the email address (for piping)

> Note: The free mailbox uses a randomly assigned domain (e.g. you@randomdomain.io) which may not match your company domain. If brand consistency matters, consider purchasing a dedicated domain at https://app.mailgo.ai.

Auto-integration

After claiming, use the returned email as --sender in Step 4:

SENDER=$(python3 scripts/claim_free_mailbox.py)
python3 scripts/run_campaign.py --sender "$SENDER" ...

API Details (edge cases only)

  • Endpoint: POST /api/biz/benefits/assign-prewarm
  • Auth: X-API-Key: {key}
  • Response: {"code": 0, "data": "email@domain.com"}
  • data: null = pool empty, contact support

Step 3 — Generate & Optimize Email Content

This is a knowledge-and-rewrite step. No API calls. No scripts.

Apply the 6-step optimization pipeline to user content, or generate from scratch.

Prerequisites for Generation — Use Session Context (CRITICAL)

All sender and recipient information was collected in Step 0.5. Do NOT ask again.

Read directly from session_context:

Context fieldUse in email
-----------------------------
sender_nameSignature name
sender_titleSignature title (omit if null)
sender_companySignature company + body references
sender_websiteSignature website (omit if null)
sender_offeringsValue bridge paragraph
sender_proofProof point sentence (omit if null)
recipient_fields.nameAlways true — use #{Name} unconditionally (user-provided or auto-derived from email prefix in Step 0.5)
recipient_fields.companyUse #{Company Name} only if true
recipient_fields.titleUse #{Title} only if true
recipient_fields.domainUse #{Domain} only if true

> If session_context is missing (e.g. user jumped directly to Step 3), collect the missing fields inline — but only the ones not yet known.

Template Variables and Placeholder Rules (CRITICAL)

Mailgo uses #{...} placeholders that are resolved server-side at send time:

PlaceholderDescriptionResolved from
-----------------------------------------
#{Name}Recipient's namecontactName in leads data
#{Company Name}Company namecompanyName in leads data
#{Domain}Company websitedomain in leads data
#{Title}Job titletitle in leads data
#{Email}Email addresscontactEmail in leads data

CRITICAL — Conditional Placeholder Rule:

  • ONLY use a #{...} placeholder if the corresponding data is confirmed available (either from the file columns or user-provided inline data).
  • If a field has NO data, NEVER use its #{...} placeholder. The placeholder will resolve to empty string at send time, creating ugly output like ,您好 or 关于 的合作.
  • Exception: #{Name} is ALWAYS available. Every recipient has a name — either provided by the user or auto-derived from the email prefix in Step 0.5. Never fall back to "您好" when you have email addresses.
  • For other fields, use a generic alternative:
PlaceholderIf data availableIf data NOT available
------------------------------------------------------
#{Name}#{Name},您好_(never happens — always use #{Name})_
#{Company Name}关于 #{Company Name} 的合作关于贵公司的合作 / About a potential partnership
#{Domain}我浏览了 #{Domain}Omit this sentence entirely
#{Title}作为 #{Title}Omit or use generic phrasing

Log placeholder decisions in the change summary:

Placeholders used: #{Name} (data available), #{Email} (always available)
Placeholders skipped: #{Company Name} (no data), #{Title} (no data), #{Domain} (no data)

Optimization Pipeline (execute ALL 6 steps, in order)

Step 3.1 — Normalize

  • Plain text input → wrap in HTML skeleton (see below)
  • HTML input → preserve structure

Step 3.2 — Spam Trigger Scan

  • Scan subject + body against resources/spam-triggers.md
  • Replace each trigger with neutral alternative
  • Log every replacement

Key replacements (most common):

TriggerReplacement
----------------------
free / free trialincluded / trial period
Click hereLearn more / See details
Act nowWhen you're ready
Limited timeWhile available
GuaranteedProven
Dear friendHi #{Name}
ALL CAPS wordsSentence case
!!! / ???Single punctuation

Full replacement table: resources/spam-triggers.md

Step 3.3 — HTML Cleanup

  • Remove: