Setup Email Sequence
setup_email_sequenceFor 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
| Name | Required | Description | Default |
|---|---|---|---|
| enrich | No | When 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)`. | |
| mailbox | No | Email 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_id | No | Optional. 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_id | Yes | Required. Agent ID to associate with the queued items. | |
| recipients | Yes | List 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_up | No | If 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_template | No | Batch 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_template | No | Batch fallback subject for recipients without their own `subject`. Final literal text — placeholder syntax rejected. |