Skip to main content
Glama

Setup Email Sequence

setup_email_sequence
Destructive

For single personal emails, use draft_email + send_email.

A campaign already sending without a flow keeps calling this tool without node_id. Every other campaign sends through its flow, even a single email: create it with define_sequence and add the prospects with track_prospects, and the flow's send steps call this tool with their node_id. A call without node_id on an agent that has no flow and hasn't sent any outreach yet is refused.

An agent is required — create one via create_agent if none exists. This tool creates tracking items for the recipients it queues, so don't also call track_prospects for them. Only call this AFTER the user has explicitly confirmed the outreach. Dict with queued_count, skipped items, a preview of the first queued email, first_send_at / last_send_at (see below), and tracking_skipped — recipients already tracked in another campaign, so nothing queued for them. Each entry names existing_agent_title / existing_agent_id; surface these and let the user place them.

This tool QUEUES; it never sends. Nothing has been delivered when it returns — a background beat drains each mailbox in derived order at a human-like pace, minutes to days later. first_send_at / last_send_at are ISO timestamps bounding the projected send window (from the read-time forecast), and awaiting_approval counts rows held for the user's approval. Gated rows are excluded from the window; when every row is gated both bounds are null and nothing is projected until the user approves.

So report queued work as queued, with the window: "Queued 4, first lands 12:02pm, last 12:11pm." Do NOT tell the user these were sent.

