Outbound Server
Overview
The Outbound Server specializes in analyzing outbound campaign engagement data. It helps you understand email campaign performance, reply rates, contact engagement, and identify accounts for outbound campaigns.
Server Details
- Server Name:
outbound-server - Version: 0.0.1
- Endpoint:
/mcp/outbound - Authentication: Organization-level required
Purpose
Analyze outbound email campaigns, track engagement metrics (opens, clicks, replies), measure campaign performance, and identify accounts that should be added to campaigns or have been contacted.
Available Tools
1. engagements-schema-tool
Purpose: Get field mappings for the Engagements index
When to use: Before constructing queries to understand available fields
Returns: Elasticsearch mapping with field names, types, and descriptions
2. engagements-compute-tool
Purpose: Execute Elasticsearch queries against engagement events
Input: Elasticsearch query JSON Returns: Query results with engagement events and aggregations
Important: The Engagements index is event-level - each document represents one engagement event (email sent, opened, replied, etc.)
3. companies-schema-tool
Purpose: Get field mappings for the Companies index (outbound-specific)
When to use: For cross-index queries involving account attributes
4. companies-compute-tool
Purpose: Execute queries against the Companies index
When to use: For negation queries or when you need account data not in Engagements
5. chart-format-tool
Purpose: Generate Chart.js configurations for visualizing campaign data
Key Concepts
Event Types
Filter by eventType.keyword to get specific engagement types:
email_sent- Outbound email was sentemail_open- Lead opened the emailemail_reply- Lead replied to the emailemail_bounce- Email bounced (undeliverable)email_link_click- Lead clicked a link in the emaillead_unsubscribed- Lead unsubscribed from campaign
Nested Account Fields
The Engagements index contains two special nested fields with complete Company data:
targetAccountEngaged
Full Company object when the lead's company matches an engaged/identified account. Access fields using dot notation:
targetAccountEngaged.Uuid- Account UUIDtargetAccountEngaged.Name- Company nametargetAccountEngaged.Domain- Company domaintargetAccountEngaged.Icp- ICP score (0-100)targetAccountEngaged.Intent- Intent score (0-100)targetAccountEngaged.Buying Stage.keyword- Buying stagetargetAccountEngaged.Industry.keyword- IndustrytargetAccountEngaged.Employees- Employee counttargetAccountEngaged.Urls- Pages visited (use wildcard search)- And all other Company model fields...
targetAccount
Full Company object when the lead's company matches a prospect/target account list.
Critical Rule for Negation Queries
IF the query contains keywords like:
- "not contacted"
- "haven't been touched"
- "no outbound"
- "overdue for"
- "should add to campaigns"
- "not in any campaign"
- "never contacted"
- "missing from campaigns"
THEN you MUST use BOTH tools:
- Call
companies-compute-toolto get accounts matching criteria - Call
engagements-compute-toolto get accounts already in campaigns - Subtract step 2 from step 1
Why? The Engagements index only contains accounts that HAVE engagement events. You cannot find "not contacted" accounts by querying Engagements alone.
Common Use Cases
1. Campaign Reply Rate
Workflow:
{
"query": {
"term": {"campaignName.keyword": "Q1 Outreach"}
},
"size": 0,
"aggs": {
"sent": {
"filter": {"term": {"eventType.keyword": "email_sent"}}
},
"replied": {
"filter": {"term": {"eventType.keyword": "email_reply"}}
}
}
}
Calculate: replied._count / sent._count * 100
2. Reply Rates Across All Campaigns
{
"size": 0,
"aggs": {
"by_campaign": {
"terms": {"field": "campaignName.keyword", "size": 50},
"aggs": {
"sent": {
"filter": {"term": {"eventType.keyword": "email_sent"}}
},
"replied": {
"filter": {"term": {"eventType.keyword": "email_reply"}}
},
"reply_rate": {
"bucket_script": {
"buckets_path": {
"sent": "sent>_count",
"replied": "replied>_count"
},
"script": "params.sent > 0 ? params.replied / params.sent * 100 : 0"
}
}
}
}
}
}
3. Unique Contacts per Campaign
{
"size": 0,
"aggs": {
"by_campaign": {
"terms": {"field": "campaignName.keyword", "size": 50},
"aggs": {
"unique_contacts": {
"cardinality": {"field": "toEmail.keyword"}
}
}
}
}
}
4. Contacts Who Opened But Didn't Reply
{
"size": 0,
"aggs": {
"by_contact": {
"terms": {"field": "toEmail.keyword", "size": 200},
"aggs": {
"has_open": {
"filter": {"term": {"eventType.keyword": "email_open"}}
},
"has_reply": {
"filter": {"term": {"eventType.keyword": "email_reply"}}
},
"opened_not_replied": {
"bucket_selector": {
"buckets_path": {
"opens": "has_open>_count",
"replies": "has_reply>_count"
},
"script": "params.opens > 0 && params.replies == 0"
}
}
}
}
}
}
5. Engagement Trend Over Time
{
"query": {
"range": {"eventTimestamp": {"gte": "now-30d/d"}}
},
"size": 0,
"aggs": {
"by_day": {
"date_histogram": {
"field": "eventTimestamp",
"calendar_interval": "day"
},
"aggs": {
"by_event_type": {
"terms": {"field": "eventType.keyword"}
}
}
}
}
}
6. ICP-Fit Accounts That Replied
{
"query": {
"bool": {
"filter": [
{"term": {"eventType.keyword": "email_reply"}},
{"range": {"targetAccountEngaged.Icp": {"gte": 70}}}
]
}
},
"_source": [
"toEmail",
"toName",
"campaignName",
"targetAccountEngaged.Name",
"targetAccountEngaged.Domain",
"targetAccountEngaged.Uuid",
"targetAccountEngaged.Icp"
],
"size": 50
}
7. Accounts That Viewed Pricing Pages
{
"query": {
"bool": {
"filter": [
{"exists": {"field": "targetAccountEngaged"}},
{"wildcard": {"targetAccountEngaged.Urls": "*pricing*"}}
]
}
},
"_source": [
"toEmail",
"campaignName",
"targetAccountEngaged.Name",
"targetAccountEngaged.Urls",
"targetAccountEngaged.Uuid"
],
"size": 100
}
8. High-ICP Accounts NOT in Campaigns (Negation Query)
⚠️ CRITICAL: This requires BOTH tools
Step 1 - Get candidate accounts:
// Call companies-compute-tool
{
"query": {
"bool": {
"filter": [
{"range": {"Icp": {"gte": 70}}},
{"term": {"Buying Stage.keyword": "Awareness"}},
{"range": {"Identified People": {"gte": 1}}}
]
}
},
"_source": ["Name", "Domain", "Uuid", "Icp", "Buying Stage"],
"size": 100
}
Step 2 - Get accounts already touched:
// Call engagements-compute-tool
{
"query": {
"terms": {"eventType.keyword": ["email_sent", "email_open", "email_reply", "email_bounce", "email_link_click"]}
},
"aggs": {
"touched_accounts": {
"terms": {"field": "targetAccountEngaged.Uuid.keyword", "size": 10000}
}
},
"size": 0
}
Step 3 - Compare and subtract:
- Take UUIDs from Step 1
- Remove UUIDs found in Step 2 aggregation
- Return remaining accounts as "not contacted"
9. Decision-Stage Accounts by Industry
{
"query": {
"bool": {
"filter": [
{"term": {"targetAccountEngaged.Buying Stage.keyword": "Decision"}},
{"exists": {"field": "targetAccountEngaged"}}
]
}
},
"size": 0,
"aggs": {
"by_industry": {
"terms": {"field": "targetAccountEngaged.Industry.keyword", "size": 20},
"aggs": {
"unique_accounts": {
"cardinality": {"field": "targetAccountEngaged.Uuid.keyword"}
},
"avg_icp": {
"avg": {"field": "targetAccountEngaged.Icp"}
}
}
}
}
}
Best Practices
1. Always Filter by eventType
For outbound campaign analysis, always include eventType filter:
{
"terms": {
"eventType.keyword": ["email_sent", "email_open", "email_reply", "email_bounce", "email_link_click"]
}
}
2. Use Aggregations for Metrics
Never retrieve all documents to calculate rates. Use aggregations with bucket_script.
3. Unique Contact Counts
Use cardinality aggregation on toEmail.keyword for unique contact counts.
4. Date Filtering
Always use eventTimestamp for time-based filtering:
{"range": {"eventTimestamp": {"gte": "now-7d/d", "lte": "now/d"}}}
5. Accessing Nested Account Fields
Use dot notation with .keyword for exact matches on text fields:
{"term": {"targetAccountEngaged.Industry.keyword": "Technology"}}
For numeric fields, no .keyword needed:
{"range": {"targetAccountEngaged.Icp": {"gte": 70}}}
For wildcard searches on text, no .keyword:
{"wildcard": {"targetAccountEngaged.Urls": "*pricing*"}}
6. Check for Nested Field Existence
To find leads with target accounts:
{"exists": {"field": "targetAccountEngaged"}}
When to Use Both Tools
Use BOTH Companies and Engagements tools when:
- Query involves account attributes AND campaign status
- Negation queries (accounts NOT in campaigns)
- Comparison queries (account characteristics vs campaign performance)
- Gap analysis (accounts meeting criteria but lacking campaign activity)
Use ONLY Engagements tool when:
- Query is purely about campaign performance (reply rates, open rates)
- Account attributes accessed via
targetAccountEngaged.*fields
Use ONLY Companies tool when:
- Query is purely about account attributes (ICP, intent, buying stage)
- No mention of campaigns or engagement
Query Construction Tips
Combining Account Filters with Engagement
{
"query": {
"bool": {
"filter": [
{"term": {"eventType.keyword": "email_reply"}},
{"range": {"targetAccountEngaged.Icp": {"gte": 70}}},
{"term": {"targetAccountEngaged.Industry.keyword": "Technology"}},
{"range": {"eventTimestamp": {"gte": "now-30d/d"}}}
]
}
}
}
Multiple Event Types
{
"query": {
"terms": {
"eventType.keyword": ["email_open", "email_reply", "email_link_click"]
}
}
}
Text Search on Campaign Names
{
"query": {
"wildcard": {"campaignName": "*q1*outreach*"}
}
}
Sorting by Engagement Quality
{
"sort": [
{"sentimentScore": "desc"},
{"eventTimestamp": "desc"}
]
}