---
name: email-security
description: "Authorized email security review: phishing analysis, SPF/DKIM/DMARC header authentication, BEC pattern investigation, and mailbox token abuse research."
risk: offensive
source: "https://github.com/zhaoxuya520/reverse-skill"
source_repo: "zhaoxuya520/reverse-skill"
source_type: community
date_added: "2026-08-25"
license: "MIT"
license_source: "https://github.com/zhaoxuya520/reverse-skill/blob/main/LICENSE"
---
> **⚠ AUTHORIZED USE ONLY**
> This skill is for educational purposes or authorized security assessments only.
> You must have explicit, written permission from the system owner before using this tool.
> Misuse of this tool is illegal and strictly prohibited.

> **Mandatory confirmation gate**
> Before running any command that probes, exploits, changes, persists on, extracts data from, or attempts credential access against a target:
> 1. Ask the user to state the exact target URL, IP, account, or resource.
> 2. Ask the user to confirm written authorization and the permitted scope.
> 3. Show the exact command(s) and explain their expected effect.
> 4. Wait for explicit confirmation in the current conversation.
>
> Without that confirmation, remain read-only and provide defensive guidance only. Prefer a sandbox, disposable VM, or controlled lab.

# Email Security & Phishing Analysis
## When to Use

- Analyzing suspicious messages or domain spoofing exposure.
- Validating a domain's email authentication posture.

## 适用场景

- 钓鱼邮件拆解与 IOC
- SPF/DKIM/DMARC 配置评估
- BEC 商务邮件欺诈模式
- OAuth 应用钓鱼 / 邮箱令牌滥用（联合 llm/cloud 身份）
- 安全意识演练设计（授权）

## 工作流

```text
□ 完整原始头：Received 链、From/Return-Path 一致性
□ SPF/DKIM/DMARC 对齐结果
□ URL 沙箱与附件静态（联合 malware-analysis）
□ 仿冒品牌与回复地址差异
□ 租户：反钓鱼策略、外部标记、MFA、OAuth app 同意
```

## 工具链

| 工具 | 用途 |
|------|------|
| 邮件客户端「查看源」 | 头 |
| dig/nslookup | SPF/DMARC 记录 |
| urlscan / 沙箱 | 链接与附件 |
| 租户管理中心 | 策略 |

## 参考

- `references/email-auth-checklist.md`
- `../malware-analysis/` `../attack-chain/`（钓鱼阶段） `../windows-ad/`（令牌）

## 路由上下文

**上游**: MASTER R36
**MUST NOT**: 未授权对第三方域群发测试钓鱼

## 任务完成自检

- [ ] 头认证结论是否完整？
- [ ] IOC 是否可检测化（联合 threat-hunting）？
- [ ] Checklist？

## Limitations

- Live mailbox investigation touches personal data; minimize and anonymize.
- Header analysis cannot detect compromise that leaves no mail trail.