Writing a marker into a campaign's own tracker (a sheet, a CRM field) at queue time is fine and is usually what its dedup depends on — skip it and the next run re-queues the same people. But that marker records handoff, not delivery: don't cite it back as proof a send happened, and don't let it turn into "sent" in your summary. For what actually went out, read the queue (manage_email_outreach_queue(action='status')); to act at real send time, the agent needs a sent_email trigger.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
enrichNoWhen True, look up each recipient's LinkedIn URL via Apollo (using their `email` plus optional `first_name` / `last_name`) and stamp it on the tracking row. Costs 1 Sliq credit per verified hit; free with BYO Apollo. Recipients that already carry `linkedin_url`, those missing inputs, and those past the credit limit are silently skipped. Reverse of `setup_linkedin_sequence(enrich=True)`.
mailboxNoEmail address of a connected mailbox (e.g. 'alice@acme.io'). Omit to use the user's default mailbox. When the user has multiple mailboxes connected, ask which to use rather than guessing — surfacing the choice is the agent's job, not a silent fallback. For segmented delivery ("first third from A, second from B, last from C"), call this tool once per segment with the segment's recipients and the segment's mailbox. The tool does not rotate across calls; per-call recipient lists are how segmentation is expressed.
node_idNoOptional. The id of the sequence-DAG node this batch enacts (a node in the agent's `sequence`, authored via `define_sequence`). Stamped on every queued row so the Campaign Flow view can place each prospect and count per node. Pass it whenever the agent has a sequence. Rejected with ModelRetry if it isn't a node in the agent's sequence.
agent_idYesRequired. Agent ID to associate with the queued items.
recipientsYesList of dicts. Required: `email`. Optional per-recipient `subject` / `body` (final literal text; placeholder syntax `{first_name}`, `[name]`, `<<name>>`, `{{name}}` is rejected with ModelRetry; overrides templates). Other fields (`first_name`, `last_name`, `company`, `title`) are stored on the tracking item for later lookup — NOT substituted into templates. Other extras are ignored, except the LinkedIn identifiers: `linkedin_url` is honored from either the top-level key OR a `data` sub-dict (validated / canonicalized before storage), while `linkedin_provider_id` is honored from the top-level key only. Both land on the prospect's LinkedIn fields. For mixed-channel campaigns, also pass `linkedin_url` (and `linkedin_provider_id` when known) on each recipient so this tool can dedup against any existing LinkedIn-keyed tracking row for the same person — both identifiers land on one row. When `find_email` returned `{email, linkedin_url}` for this recipient, forward both fields here verbatim. On a flow email node this is also how a just-discovered address binds to the prospect resting on the node: passing their `linkedin_url` resolves the send to that existing row instead of orphaning a new one.
is_follow_upNoIf True, send as a threaded reply to the original outreach email instead of a new email. Requires recipients to have been previously emailed via this agent.
body_templateNoBatch fallback body for recipients without their own `body`. Final literal text — placeholder syntax rejected. Bodies (this and per-recipient `body`) are Markdown, rendered to HTML at send time for every provider — write hyperlinks as [text](url) so the link reads as its anchor text rather than a raw URL.
subject_templateNoBatch fallback subject for recipients without their own `subject`. Final literal text — placeholder syntax rejected.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / node_id / description
      Previous value: -"Optional. The id of the sequence-DAG node this batch enacts\n(a node in the agent's `sequence`, authored via `define_sequence`).\nStamped on every queued row so the Campaign Flow view can place\neach prospect and count per node. Pass it whenever the agent has a\nsequence; omit for flowless/ad-hoc sends. Rejected with ModelRetry\nif it isn't a node in the agent's sequence."New value: +"Optional. The id of the sequence-DAG node this batch enacts\n(a node in the agent's `sequence`, authored via `define_sequence`).\nStamped on every queued row so the Campaign Flow view can place\neach prospect and count per node. Pass it whenever the agent has a\nsequence. Rejected with ModelRetry if it isn't a node in the agent's\nsequence."
  2. Changed5 schema fields changed
    • addedInput schema / properties / agent_id
      Added value: +{
      +  "description": "Required. Agent ID to associate with the queued items.",
      +  "type": "integer"
      +}
    • changedInput schema / properties / is_follow_up / description
      Previous value: -"If True, send as a threaded reply to the original outreach\nemail instead of a new email. Requires recipients to have been\npreviously emailed via this task."New value: +"If True, send as a threaded reply to the original outreach\nemail instead of a new email. Requires recipients to have been\npreviously emailed via this agent."
    • changedInput schema / properties / node_id / description
      Previous value: -"Optional. The id of the sequence-DAG node this batch enacts\n(a node in the task's `sequence`, authored via `define_sequence`).\nStamped on every queued row so the Campaign Flow view can place\neach prospect and count per node. Pass it whenever the task has a\nsequence; omit for flowless/ad-hoc sends. Rejected with ModelRetry\nif it isn't a node in the task's sequence."New value: +"Optional. The id of the sequence-DAG node this batch enacts\n(a node in the agent's `sequence`, authored via `define_sequence`).\nStamped on every queued row so the Campaign Flow view can place\neach prospect and count per node. Pass it whenever the agent has a\nsequence; omit for flowless/ad-hoc sends. Rejected with ModelRetry\nif it isn't a node in the agent's sequence."
    • removedInput schema / properties / task_id
      Removed value: -{
      -  "description": "Required. Task ID to associate with the queued items.",
      -  "type": "integer"
      -}
    • changedInput schema / required
      Previous value: -[
      -  "recipients",
      -  "task_id"
      -]New value: +[
      +  "recipients",
      +  "agent_id"
      +]
  3. First observed

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations only declaring readOnlyHint=false and destructiveHint=true, the description adds substantial behavioral context beyond them: it QUEUES and never sends, sends drain minutes-to-days later via a background beat, it creates tracking items (so don't double-call track_prospects), dedup/`tracking_skipped` semantics, and awaiting_approval gating that can null the send window. This is exactly the extra context the annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded and tagged with <summary>/<returns>, which helps, but it runs long and repeats the same point about not reporting queued work as sent three times ('report queued work as queued', 'Do NOT tell the user these were sent', 'don't let it turn into sent'). The returns prose is dense and could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by fully documenting the return shape (queued_count, skipped, preview, first_send_at/last_send_at, tracking_skipped, awaiting_approval) and the queue-vs-send distinction. For an 8-parameter mutation tool with an external prerequisite (agent) and flow interaction, nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema on parameter interplay — most notably when to pass `node_id` (every campaign that sends through a flow) versus the no-flow case, and how recipient `linkedin_url` binds a just-discovered address to an existing prospect row. It does not restate the per-param syntax already documented in the schema, so it earns above baseline without being redundant.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The summary gives a specific verb+resource ('Queue bulk email outreach') and immediately scopes it as a 'Campaign/batch tool' that handles queuing, rate limiting, staggering, business hours, and tracking. It explicitly distinguishes itself from siblings by naming draft_email + send_email for single personal emails and setup_linkedin_sequence as its reverse. An agent can tell this apart from single-send and LinkedIn tools without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when-to-use routing ('For single personal emails, use draft_email + send_email'), prerequisites ('An agent is required — create one via create_agent if none exists'), and a hard precondition ('Only call this AFTER the user has explicitly confirmed the outreach'). It even describes the flow-based invocation path via define_sequence/track_prospects and when the no-node_id call is refused.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources