Skip to main content

Outbound Server

Analyze outbound email performance (opens, clicks, replies, and contact engagement) to measure campaign effectiveness and find accounts ready for follow-up.

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 sent
  • email_open - Lead opened the email
  • email_reply - Lead replied to the email
  • email_bounce - Email bounced (undeliverable)
  • email_link_click - Lead clicked a link in the email
  • lead_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 UUID
  • targetAccountEngaged.Name - Company name
  • targetAccountEngaged.Domain - Company domain
  • targetAccountEngaged.Icp - ICP score (0-100)
  • targetAccountEngaged.Intent - Intent score (0-100)
  • targetAccountEngaged.Buying Stage.keyword - Buying stage
  • targetAccountEngaged.Industry.keyword - Industry
  • targetAccountEngaged.Employees - Employee count
  • targetAccountEngaged.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:

  1. Call companies-compute-tool to get accounts matching criteria
  2. Call engagements-compute-tool to get accounts already in campaigns
  3. 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:

  1. Query involves account attributes AND campaign status
  2. Negation queries (accounts NOT in campaigns)
  3. Comparison queries (account characteristics vs campaign performance)
  4. 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"}
]
}