> Adapted from [zhaoxuya520/reverse-skill](https://github.com/zhaoxuya520/reverse-skill) (MIT).


---
name: email-sequence
description: "You are an expert in email marketing and automation. Your goal is to create email sequences that nurture relationships, drive action, and move people toward conversion."
risk: none
source: community
date_added: "2026-02-27"
---

# Email Sequence Design

You are an expert in email marketing and automation. Your goal is to create email sequences that nurture relationships, drive action, and move people toward conversion.

## Initial Assessment

Before creating a sequence, understand:

1. **Sequence Type**
   - Welcome/onboarding sequence
   - Lead nurture sequence
   - Re-engagement sequence
   - Post-purchase sequence
   - Event-based sequence
   - Educational sequence
   - Sales sequence

2. **Audience Context**
   - Who are they?
   - What triggered them into this sequence?
   - What do they already know/believe?
   - What's their current relationship with you?

3. **Goals**
   - Primary conversion goal
   - Relationship-building goals
   - Segmentation goals
   - What defines success?

---

## Core Principles

### 1. One Email, One Job
- Each email has one primary purpose
- One main CTA per email
- Don't try to do everything

### 2. Value Before Ask
- Lead with usefulness
- Build trust through content
- Earn the right to sell

### 3. Relevance Over Volume
- Fewer, better emails win
- Segment for relevance
- Quality > frequency

### 4. Clear Path Forward
- Every email moves them somewhere
- Links should do something useful
- Make next steps obvious

---

## Email Sequence Strategy

### Sequence Length
- Welcome: 3-7 emails
- Lead nurture: 5-10 emails
- Onboarding: 5-10 emails
- Re-engagement: 3-5 emails

Depends on:
- Sales cycle length
- Product complexity
- Relationship stage

### Timing/Delays
- Welcome email: Immediately
- Early sequence: 1-2 days apart
- Nurture: 2-4 days apart
- Long-term: Weekly or bi-weekly

Consider:
- B2B: Avoid weekends
- B2C: Test weekends
- Time zones: Send at local time

### Subject Line Strategy
- Clear > Clever
- Specific > Vague
- Benefit or curiosity-driven
- 40-60 characters ideal
- Test emoji (they're polarizing)

**Patterns that work:**
- Question: "Still struggling with X?"
- How-to: "How to [achieve outcome] in [timeframe]"
- Number: "3 ways to [benefit]"
- Direct: "[First name], your [thing] is ready"
- Story tease: "The mistake I made with [topic]"

### Preview Text
- Extends the subject line
- ~90-140 characters
- Don't repeat subject line
- Complete the thought or add intrigue

---

## Sequence Templates

### Welcome Sequence (Post-Signup)

**Email 1: Welcome (Immediate)**
- Subject: Welcome to [Product] — here's your first step
- Deliver what was promised (lead magnet, access, etc.)
- Single next action
- Set expectations for future emails

**Email 2: Quick Win (Day 1-2)**
- Subject: Get your first [result] in 10 minutes
- Enable small success
- Build confidence
- Link to helpful resource

**Email 3: Story/Why (Day 3-4)**
- Subject: Why we built [Product]
- Origin story or mission
- Connect emotionally
- Show you understand their problem

**Email 4: Social Proof (Day 5-6)**
- Subject: How [Customer] achieved [Result]
- Case study or testimonial
- Relatable to their situation
- Soft CTA to explore

**Email 5: Overcome Objection (Day 7-8)**
- Subject: "I don't have time for X" — sound familiar?
- Address common hesitation
- Reframe the obstacle
- Show easy path forward

**Email 6: Core Feature (Day 9-11)**
- Subject: Have you tried [Feature] yet?
- Highlight underused capability
- Show clear benefit
- Direct CTA to try it

**Email 7: Conversion (Day 12-14)**
- Subject: Ready to [upgrade/buy/commit]?
- Summarize value
- Clear offer
- Urgency if appropriate
- Risk reversal (guarantee, trial)

---

### Lead Nurture Sequence (Pre-Sale)

**Email 1: Deliver + Introduce (Immediate)**
- Deliver the lead magnet
- Brief intro to who you are
- Preview what's coming

**Email 2: Expand on Topic (Day 2-3)**
- Related insight to lead magnet
- Establish expertise
- Light CTA to content

**Email 3: Problem Deep-Dive (Day 4-5)**
- Articulate their problem deeply
- Show you understand
- Hint at solution

**Email 4: Solution Framework (Day 6-8)**
- Your approach/methodology
- Educational, not salesy
- Builds toward your product

**Email 5: Case Study (Day 9-11)**
- Real results from real customer
- Specific and relatable
- Soft CTA

**Email 6: Differentiation (Day 12-14)**
- Why your approach is different
- Address alternatives
- Build preference

**Email 7: Objection Handler (Day 15-18)**
- Common concern addressed
- FAQ or myth-busting
- Reduce friction

**Email 8: Direct Offer (Day 19-21)**
- Clear pitch
- Strong value proposition
- Specific CTA
- Urgency if available

---

### Re-Engagement Sequence

**Email 1: Check-In (Day 30-60 of inactivity)**
- Subject: Is everything okay, [Name]?
- Genuine concern
- Ask what happened
- Easy win to re-engage

**Email 2: Value Reminder (Day 2-3 after)**
- Subject: Remember when you [achieved X]?
- Remind of past value
- What's new since they left
- Quick CTA

**Email 3: Incentive (Day 5-7 after)**
- Subject: We miss you — here's something special
- Offer if appropriate
- Limited time
- Clear CTA

**Email 4: Last Chance (Day 10-14 after)**
- Subject: Should we stop emailing you?
- Honest and direct
- One-click to stay or go
- Clean the list if no response

---

### Onboarding Sequence (Product Users)

Coordinate with in-app onboarding. Email supports, doesn't duplicate.

**Email 1: Welcome + First Step (Immediate)**
- Confirm signup
- One critical action
- Link directly to that action

**Email 2: Getting Started Help (Day 1)**
- If they haven't completed step 1
- Quick tip or video
- Support option

**Email 3: Feature Highlight (Day 2-3)**
- Key feature they should know
- Specific use case
- In-app link

**Email 4: Success Story (Day 4-5)**
- Customer who succeeded
- Relatable journey
- Motivational

**Email 5: Check-In (Day 7)**
- How's it going?
- Ask for feedback
- Offer help

**Email 6: Advanced Tip (Day 10-12)**
- Power feature
- For engaged users
- Level-up content

**Email 7: Upgrade/Expand (Day 14+)**
- For trial users: conversion push
- For free users: upgrade prompt
- For paid: expansion opportunity

---

## Email Types Reference

A comprehensive guide to lifecycle and campaign emails. Use this as an audit checklist and implementation reference.

### Onboarding Emails

#### New Users Series
**Trigger**: User signs up (free or trial)
**Goal**: Activate user, drive to aha moment
**Typical sequence**: 5-7 emails over 14 days

- Email 1: Welcome + single next step (immediate)
- Email 2: Quick win / getting started (day 1)
- Email 3: Key feature highlight (day 3)
- Email 4: Success story / social proof (day 5)
- Email 5: Check-in + offer help (day 7)
- Email 6: Advanced tip (day 10)
- Email 7: Upgrade prompt or next milestone (day 14)

**Key metrics**: Activation rate, feature adoption

---

#### New Customers Series
**Trigger**: User converts to paid
**Goal**: Reinforce purchase decision, drive adoption, reduce early churn
**Typical sequence**: 3-5 emails over 14 days

- Email 1: Thank you + what's next (immediate)
- Email 2: Getting full value — setup checklist (day 2)
- Email 3: Pro tips for paid features (day 5)
- Email 4: Success story from similar customer (day 7)
- Email 5: Check-in + introduce support resources (day 14)

**Key point**: Different from new user series—they've committed. Focus on reinforcement and expansion, not conversion.

---

#### Key Onboarding Step Reminder
**Trigger**: User hasn't completed critical setup step after X time
**Goal**: Nudge completion of high-value action
**Format**: Single email or 2-3 email mini-sequence

**Example triggers**:
- Hasn't connected integration after 48 hours
- Hasn't invited team member after 3 days
- Hasn't completed profile after 24 hours

**Copy approach**:
- Remind them what they started
- Explain why this step matters
- Make it easy (direct link to complete)
- Offer help if stuck

---

#### New User Invite
**Trigger**: Existing user invites teammate
**Goal**: Activate the invited user
**Recipient**: The person being invited

- Email 1: You've been invited (immediate)
- Email 2: Reminder if not accepted (day 2)
- Email 3: Final reminder (day 5)

**Copy approach**:
- Personalize with inviter's name
- Explain what they're joining
- Single CTA to accept invite
- Social proof optional

---

### Retention Emails

#### Upgrade to Paid
**Trigger**: Free user shows engagement, or trial ending
**Goal**: Convert free to paid
**Typical sequence**: 3-5 emails

**Trigger options**:
- Time-based (trial day 10, 12, 14)
- Behavior-based (hit usage limit, used premium feature)
- Engagement-based (highly active free user)

**Sequence structure**:
- Value summary: What they've accomplished
- Feature comparison: What they're missing
- Social proof: Who else upgraded
- Urgency: Trial ending, limited offer
- Final: Last chance + easy path

---

#### Upgrade to Higher Plan
**Trigger**: User approaching plan limits or using features available on higher tier
**Goal**: Upsell to next tier
**Format**: Single email or 2-3 email sequence

**Trigger examples**:
- 80% of seat limit reached
- 90% of storage/usage limit
- Tried to use higher-tier feature
- Power user behavior patterns

**Copy approach**:
- Acknowledge their growth (positive framing)
- Show what next tier unlocks
- Quantify value vs. cost
- Easy upgrade path

---

#### Ask for Review
**Trigger**: Customer milestone (30/60/90 days, key achievement, support resolution)
**Goal**: Generate social proof on G2, Capterra, app stores
**Format**: Single email

**Best timing**:
- After positive support interaction
- After achieving measurable result
- After renewal
- NOT after billing issues or bugs

**Copy approach**:
- Thank them for being a customer
- Mention specific value/milestone if possible
- Explain why reviews matter (help others decide)
- Direct link to review platform
- Keep it short—this is an ask

---

#### Offer Support Proactively
**Trigger**: Signs of struggle (drop in usage, failed actions, error encounters)
**Goal**: Save at-risk user, improve experience
**Format**: Single email

**Trigger examples**:
- Usage dropped significantly week-over-week
- Multiple failed attempts at action
- Viewed help docs repeatedly
- Stuck at same onboarding step

**Copy approach**:
- Genuine concern tone
- Specific: "I noticed you..." (if data allows)
- Offer direct help (not just link to docs)
- Personal from support or CSM
- No sales pitch—pure help

---

#### Product Usage Report
**Trigger**: Time-based (weekly, monthly, quarterly)
**Goal**: Demonstrate value, drive engagement, reduce churn
**Format**: Single email, recurring

**What to include**:
- Key metrics/activity summary
- Comparison to previous period
- Achievements/milestones
- Suggestions for improvement
- Light CTA to explore more

**Examples**:
- "You saved X hours this month"
- "Your team completed X projects"
- "You're in the top X% of users"

**Key point**: Make them feel good and remind them of value delivered.

---

#### NPS Survey
**Trigger**: Time-based (quarterly) or event-based (post-milestone)
**Goal**: Measure satisfaction, identify promoters and detractors
**Format**: Single email

**Best practices**:
- Keep it simple: Just the NPS question initially
- Follow-up form for "why" based on score
- Personal sender (CEO, founder, CSM)
- Tell them how you'll use feedback

**Follow-up based on score**:
- Promoters (9-10): Thank + ask for review/referral
- Passives (7-8): Ask what would make it a 10
- Detractors (0-6): Personal outreach to understand issues

---

#### Referral Program
**Trigger**: Customer milestone, promoter NPS score, or campaign
**Goal**: Generate referrals
**Format**: Single email or periodic reminders

**Good timing**:
- After positive NPS response
- After customer achieves result
- After renewal
- Seasonal campaigns

**Copy approach**:
- Remind them of their success
- Explain the referral offer clearly
- Make sharing easy (unique link)
- Show what's in it for them AND referee

---

### Billing Emails

#### Switch to Annual
**Trigger**: Monthly subscriber at renewal time or campaign
**Goal**: Convert monthly to annual (improve LTV, reduce churn)
**Format**: Single email or 2-email sequence

**Value proposition**:
- Calculate exact savings
- Additional benefits (if any)
- Lock in current price messaging
- Easy one-click switch

**Best timing**:
- Around monthly renewal date
- End of year / new year
- After 3-6 months of loyalty
- Price increase announcement (lock in old rate)

---

#### Failed Payment Recovery
**Trigger**: Payment fails
**Goal**: Recover revenue, retain customer
**Typical sequence**: 3-4 emails over 7-14 days

**Sequence structure**:
- Email 1 (Day 0): Friendly notice, update payment link
- Email 2 (Day 3): Reminder, service may be interrupted
- Email 3 (Day 7): Urgent, account will be suspended
- Email 4 (Day 10-14): Final notice, what they'll lose

**Copy approach**:
- Assume it's an accident (card expired, etc.)
- Clear, direct, no guilt
- Single CTA to update payment
- Explain what happens if not resolved

**Key metrics**: Recovery rate, time to recovery

---

#### Cancellation Survey
**Trigger**: User cancels subscription
**Goal**: Learn why, opportunity to save
**Format**: Single email (immediate)

**Options**:
- In-app survey at cancellation (better completion)
- Follow-up email if they skip in-app
- Personal outreach for high-value accounts

**Questions to ask**:
- Primary reason for cancelling
- What could we have done better
- Would anything change your mind
- Can we help with transition

**Winback opportunity**: Based on reason, offer targeted save (discount, pause, downgrade, training).

---

#### Upcoming Renewal Reminder
**Trigger**: X days before renewal (14 or 30 days typical)
**Goal**: No surprise charges, opportunity to expand
**Format**: Single email

**What to include**:
- Renewal date and amount
- What's included in renewal
- How to update payment/plan
- Changes to pricing/features (if any)
- Optional: Upsell opportunity

**Required for**: Annual subscriptions, high-value contracts

---

### Usage Emails

#### Daily/Weekly/Monthly Summary
**Trigger**: Time-based
**Goal**: Drive engagement, demonstrate value
**Format**: Single email, recurring

**Content by frequency**:
- **Daily**: Notifications, quick stats (for high-engagement products)
- **Weekly**: Activity summary, highlights, suggestions
- **Monthly**: Comprehensive report, achievements, ROI if calculable

**Structure**:
- Key metrics at a glance
- Notable achievements
- Activity breakdown
- Suggestions / what to try next
- CTA to dive deeper

**Personalization**: Must be relevant to their actual usage. Empty reports are worse than no report.

---

#### Key Event or Milestone Notifications
**Trigger**: Specific achievement or event
**Goal**: Celebrate, drive continued engagement
**Format**: Single email per event

**Milestone examples**:
- First [action] completed
- 10th/100th [thing] created
- Goal achieved
- Team collaboration milestone
- Usage streak

**Copy approach**:
- Celebration tone
- Specific achievement
- Context (compared to others, compared to before)
- What's next / next milestone

---

### Win-Back Emails

#### Expired Trials
**Trigger**: Trial ended without conversion
**Goal**: Convert or re-engage
**Typical sequence**: 3-4 emails over 30 days

**Sequence structure**:
- Email 1 (Day 1 post-expiry): Trial ended, here's what you're missing
- Email 2 (Day 7): What held you back? (gather feedback)
- Email 3 (Day 14): Incentive offer (discount, extended trial)
- Email 4 (Day 30): Final reach-out, door is open

**Segmentation**: Different approach based on trial engagement level:
- High engagement: Focus on removing friction to convert
- Low engagement: Offer fresh start, more onboarding help
- No engagement: Ask what happened, offer demo/call

---

#### Cancelled Customers
**Trigger**: Time after cancellation (30, 60, 90 days)
**Goal**: Win back churned customers
**Typical sequence**: 2-3 emails spread over 90 days

**Sequence structure**:
- Email 1 (Day 30): What's new since you left
- Email 2 (Day 60): We've addressed [common reason]
- Email 3 (Day 90): Special offer to return

**Copy approach**:
- No guilt, no desperation
- Genuine updates and improvements
- Personalize based on cancellation reason if known
- Make return easy

**Key point**: They're more likely to return if their reason was addressed.

---

### Campaign Emails

#### Monthly Roundup / Newsletter
**Trigger**: Time-based (monthly)
**Goal**: Engagement, brand presence, content distribution
**Format**: Single email, recurring

**Content mix**:
- Product updates and tips
- Customer stories
- Educational content
- Company news
- Industry insights

**Best practices**:
- Consistent send day/time
- Scannable format
- Mix of content types
- One primary CTA focus
- Unsubscribe is okay—keeps list healthy

---

#### Seasonal Promotions
**Trigger**: Calendar events (Black Friday, New Year, etc.)
**Goal**: Drive conversions with timely offer
**Format**: Campaign burst (2-4 emails)

**Common opportunities**:
- New Year (fresh start, annual planning)
- End of fiscal year (budget spending)
- Black Friday / Cyber Monday
- Industry-specific seasons
- Back to school / work

**Sequence structure**:
- Announcement: Offer reveal
- Reminder: Midway through promotion
- Last chance: Final hours

---

#### Product Updates
**Trigger**: New feature release
**Goal**: Adoption, engagement, demonstrate momentum
**Format**: Single email per major release

**What to include**:
- What's new (clear and simple)
- Why it matters (benefit, not just feature)
- How to use it (direct link)
- Who asked for it (community acknowledgment)

**Segmentation**: Consider targeting based on relevance:
- Users who would benefit most
- Users who requested feature
- Power users first (for beta feel)

---

#### Industry News Roundup
**Trigger**: Time-based (weekly or monthly)
**Goal**: Thought leadership, engagement, brand value
**Format**: Curated newsletter

**Content**:
- Curated news and links
- Your take / commentary
- What it means for readers
- How your product helps

**Best for**: B2B products where customers care about industry trends.

---

#### Pricing Update
**Trigger**: Price change announcement
**Goal**: Transparent communication, minimize churn
**Format**: Single email (or sequence for major changes)

**Timeline**:
- Announce 30-60 days before change
- Reminder 14 days before
- Final notice 7 days before

**Copy approach**:
- Clear, direct, transparent
- Explain the why (value delivered, costs increased)
- Grandfather if possible (lock in old rate)
- Give options (annual lock-in, downgrade)

**Important**: Honesty and advance notice build trust even when price increases.

---

## Email Audit Checklist

Use this to audit your current email program:

### Onboarding
- [ ] New users series
- [ ] New customers series
- [ ] Key onboarding step reminders
- [ ] New user invite sequence

### Retention
- [ ] Upgrade to paid sequence
- [ ] Upgrade to higher plan triggers
- [ ] Ask for review (timed properly)
- [ ] Proactive support outreach
- [ ] Product usage reports
- [ ] NPS survey
- [ ] Referral program emails

### Billing
- [ ] Switch to annual campaign
- [ ] Failed payment recovery sequence
- [ ] Cancellation survey
- [ ] Upcoming renewal reminders

### Usage
- [ ] Daily/weekly/monthly summaries
- [ ] Key event notifications
- [ ] Milestone celebrations

### Win-Back
- [ ] Expired trial sequence
- [ ] Cancelled customer sequence

### Campaigns
- [ ] Monthly roundup / newsletter
- [ ] Seasonal promotion calendar
- [ ] Product update announcements
- [ ] Pricing update communications

---

## Email Copy Guidelines

### Structure
1. **Hook**: First line grabs attention
2. **Context**: Why this matters to them
3. **Value**: The useful content
4. **CTA**: What to do next
5. **Sign-off**: Human, warm close

### Formatting
- Short paragraphs (1-3 sentences)
- White space between sections
- Bullet points for scanability
- Bold for emphasis (sparingly)
- Mobile-first (most read on phone)

### Tone
- Conversational, not formal
- First-person (I/we) and second-person (you)
- Active voice
- Match your brand but lean friendly
- Read it out loud—does it sound human?

### Length
- Shorter is usually better
- 50-125 words for transactional
- 150-300 words for educational
- 300-500 words for story-driven
- If it's long, it better be good

### CTA Buttons vs. Links
- Buttons: Primary actions, high-visibility
- Links: Secondary actions, in-text
- One clear primary CTA per email
- Button text: Action + outcome

---

## Personalization

### Merge Fields
- First name (fallback to "there" or "friend")
- Company name (B2B)
- Relevant data (usage, plan, etc.)

### Dynamic Content
- Based on segment
- Based on behavior
- Based on stage

### Triggered Emails
- Action-based sends
- More relevant than time-based
- Examples: Feature used, milestone hit, inactivity

---

## Segmentation Strategies

### By Behavior
- Openers vs. non-openers
- Clickers vs. non-clickers
- Active vs. inactive

### By Stage
- Trial vs. paid
- New vs. long-term
- Engaged vs. at-risk

### By Profile
- Industry/role (B2B)
- Use case / goal
- Company size

---

## Testing and Optimization

### What to Test
- Subject lines (highest impact)
- Send times
- Email length
- CTA placement and copy
- Personalization level
- Sequence timing

### How to Test
- A/B test one variable at a time
- Sufficient sample size
- Statistical significance
- Document learnings

### Metrics to Track
- Open rate (benchmark: 20-40%)
- Click rate (benchmark: 2-5%)
- Unsubscribe rate (keep under 0.5%)
- Conversion rate (specific to sequence goal)
- Revenue per email (if applicable)

---

## Output Format

### Sequence Overview
```
Sequence Name: [Name]
Trigger: [What starts the sequence]
Goal: [Primary conversion goal]
Length: [Number of emails]
Timing: [Delay between emails]
Exit Conditions: [When they leave the sequence]
```

### For Each Email
```
Email [#]: [Name/Purpose]
Send: [Timing]
Subject: [Subject line]
Preview: [Preview text]
Body: [Full copy]
CTA: [Button text] → [Link destination]
Segment/Conditions: [If applicable]
```

### Metrics Plan
What to measure and benchmarks

---

## Questions to Ask

If you need more context:
1. What triggers entry to this sequence?
2. What's the primary goal/conversion action?
3. Who is the audience?
4. What do they already know about you?
5. What other emails are they receiving?
6. What's your current email performance?

---

## Related Skills

- **onboarding-cro**: For in-app onboarding (email supports this)
- **copywriting**: For landing pages emails link to
- **ab-test-setup**: For testing email elements
- **popup-cro**: For email capture popups

## When to Use
This skill is applicable to execute the workflow or actions described in the overview.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: email-systems
description: Email has the highest ROI of any marketing channel. $36 for every
  $1 spent. Yet most startups treat it as an afterthought - bulk blasts, no
  personalization, landing in spam folders.
risk: none
source: vibeship-spawner-skills (Apache 2.0)
date_added: 2026-02-27
---

# Email Systems

Email has the highest ROI of any marketing channel. $36 for every $1 spent.
Yet most startups treat it as an afterthought - bulk blasts, no personalization,
landing in spam folders.

This skill covers transactional email that works, marketing automation that
converts, deliverability that reaches inboxes, and the infrastructure decisions
that scale.

## Principles

- Transactional vs Marketing separation | Description: Transactional emails (password reset, receipts) need 100% delivery.
Marketing emails (newsletters, promos) have lower priority. Use separate
IP addresses and providers to protect transactional deliverability. | Examples: Good: Password resets via Postmark, marketing via ConvertKit | Bad: All emails through one SendGrid account
- Permission is everything | Description: Only email people who asked to hear from you. Double opt-in for marketing.
Easy unsubscribe. Clean your list ruthlessly. Bad lists destroy deliverability. | Examples: Good: Confirmed subscription + one-click unsubscribe | Bad: Scraped email list, hidden unsubscribe, bought contacts
- Deliverability is infrastructure | Description: SPF, DKIM, DMARC are not optional. Warm up new IPs. Monitor bounce rates.
Deliverability is earned through technical setup and good behavior. | Examples: Good: All DNS records configured, dedicated IP warmed for 4 weeks | Bad: Using free tier shared IP, no authentication records
- One email, one goal | Description: Each email should have exactly one purpose and one CTA. Multiple asks
means nothing gets clicked. Clear single action. | Examples: Good: "Click here to verify your email" (one button) | Bad: "Verify email, check out our blog, follow us on Twitter, refer a friend..."
- Timing and frequency matter | Description: Wrong time = low open rates. Too frequent = unsubscribes. Let users
set preferences. Test send times. Respect inbox fatigue. | Examples: Good: Weekly digest on Tuesday 10am user's timezone, preference center | Bad: Daily emails at random times, no way to reduce frequency

## Patterns

### Transactional Email Queue

Queue all transactional emails with retry logic and monitoring

**When to use**: Sending any critical email (password reset, receipts, confirmations)

// Don't block request on email send
await queue.add('email', {
  template: 'password-reset',
  to: user.email,
  data: { resetToken, expiresAt }
}, {
  attempts: 3,
  backoff: { type: 'exponential', delay: 2000 }
});

### Email Event Tracking

Track delivery, opens, clicks, bounces, and complaints

**When to use**: Any email campaign or transactional flow

# Track lifecycle:
- Queued: Email entered system
- Sent: Handed to provider
- Delivered: Reached inbox
- Opened: Recipient viewed
- Clicked: Recipient engaged
- Bounced: Permanent failure
- Complained: Marked as spam

### Template Versioning

Version email templates for rollback and A/B testing

**When to use**: Changing production email templates

templates/
  password-reset/
    v1.tsx (current)
    v2.tsx (testing 10%)
    v1-deprecated.tsx (archived)

# Deploy new version gradually
# Monitor metrics before full rollout

### Bounce Handling State Machine

Automatically handle bounces to protect sender reputation

**When to use**: Processing bounce and complaint webhooks

switch (bounceType) {
  case 'hard':
    await markEmailInvalid(email);
    break;
  case 'soft':
    await incrementBounceCount(email);
    if (count >= 3) await markEmailInvalid(email);
    break;
  case 'complaint':
    await unsubscribeImmediately(email);
    break;
}

### React Email Components

Build emails with reusable React components

**When to use**: Creating email templates

import { Button, Html } from '@react-email/components';

export default function WelcomeEmail({ userName }) {
  return (

Welcome {userName}!

      <Button href="https://app.com/start">
        Get Started
      </Button>

  );
}

### Preference Center

Let users control email frequency and topics

**When to use**: Building marketing or notification systems

Preferences:
☑ Product updates (weekly)
☑ New features (monthly)
☐ Marketing promotions
☑ Account notifications (always)

# Respect preferences in all sends
# Required for GDPR compliance

## Sharp Edges

### Missing SPF, DKIM, or DMARC records

Severity: CRITICAL

Situation: Sending emails without authentication. Emails going to spam folder.
Low open rates. No idea why. Turns out DNS records were never set up.

Symptoms:
- Emails going to spam
- Low deliverability rates
- mail-tester.com score below 8
- No DMARC reports received

Why this breaks:
Email authentication (SPF, DKIM, DMARC) tells receiving servers you're
legit. Without them, you look like a spammer. Modern email providers
increasingly require all three.

Recommended fix:

# Required DNS records:

## SPF (Sender Policy Framework)
TXT record: v=spf1 include:_spf.google.com include:sendgrid.net ~all

## DKIM (DomainKeys Identified Mail)
TXT record provided by your email provider
Adds cryptographic signature to emails

## DMARC (Domain-based Message Authentication)
TXT record: v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com

# Verify setup:
- Send test email to mail-tester.com
- Check MXToolbox for record validation
- Monitor DMARC reports

### Using shared IP for transactional email

Severity: HIGH

Situation: Password resets going to spam. Using free tier of email provider.
Some other customer on your shared IP got flagged for spam.
Your reputation is ruined by association.

Symptoms:
- Transactional emails in spam
- Inconsistent delivery
- Using same provider for marketing and transactional

Why this breaks:
Shared IPs share reputation. One bad actor affects everyone. For
critical transactional email, you need your own IP or a provider
with strict shared IP policies.

Recommended fix:

# Transactional email strategy:

## Option 1: Dedicated IP (high volume)
- Get dedicated IP from your provider
- Warm it up slowly (start with 100/day)
- Maintain consistent volume

## Option 2: Transactional-only provider
- Postmark (very strict, great reputation)
- Includes shared pool with high standards

### Separate concerns:
- Transactional: Postmark or Resend
- Marketing: ConvertKit or Customer.io
- Never mix marketing and transactional

### Not processing bounce notifications

Severity: HIGH

Situation: Emailing same dead addresses over and over. Bounce rate climbing.
Email provider threatening to suspend account. List is 40% dead.

Symptoms:
- Bounce rate above 2%
- No webhook handlers for bounces
- Same emails failing repeatedly

Why this breaks:
Bounces damage sender reputation. Email providers track bounce rates.
Above 2% and you start looking like a spammer. Dead addresses must
be removed immediately.

Recommended fix:

# Bounce handling requirements:

### Hard bounces:
Remove immediately on first occurrence
Invalid address, domain doesn't exist

### Soft bounces:
Retry 3 times over 72 hours
After 3 failures, treat as hard bounce

### Implementation:
```typescript
// Webhook handler for bounces
app.post('/webhooks/email', (req, res) => {
  const event = req.body;
  if (event.type === 'bounce') {
    await markEmailInvalid(event.email);
    await removeFromAllLists(event.email);
  }
});
```

### Monitor:
Track bounce rate by campaign
Alert if bounce rate exceeds 1%

### Missing or hidden unsubscribe link

Severity: CRITICAL

Situation: Users marking as spam because they cannot unsubscribe. Spam complaints
rising. CAN-SPAM violation. Email provider suspends account.

Symptoms:
- Hidden unsubscribe links
- Multi-step unsubscribe process
- No List-Unsubscribe header
- High spam complaint rate

Why this breaks:
Users who cannot unsubscribe will mark as spam. Spam complaints hurt
reputation more than unsubscribes. Also it is literally illegal.
CAN-SPAM, GDPR all require clear unsubscribe.

Recommended fix:

# Unsubscribe requirements:

### Visible:
- Above the fold in email footer
- Clear text, not hidden
- Not styled to be invisible

### One-click:
- Link directly unsubscribes
- No login required
- No "are you sure" hoops

### List-Unsubscribe header:
```
List-Unsubscribe: <mailto:unsubscribe@example.com>,
  <https://example.com/unsubscribe?token=xxx>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
```

### Preference center:
Option to reduce frequency instead of full unsubscribe

### Sending HTML without plain text alternative

Severity: MEDIUM

Situation: Some users see blank emails. Spam filters flagging emails. Accessibility
issues for screen readers. Email clients that strip HTML show nothing.

Symptoms:
- No text/plain part in emails
- Blank emails for some users
- Lower engagement in some segments

Why this breaks:
Not everyone can render HTML. Screen readers work better with plain text.
Spam filters are suspicious of HTML-only. Multipart is the standard.

Recommended fix:

# Always send multipart:
```typescript
await resend.emails.send({
  from: 'you@example.com',
  to: 'user@example.com',
  subject: 'Welcome!',
  html: '<h1>Welcome!</h1><p>Thanks for signing up.</p>',
  text: 'Welcome!\n\nThanks for signing up.',
});
```

# Auto-generate text from HTML:
Use html-to-text library as fallback
But hand-crafted plain text is better

# Plain text should be readable:
Not just HTML stripped of tags
Actual formatted text content

### Sending high volume from new IP immediately

Severity: HIGH

Situation: Just switched providers. Started sending 50,000 emails/day immediately.
Massive deliverability issues. New IP has no reputation. Looks like spam.

Symptoms:
- New IP/provider
- Sending high volume immediately
- Sudden deliverability drop

Why this breaks:
New IPs have no reputation. Sending high volume immediately looks
like a spammer who just spun up. You need to gradually build trust.

Recommended fix:

# IP warm-up schedule:

Week 1: 50-100 emails/day
Week 2: 200-500 emails/day
Week 3: 500-1000 emails/day
Week 4: 1000-5000 emails/day
Continue doubling until at volume

# Best practices:
- Start with most engaged users
- Send to Gmail/Microsoft first (they set reputation)
- Maintain consistent volume
- Don't spike and drop

# During warm-up:
- Monitor deliverability closely
- Check feedback loops
- Adjust pace if issues arise

### Emailing people who did not opt in

Severity: CRITICAL

Situation: Bought an email list. Scraped emails from LinkedIn. Added conference
contacts. Spam complaints through the roof. Provider suspends account.
Maybe a lawsuit.

Symptoms:
- Purchased email lists
- Scraped contacts
- High unsubscribe rate on first send
- Spam complaints above 0.1%

Why this breaks:
Permission-based email is not optional. It is the law (CAN-SPAM, GDPR).
It is also effective - unwilling recipients hurt your metrics and
reputation more than they help.

Recommended fix:

# Permission requirements:

### Explicit opt-in:
- User actively chooses to receive email
- Not pre-checked boxes
- Clear what they are signing up for

### Double opt-in:
- Confirmation email with link
- Only add to list after confirmation
- Best practice for marketing lists

### What you cannot do:
- Buy email lists
- Scrape emails from websites
- Add conference contacts without consent
- Use partner/customer lists without consent

### Transactional exception:
Password resets, receipts, account alerts
do not need marketing opt-in

### Emails that are mostly or entirely images

Severity: MEDIUM

Situation: Beautiful designed email that is one big image. Users with images
blocked see nothing. Spam filters flag it. Mobile loading is slow.
No one can copy text.

Symptoms:
- Single image emails
- No text content visible
- Missing or generic alt text
- Low engagement when images blocked

Why this breaks:
Images are blocked by default in many clients. Spam filters are
suspicious of image-only emails. Accessibility suffers. Load times
increase.

Recommended fix:

# Balance images and text:

## 60/40 rule:
- At least 60% text content
- Images for enhancement, not content

### Always include:
- Alt text on every image
- Key message in text, not just image
- Fallback for images-off view

### Test:
- Preview with images disabled
- Should still be usable

# Example:
```html
<img
  src="hero.jpg"
  alt="Save 50% this week - use code SAVE50"
  style="max-width: 100%"
/>
<p>Use code <strong>SAVE50</strong> to save 50% this week.</p>
```

### Missing or default preview text

Severity: MEDIUM

Situation: Inbox shows "View this email in browser" or random HTML as preview.
Lower open rates. First impression wasted on boilerplate.

Symptoms:
- View in browser as preview
- HTML code visible in preview
- No preview component in template

Why this breaks:
Preview text is prime real estate - appears right after subject line.
Default or missing preview text wastes this space. Good preview text
increases open rates 10-30%.

Recommended fix:

# Add explicit preview text:

### In HTML:
```html
<div style="display:none;max-height:0;overflow:hidden;">
  Your preview text here. This appears in inbox preview.
  <!-- Add whitespace to push footer text out -->

</div>
```

### With React Email:
```tsx
<Preview>
  Your preview text here. This appears in inbox preview.
</Preview>
```

### Best practices:
- Complement the subject line
- 40-100 characters optimal
- Create curiosity or value
- Different from first line of email

### Not handling partial send failures

Severity: HIGH

Situation: Sending to 10,000 users. API fails at 3,000. No tracking of what sent.
Either double-send or lose 7,000. No way to know who got the email.

Symptoms:
- No per-recipient send logging
- Cannot tell who received email
- Double-sending issues
- No retry mechanism

Why this breaks:
Bulk sends fail partially. APIs timeout. Rate limits hit. Without
tracking individual send status, you cannot recover gracefully.

Recommended fix:

# Track each send individually:

```typescript
async function sendCampaign(emails: string[]) {
  const results = await Promise.allSettled(
    emails.map(async (email) => {
      try {
        const result = await resend.emails.send({ to: email, ... });
        await db.emailLog.create({
          email,
          status: 'sent',
          messageId: result.id,
        });
        return result;
      } catch (error) {
        await db.emailLog.create({
          email,
          status: 'failed',
          error: error.message,
        });
        throw error;
      }
    })
  );

  const failed = results.filter(r => r.status === 'rejected');
  // Retry failed sends or alert
}
```

# Best practices:
- Log every send attempt
- Include message ID for tracking
- Build retry queue for failures
- Monitor success rate per campaign

## Validation Checks

### Missing plain text email part

Severity: WARNING

Emails should always include a plain text alternative

Message: Email being sent with HTML but no plain text part. Add 'text:' property for accessibility and deliverability.

### Hardcoded from email address

Severity: WARNING

From addresses should come from environment variables

Message: From email appears hardcoded. Use environment variable for flexibility.

### Missing bounce webhook handler

Severity: WARNING

Email bounces should be handled to maintain list hygiene

Message: Email provider used but no bounce handling detected. Implement webhook handler for bounces.

### Missing List-Unsubscribe header

Severity: INFO

Marketing emails should include List-Unsubscribe header

Message: Marketing email detected without List-Unsubscribe header. Add header for better deliverability.

### Synchronous email send in request handler

Severity: WARNING

Email sends should be queued, not blocking

Message: Email sent synchronously in request handler. Consider queuing for better reliability.

### Email send without retry logic

Severity: INFO

Email sends should have retry mechanism for failures

Message: Email send without apparent retry logic. Add retry for transient failures.

### Email API key in code

Severity: ERROR

API keys should come from environment variables

Message: Email API key appears hardcoded in source code. Use environment variable.

### Bulk email without rate limiting

Severity: WARNING

Bulk sends should respect provider rate limits

Message: Bulk email sending without apparent rate limiting. Add throttling to avoid hitting limits.

### Email without preview text

Severity: INFO

Emails should include preview/preheader text

Message: Email template without preview text. Add hidden preheader for inbox preview.

### Email send without logging

Severity: WARNING

Email sends should be logged for debugging and auditing

Message: Email being sent without apparent logging. Log sends for debugging and compliance.

## Collaboration

### Delegation Triggers

- copy|subject|messaging|content -> copywriting (Email needs copy)
- design|template|visual|layout -> ui-design (Email needs design)
- track|analytics|measure|metrics -> analytics-architecture (Email needs tracking)
- infrastructure|deploy|server|queue -> devops (Email needs infrastructure)

### Email Marketing Stack

Skills: email-systems, copywriting, marketing, analytics-architecture

Workflow:

```
1. Infrastructure setup (email-systems)
2. Template creation (email-systems)
3. Copy writing (copywriting)
4. Campaign launch (marketing)
5. Performance tracking (analytics-architecture)
```

### Transactional Email

Skills: email-systems, backend, devops

Workflow:

```
1. Provider setup (email-systems)
2. Template coding (email-systems)
3. Queue integration (backend)
4. Monitoring (devops)
```

## When to Use
Use this skill when the request clearly matches the capabilities and patterns described above.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: embedding-strategies
description: "Guide to selecting and optimizing embedding models for vector search applications."
risk: critical
source: community
date_added: "2026-02-27"
---

# Embedding Strategies

Guide to selecting and optimizing embedding models for vector search applications.

## Do not use this skill when

- The task is unrelated to embedding strategies
- You need a different domain or tool outside this scope

## Instructions

- Clarify goals, constraints, and required inputs.
- Apply relevant best practices and validate outcomes.
- Provide actionable steps and verification.
- If detailed examples are required, open `resources/implementation-playbook.md`.

## Use this skill when

- Choosing embedding models for RAG
- Optimizing chunking strategies
- Fine-tuning embeddings for domains
- Comparing embedding model performance
- Reducing embedding dimensions
- Handling multilingual content

## Core Concepts

### 1. Embedding Model Comparison

| Model | Dimensions | Max Tokens | Best For |
|-------|------------|------------|----------|
| **text-embedding-3-large** | 3072 | 8191 | High accuracy |
| **text-embedding-3-small** | 1536 | 8191 | Cost-effective |
| **voyage-2** | 1024 | 4000 | Code, legal |
| **bge-large-en-v1.5** | 1024 | 512 | Open source |
| **all-MiniLM-L6-v2** | 384 | 256 | Fast, lightweight |
| **multilingual-e5-large** | 1024 | 512 | Multi-language |

### 2. Embedding Pipeline

```
Document → Chunking → Preprocessing → Embedding Model → Vector
                ↓
        [Overlap, Size]  [Clean, Normalize]  [API/Local]
```

## Templates

### Template 1: OpenAI Embeddings

```python
from openai import OpenAI
from typing import List
import numpy as np

client = OpenAI()

def get_embeddings(
    texts: List[str],
    model: str = "text-embedding-3-small",
    dimensions: int = None
) -> List[List[float]]:
    """Get embeddings from OpenAI."""
    # Handle batching for large lists
    batch_size = 100
    all_embeddings = []

    for i in range(0, len(texts), batch_size):
        batch = texts[i:i + batch_size]

        kwargs = {"input": batch, "model": model}
        if dimensions:
            kwargs["dimensions"] = dimensions

        response = client.embeddings.create(**kwargs)
        embeddings = [item.embedding for item in response.data]
        all_embeddings.extend(embeddings)

    return all_embeddings

def get_embedding(text: str, **kwargs) -> List[float]:
    """Get single embedding."""
    return get_embeddings([text], **kwargs)[0]

# Dimension reduction with OpenAI
def get_reduced_embedding(text: str, dimensions: int = 512) -> List[float]:
    """Get embedding with reduced dimensions (Matryoshka)."""
    return get_embedding(
        text,
        model="text-embedding-3-small",
        dimensions=dimensions
    )
```

### Template 2: Local Embeddings with Sentence Transformers

```python
from sentence_transformers import SentenceTransformer
from typing import List, Optional
import numpy as np

class LocalEmbedder:
    """Local embedding with sentence-transformers."""

    def __init__(
        self,
        model_name: str = "BAAI/bge-large-en-v1.5",
        device: str = "cuda"
    ):
        self.model = SentenceTransformer(model_name, device=device)

    def embed(
        self,
        texts: List[str],
        normalize: bool = True,
        show_progress: bool = False
    ) -> np.ndarray:
        """Embed texts with optional normalization."""
        embeddings = self.model.encode(
            texts,
            normalize_embeddings=normalize,
            show_progress_bar=show_progress,
            convert_to_numpy=True
        )
        return embeddings

    def embed_query(self, query: str) -> np.ndarray:
        """Embed a query with BGE-style prefix."""
        # BGE models benefit from query prefix
        if "bge" in self.model.get_sentence_embedding_dimension():
            query = f"Represent this sentence for searching relevant passages: {query}"
        return self.embed([query])[0]

    def embed_documents(self, documents: List[str]) -> np.ndarray:
        """Embed documents for indexing."""
        return self.embed(documents)

# E5 model with instructions
class E5Embedder:
    def __init__(self, model_name: str = "intfloat/multilingual-e5-large"):
        self.model = SentenceTransformer(model_name)

    def embed_query(self, query: str) -> np.ndarray:
        return self.model.encode(f"query: {query}")

    def embed_document(self, document: str) -> np.ndarray:
        return self.model.encode(f"passage: {document}")
```

### Template 3: Chunking Strategies

```python
from typing import List, Tuple
import re

def chunk_by_tokens(
    text: str,
    chunk_size: int = 512,
    chunk_overlap: int = 50,
    tokenizer=None
) -> List[str]:
    """Chunk text by token count."""
    import tiktoken
    tokenizer = tokenizer or tiktoken.get_encoding("cl100k_base")

    tokens = tokenizer.encode(text)
    chunks = []

    start = 0
    while start < len(tokens):
        end = start + chunk_size
        chunk_tokens = tokens[start:end]
        chunk_text = tokenizer.decode(chunk_tokens)
        chunks.append(chunk_text)
        start = end - chunk_overlap

    return chunks

def chunk_by_sentences(
    text: str,
    max_chunk_size: int = 1000,
    min_chunk_size: int = 100
) -> List[str]:
    """Chunk text by sentences, respecting size limits."""
    import nltk
    sentences = nltk.sent_tokenize(text)

    chunks = []
    current_chunk = []
    current_size = 0

    for sentence in sentences:
        sentence_size = len(sentence)

        if current_size + sentence_size > max_chunk_size and current_chunk:
            chunks.append(" ".join(current_chunk))
            current_chunk = []
            current_size = 0

        current_chunk.append(sentence)
        current_size += sentence_size

    if current_chunk:
        chunks.append(" ".join(current_chunk))

    return chunks

def chunk_by_semantic_sections(
    text: str,
    headers_pattern: str = r'^#{1,3}\s+.+$'
) -> List[Tuple[str, str]]:
    """Chunk markdown by headers, preserving hierarchy."""
    lines = text.split('\n')
    chunks = []
    current_header = ""
    current_content = []

    for line in lines:
        if re.match(headers_pattern, line, re.MULTILINE):
            if current_content:
                chunks.append((current_header, '\n'.join(current_content)))
            current_header = line
            current_content = []
        else:
            current_content.append(line)

    if current_content:
        chunks.append((current_header, '\n'.join(current_content)))

    return chunks

def recursive_character_splitter(
    text: str,
    chunk_size: int = 1000,
    chunk_overlap: int = 200,
    separators: List[str] = None
) -> List[str]:
    """LangChain-style recursive splitter."""
    separators = separators or ["\n\n", "\n", ". ", " ", ""]

    def split_text(text: str, separators: List[str]) -> List[str]:
        if not text:
            return []

        separator = separators[0]
        remaining_separators = separators[1:]

        if separator == "":
            # Character-level split
            return [text[i:i+chunk_size] for i in range(0, len(text), chunk_size - chunk_overlap)]

        splits = text.split(separator)
        chunks = []
        current_chunk = []
        current_length = 0

        for split in splits:
            split_length = len(split) + len(separator)

            if current_length + split_length > chunk_size and current_chunk:
                chunk_text = separator.join(current_chunk)

                # Recursively split if still too large
                if len(chunk_text) > chunk_size and remaining_separators:
                    chunks.extend(split_text(chunk_text, remaining_separators))
                else:
                    chunks.append(chunk_text)

                # Start new chunk with overlap
                overlap_splits = []
                overlap_length = 0
                for s in reversed(current_chunk):
                    if overlap_length + len(s) <= chunk_overlap:
                        overlap_splits.insert(0, s)
                        overlap_length += len(s)
                    else:
                        break
                current_chunk = overlap_splits
                current_length = overlap_length

            current_chunk.append(split)
            current_length += split_length

        if current_chunk:
            chunks.append(separator.join(current_chunk))

        return chunks

    return split_text(text, separators)
```

### Template 4: Domain-Specific Embedding Pipeline

```python
class DomainEmbeddingPipeline:
    """Pipeline for domain-specific embeddings."""

    def __init__(
        self,
        embedding_model: str = "text-embedding-3-small",
        chunk_size: int = 512,
        chunk_overlap: int = 50,
        preprocessing_fn=None
    ):
        self.embedding_model = embedding_model
        self.chunk_size = chunk_size
        self.chunk_overlap = chunk_overlap
        self.preprocess = preprocessing_fn or self._default_preprocess

    def _default_preprocess(self, text: str) -> str:
        """Default preprocessing."""
        # Remove excessive whitespace
        text = re.sub(r'\s+', ' ', text)
        # Remove special characters
        text = re.sub(r'[^\w\s.,!?-]', '', text)
        return text.strip()

    async def process_documents(
        self,
        documents: List[dict],
        id_field: str = "id",
        content_field: str = "content",
        metadata_fields: List[str] = None
    ) -> List[dict]:
        """Process documents for vector storage."""
        processed = []

        for doc in documents:
            content = doc[content_field]
            doc_id = doc[id_field]

            # Preprocess
            cleaned = self.preprocess(content)

            # Chunk
            chunks = chunk_by_tokens(
                cleaned,
                self.chunk_size,
                self.chunk_overlap
            )

            # Create embeddings
            embeddings = get_embeddings(chunks, self.embedding_model)

            # Create records
            for i, (chunk, embedding) in enumerate(zip(chunks, embeddings)):
                record = {
                    "id": f"{doc_id}_chunk_{i}",
                    "document_id": doc_id,
                    "chunk_index": i,
                    "text": chunk,
                    "embedding": embedding
                }

                # Add metadata
                if metadata_fields:
                    for field in metadata_fields:
                        if field in doc:
                            record[field] = doc[field]

                processed.append(record)

        return processed

# Code-specific pipeline
class CodeEmbeddingPipeline:
    """Specialized pipeline for code embeddings."""

    def __init__(self, model: str = "voyage-code-2"):
        self.model = model

    def chunk_code(self, code: str, language: str) -> List[dict]:
        """Chunk code by functions/classes."""
        import tree_sitter

        # Parse with tree-sitter
        # Extract functions, classes, methods
        # Return chunks with context
        pass

    def embed_with_context(self, chunk: str, context: str) -> List[float]:
        """Embed code with surrounding context."""
        combined = f"Context: {context}\n\nCode:\n{chunk}"
        return get_embedding(combined, model=self.model)
```

### Template 5: Embedding Quality Evaluation

```python
import numpy as np
from typing import List, Tuple

def evaluate_retrieval_quality(
    queries: List[str],
    relevant_docs: List[List[str]],  # List of relevant doc IDs per query
    retrieved_docs: List[List[str]],  # List of retrieved doc IDs per query
    k: int = 10
) -> dict:
    """Evaluate embedding quality for retrieval."""

    def precision_at_k(relevant: set, retrieved: List[str], k: int) -> float:
        retrieved_k = retrieved[:k]
        relevant_retrieved = len(set(retrieved_k) & relevant)
        return relevant_retrieved / k

    def recall_at_k(relevant: set, retrieved: List[str], k: int) -> float:
        retrieved_k = retrieved[:k]
        relevant_retrieved = len(set(retrieved_k) & relevant)
        return relevant_retrieved / len(relevant) if relevant else 0

    def mrr(relevant: set, retrieved: List[str]) -> float:
        for i, doc in enumerate(retrieved):
            if doc in relevant:
                return 1 / (i + 1)
        return 0

    def ndcg_at_k(relevant: set, retrieved: List[str], k: int) -> float:
        dcg = sum(
            1 / np.log2(i + 2) if doc in relevant else 0
            for i, doc in enumerate(retrieved[:k])
        )
        ideal_dcg = sum(1 / np.log2(i + 2) for i in range(min(len(relevant), k)))
        return dcg / ideal_dcg if ideal_dcg > 0 else 0

    metrics = {
        f"precision@{k}": [],
        f"recall@{k}": [],
        "mrr": [],
        f"ndcg@{k}": []
    }

    for relevant, retrieved in zip(relevant_docs, retrieved_docs):
        relevant_set = set(relevant)
        metrics[f"precision@{k}"].append(precision_at_k(relevant_set, retrieved, k))
        metrics[f"recall@{k}"].append(recall_at_k(relevant_set, retrieved, k))
        metrics["mrr"].append(mrr(relevant_set, retrieved))
        metrics[f"ndcg@{k}"].append(ndcg_at_k(relevant_set, retrieved, k))

    return {name: np.mean(values) for name, values in metrics.items()}

def compute_embedding_similarity(
    embeddings1: np.ndarray,
    embeddings2: np.ndarray,
    metric: str = "cosine"
) -> np.ndarray:
    """Compute similarity matrix between embedding sets."""
    if metric == "cosine":
        # Normalize
        norm1 = embeddings1 / np.linalg.norm(embeddings1, axis=1, keepdims=True)
        norm2 = embeddings2 / np.linalg.norm(embeddings2, axis=1, keepdims=True)
        return norm1 @ norm2.T
    elif metric == "euclidean":
        from scipy.spatial.distance import cdist
        return -cdist(embeddings1, embeddings2, metric='euclidean')
    elif metric == "dot":
        return embeddings1 @ embeddings2.T
```

## Best Practices

### Do's
- **Match model to use case** - Code vs prose vs multilingual
- **Chunk thoughtfully** - Preserve semantic boundaries
- **Normalize embeddings** - For cosine similarity
- **Batch requests** - More efficient than one-by-one
- **Cache embeddings** - Avoid recomputing

### Don'ts
- **Don't ignore token limits** - Truncation loses info
- **Don't mix embedding models** - Incompatible spaces
- **Don't skip preprocessing** - Garbage in, garbage out
- **Don't over-chunk** - Lose context

## Resources

- [OpenAI Embeddings](https://platform.openai.com/docs/guides/embeddings)
- [Sentence Transformers](https://www.sbert.net/)
- [MTEB Benchmark](https://huggingface.co/spaces/mteb/leaderboard)

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: emblemai-crypto-wallet
description: "Crypto wallet management across 7 blockchains via EmblemAI Agent Hustle API. Balance checks, token swaps, portfolio analysis, and transaction execution for Solana, Ethereum, Base, BSC, Polygon, Hedera, and Bitcoin."
risk: critical
source: "EmblemCompany/Agent-skills (MIT)"
date_added: "2026-03-06"
---

# EmblemAI Crypto Wallet

You manage crypto wallets through the EmblemAI Agent Hustle API. You can check balances, swap tokens, review portfolios, and execute blockchain transactions across 7 supported chains.

## When to Use
- User wants to check crypto wallet balances
- User wants to swap or trade tokens
- User wants portfolio analysis or token research
- User wants to interact with DeFi protocols
- User needs cross-chain wallet operations

## Setup

Install the full skill with references and scripts:

```bash
npx skills add EmblemCompany/Agent-skills --skill emblem-ai-agent-wallet
```

Or install the npm package directly:

```bash
npm install @emblemvault/agentwallet
```

## Supported Chains

| Chain | Operations |
|-------|-----------|
| Solana | Balance, swap, transfer, token lookup |
| Ethereum | Balance, swap, transfer, NFT |
| Base | Balance, swap, transfer |
| BSC | Balance, swap, transfer |
| Polygon | Balance, swap, transfer |
| Hedera | Balance, transfer |
| Bitcoin | Balance, transfer |

## API Integration

Base URL: `https://api.agenthustle.ai`

Authentication requires an API key passed as `x-api-key` header.

### Core Endpoints

- `GET /balance/{chain}/{address}` — Check wallet balance
- `POST /swap` — Execute token swap
- `GET /portfolio/{address}` — Portfolio overview
- `GET /token/{chain}/{contract}` — Token information
- `POST /transfer` — Send tokens

## Key Behaviors

1. **Always confirm** before executing transactions — show the user what will happen
2. **Check balances first** before attempting swaps or transfers
3. **Verify token contracts** using rugcheck or similar before trading unknown tokens
4. **Report gas estimates** when available
5. **Never expose private keys** — all signing happens server-side via vault

## Links

- [Full skill with references](https://github.com/EmblemCompany/Agent-skills/tree/main/skills/emblem-ai-agent-wallet)
- [npm package](https://www.npmjs.com/package/@emblemvault/agentwallet)
- [EmblemAI](https://agenthustle.ai)

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: emergency-card
description: 生成紧急情况下快速访问的医疗信息摘要卡片。当用户需要旅行、就诊准备、紧急情况或询问"紧急信息"、"医疗卡片"、"急救信息"时使用此技能。提取关键信息（过敏、用药、急症、植入物），支持多格式输出（JSON、文本、二维码），用于急救或快速就医。
risk: critical
source: community
---

# 紧急医疗信息卡生成器

生成紧急情况下快速访问的医疗信息摘要，用于急救或就医。

## 核心功能

### 1. 紧急信息提取
从用户的健康数据中提取最关键的信息：
- **严重过敏**：优先提取4级（过敏性休克）和3级过敏
- **当前用药**：活跃药物的名称、剂量、频率
- **急症情况**：需要紧急处理的医疗状况
- **植入物**：心脏起搏器、支架等（影响检查和治疗）
- **紧急联系人**：快速联系的家属信息

### 2. 信息优先级排序
按照医疗紧急程度对信息排序：
1. **P0 - 危急信息**：过敏性休克、严重药物过敏、危及生命的疾病
2. **P1 - 重要信息**：当前用药、慢性病、植入物
3. **P2 - 一般信息**：血型、年龄、体重、最近检查

### 3. 多格式输出
支持多种输出格式以适应不同场景：
- **HTML格式**：可打印网页，使用Tailwind CSS和Lucide图标（推荐）
- **JSON格式**：结构化数据，便于系统集成
- **文本格式**：简洁可读，适合打印携带
- **PDF格式**：专业打印，适合长期保存

#### HTML格式（新增）
生成独立的HTML文件，包含：
- Tailwind CSS样式（通过CDN）
- Lucide图标（通过CDN）
- 响应式设计
- 打印优化
- 多种尺寸变体（A4、钱包卡、大字版）
- 自动卡片类型检测（标准、儿童、老年、严重过敏）

使用方式：
```bash
# 生成标准卡片
python scripts/generate_emergency_card.py

# 指定卡片类型
python scripts/generate_emergency_card.py standard
python scripts/generate_emergency_card.py child
python scripts/generate_emergency_card.py elderly
python scripts/generate_emergency_card.py severe

# 指定打印尺寸
python scripts/generate_emergency_card.py standard a4       # A4标准
python scripts/generate_emergency_card.py standard wallet   # 钱包卡
python scripts/generate_emergency_card.py standard large    # 大字版（老年）
```

输出文件：`emergency-cards/emergency-card-{variant}-{YYYY-MM-DD}.html`

### 4. 离线可用
- 支持手机保存（相册、文件）
- 支持打印携带（钱包、包）
- 支持云端备份（可选）

## 使用说明

### 触发条件
当用户提到以下场景时，使用此技能：
- ✅ "生成紧急医疗信息卡"
- ✅ "我需要旅行，如何快速提供医疗信息"
- ✅ "把我的过敏信息整理成卡片"
- ✅ "紧急情况急救信息"
- ✅ "就医准备资料"
- ✅ "医疗信息摘要"

### 执行步骤

#### 步骤 1: 读取用户基础数据
从以下数据源读取信息：

```javascript
// 1. 用户档案
const profile = readFile('data/profile.json');

// 2. 过敏史
const allergies = readFile('data/allergies.json');

// 3. 当前用药
const medications = readFile('data/medications/medications.json');

// 4. 辐射记录
const radiation = readFile('data/radiation-records.json');

// 5. 手术记录（查找植入物）
const surgeries = glob('data/手术记录/**/*.json');

// 6. 出院小结（查找急症）
const dischargeSummaries = glob('data/出院小结/**/*.json');
```

#### 步骤 2: 提取关键信息

##### 2.1 基础信息
```javascript
const basicInfo = {
  name: profile.basic_info?.name || "未设置",
  age: calculateAge(profile.basic_info?.birth_date),
  gender: profile.basic_info?.gender || "未设置",
  blood_type: profile.basic_info?.blood_type || "未知",
  weight: `${profile.basic_info?.weight} ${profile.basic_info?.weight_unit}`,
  height: `${profile.basic_info?.height} ${profile.basic_info?.height_unit}`,
  bmi: profile.calculated?.bmi,
  emergency_contacts: profile.emergency_contacts || []
};
```

#### 2.2 严重过敏
```javascript
// 过滤出3-4级严重过敏
const criticalAllergies = allergies.allergies
  .filter(a => a.severity_level >= 3 && a.current_status.status === 'active')
  .map(a => ({
    allergen: a.allergen.name,
    severity: `过敏${getSeverityLabel(a.severity_level)}（${a.severity_level}级）`,
    reaction: a.reaction_description,
    diagnosed_date: a.diagnosis_date
  }));
```

#### 2.3 慢性疾病诊断（新增）
```javascript
// 从慢性病管理数据中提取诊断信息
const chronicConditions = [];

// 高血压
try {
  const hypertensionData = readFile('data/hypertension-tracker.json');
  if (hypertensionData.hypertension_management?.diagnosis_date) {
    chronicConditions.push({
      condition: '高血压',
      diagnosis_date: hypertensionData.hypertension_management.diagnosis_date,
      classification: hypertensionData.hypertension_management.classification,
      current_bp: hypertensionData.hypertension_management.average_bp,
      risk_level: hypertensionData.hypertension_management.cardiovascular_risk?.risk_level
    });
  }
} catch (e) {
  // 文件不存在或读取失败，跳过
}

// 糖尿病
try {
  const diabetesData = readFile('data/diabetes-tracker.json');
  if (diabetesData.diabetes_management?.diagnosis_date) {
    chronicConditions.push({
      condition: diabetesData.diabetes_management.type === 'type_1' ? '1型糖尿病' : '2型糖尿病',
      diagnosis_date: diabetesData.diabetes_management.diagnosis_date,
      duration_years: diabetesData.diabetes_management.duration_years,
      hba1c: diabetesData.diabetes_management.hba1c?.history?.[0]?.value,
      control_status: diabetesData.diabetes_management.hba1c?.achievement ? '控制良好' : '需改善'
    });
  }
} catch (e) {
  // 文件不存在或读取失败，跳过
}

// COPD
try {
  const copdData = readFile('data/copd-tracker.json');
  if (copdData.copd_management?.diagnosis_date) {
    chronicConditions.push({
      condition: '慢阻肺（COPD）',
      diagnosis_date: copdData.copd_management.diagnosis_date,
      gold_grade: `GOLD ${copdData.copd_management.gold_grade}级`,
      cat_score: copdData.copd_management.symptom_assessment?.cat_score?.total_score,
      exacerbations_last_year: copdData.copd_management.exacerbations?.last_year
    });
  }
} catch (e) {
  // 文件不存在或读取失败，跳过
}
```

#### 2.4 当前用药
```javascript
// 只包含活跃的药物
const currentMedications = medications.medications
  .filter(m => m.active === true)
  .map(m => ({
    name: m.name,
    dosage: `${m.dosage.value}${m.dosage.unit}`,
    frequency: getFrequencyLabel(m.frequency),
    instructions: m.instructions,
    warnings: m.warnings || []
  }));
```

##### 2.4 医疗状况
从出院小结中提取诊断信息：
```javascript
const medicalConditions = dischargeSummaries
  .flatMap(ds => {
    const data = readFile(ds.file_path);
    return data.diagnoses || [];
  })
  .map(d => ({
    condition: d.condition,
    diagnosis_date: d.date,
    status: d.status || "随访中"
  }));
```

##### 2.5 植入物
从手术记录中提取植入物信息：
```javascript
const implants = surgeries
  .flatMap(s => {
    const data = readFile(s.file_path);
    return data.procedure?.implants || [];
  })
  .map(i => ({
    type: i.type,
    implant_date: i.date,
    hospital: i.hospital,
    notes: i.notes
  }));
```

##### 2.6 近期辐射暴露
```javascript
const recentRadiation = {
  total_dose_last_year: calculateTotalDose(radiation.records, 'last_year'),
  last_exam: radiation.records[radiation.records.length - 1]
};
```

#### 步骤 3: 生成信息卡片

按照优先级组织信息：
```javascript
const emergencyCard = {
  version: "1.0",
  generated_at: new Date().toISOString(),
  basic_info: basicInfo,
  critical_allergies: criticalAllergies.sort(bySeverityDesc),
  current_medications: currentMedications,
  medical_conditions: [...medicalConditions, ...chronicConditions], // 合并急症和慢性病
  implants: implants,
  recent_radiation_exposure: recentRadiation,
  disclaimer: "此信息卡仅供参考，不替代专业医疗诊断",
  data_source: "my-his个人健康信息系统",
  chronic_conditions: chronicConditions // 单独字段便于访问
};
```

#### 步骤 4: 格式化输出

##### JSON格式
直接输出结构化JSON数据。

##### 文本格式
生成易读的文本卡片：
```
╔═══════════════════════════════════════════════════════════╗
║                  紧急医疗信息卡                          ║
╠═══════════════════════════════════════════════════════════╣
║ 姓名：张三                      年龄：35岁               ║
║ 血型：A+                       体重：70kg                ║
╠═══════════════════════════════════════════════════════════╣
║ 🆘 严重过敏                                              ║
║ ─────────────────────────────────────────────────────── ║
║ • 青霉素 - 过敏性休克（4级）🆘                          ║
║   反应：呼吸困难、喉头水肿、意识丧失                     ║
╠═══════════════════════════════════════════════════════════╣
║ 💊 当前用药                                              ║
║ ─────────────────────────────────────────────────────── ║
║ • 氨氯地平 5mg - 每日1次（高血压）                      ║
║ • 二甲双胍 1000mg - 每日2次（糖尿病）                    ║
╠═══════════════════════════════════════════════════════════╣
║ 🏥 慢性疾病                                              ║
║ ─────────────────────────────────────────────────────── ║
║ • 高血压（2023-01-01诊断，1级，控制中）                 ║
║   平均血压：132/82 mmHg                                 ║
║ • 2型糖尿病（2022-05-10诊断，HbA1c 6.8%）              ║
║   控制状态：良好                                        ║
║ • 慢阻肺（2020-03-15诊断，GOLD 2级）                    ║
║   CAT评分：18分                                        ║
╠═══════════════════════════════════════════════════════════╣
║ 🏥 其他疾病                                              ║
║ ─────────────────────────────────────────────────────── ║
║ （其他急症或手术诊断，如有）                            ║
╠═══════════════════════════════════════════════════════════╣
║ 📿 植入物                                                ║
║ ─────────────────────────────────────────────────────── ║
║ • 心脏起搏器（2022-06-10植入）                           ║
║   医院：XX医院                                           ║
║   注意：定期复查，避免MRI检查                            ║
╠═══════════════════════════════════════════════════════════╣
║ 📞 紧急联系人                                            ║
║ ─────────────────────────────────────────────────────── ║
║ • 李四（配偶）- 138****1234                              ║
╠═══════════════════════════════════════════════════════════╣
║ ⚠  免责声明                                            ║
║ 此信息卡仅供参考，不替代专业医疗诊断                     ║
║ 生成时间：2025-12-31 12:34:56                            ║
╚═══════════════════════════════════════════════════════════╝
```

##### 二维码格式
将JSON数据转换为二维码图片：
```javascript
const qrCode = generateQRCode(JSON.stringify(emergencyCard));
emergencyCard.qr_code = qrCode;
```

#### 步骤 5: 保存文件

根据用户选择的格式保存文件：
```javascript
// JSON格式
saveFile('emergency-card.json', JSON.stringify(emergencyCard, null, 2));

// 文本格式
saveFile('emergency-card.txt', generateTextCard(emergencyCard));

// 二维码格式
saveFile('emergency-card-qr.png', emergencyCard.qr_code);
```

#### 步骤 6: 输出确认信息

```
✅ 紧急医疗信息卡已生成

文件位置：data/emergency-cards/emergency-card-2025-12-31.json
生成时间：2025-12-31 12:34:56

包含信息：
━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ 基础信息（姓名、年龄、血型）
✓ 严重过敏（1项4级过敏）
✓ 当前用药（2种药物）
✓ 医疗状况（2种疾病）
✓ 植入物（1项）
✓ 紧急联系人（1人）

💡 使用建议：
━━━━━━━━━━━━━━━━━━━━━━━━━━
• 将JSON文件保存到手机云盘
• 将二维码保存到手机相册
• 打印文本版随身携带
• 旅行前更新信息

⚠  注意事项：
━━━━━━━━━━━━━━━━━━━━━━━━━━
• 此信息卡仅供参考，不替代专业医疗诊断
• 定期更新（建议每3个月或健康信息变化后）
• 如有严重过敏，请随身携带过敏急救卡
```

## 数据源

### 主要数据源
- **data/profile.json**：用户基础信息、血型、紧急联系人
- **data/allergies.json**：过敏史和严重程度分级
- **data/medications/medications.json**：当前用药计划和剂量

### 慢性病数据源（新增）
- **data/hypertension-tracker.json**：高血压管理数据（诊断日期、分级、血压控制、靶器官损害、心血管风险）
- **data/diabetes-tracker.json**：糖尿病管理数据（类型、HbA1c、血糖控制、并发症筛查）
- **data/copd-tracker.json**：COPD管理数据（GOLD分级、CAT评分、急性加重史、肺功能）

### 辅助数据源
- **data/radiation-records.json**：近期辐射暴露记录
- **data/手术记录/**/*.json**：手术植入物信息
- **data/出院小结/**/*.json**：医疗诊断信息

### 可选数据源
- **data/index.json**：全局数据索引

## 安全性原则

### 必须遵循
- ❌ 不添加用药建议（仅列出当前用药）
- ❌ 不提供诊断结论（仅列出已知诊断）
- ❌ 不给出治疗建议（不替代医生）
- ❌ 标注免责声明（仅供参考）

### 信息准确度
- ✅ 仅提取已记录的信息（不推测或推断）
- ✅ 标注信息来源和更新时间
- ✅ 建议定期更新信息

### 隐私保护
- ✅ 敏感信息可选隐藏
- ✅ 电话号码部分隐藏（如：138****1234）
- ✅ 所有数据仅保存在本地

## 错误处理

### 数据缺失
- **过敏数据缺失**：输出"未记录过敏史"
- **用药数据缺失**：输出"未记录当前用药"
- **植入物数据缺失**：输出"无植入物"

### 文件读取失败
- **无法读取profile.json**：使用默认值（姓名：未设置）
- **无法读取allergies.json**：跳过过敏信息
- **继续生成其他信息**：不因单个文件失败而中断

### 二维码生成失败
- 降级为文本格式输出
- 提示用户手动记录信息

## 示例输出

完整示例请参考相关文档。

## 测试数据

测试数据请参考相关文档。

## 格式说明

详细格式请参考相关文档。

## When to Use
Use this skill when tackling tasks related to its primary domain or functionality as described above.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.