Echo/Docs

CLI command

email preview

A campaign message as one contact would get it, its usage blocks decided by what that contact did in the product, composed and sent nowhere.

Invocation#

Shell
echo-cli email preview --campaign <campaign-id> --contact <contact-id> [--step <n> | --variant <variant-id>]

Inputs and output#

preview writes campaign_id, contact_id, step (null for the first message), template_from (the campaign, variant <name> or step <n>), subject, body, usage: null when the template has no usage block, otherwise identifiers (the user and anonymous ids the contact is known by), events (each stored event name with how many times they sent it), sent_at (each event name with the times it was sent, oldest first) and properties (each event name with the properties each of those sends stored, in the same order), and banned: every banned phrase of the product the campaign speaks for (echo-cli email brand) that the subject or body holds — phrase, use_instead, field, line, column — empty when it holds none or the campaign names no product. A message whose banned is not empty would not be sent.

State effect#

preview calls Echo Web's authenticated /api/crm/campaigns/<id>/preview with ECHO_INTERNAL_BEARER at ECHO_WEB_BASE_URL; the /campaigns/variants screen and Echo Desktop's Campaign A/B variants section call the same operation (each event with its count and last send), and echo-mcp exposes it as echo_preview_campaign_message. A campaign template, variant or sequence step may hold usage blocks: {{#did <event>}}text{{/did}} keeps its text only when the recipient sent that event, {{#didnt <event>}}text{{/didnt}} only when they did not. The event may name one of its properties and the value it must hold, in brackets right after it: {{#did plan.changed[plan=pro]}} keeps its text only for someone whose plan.changed event stored plan pro; a send without the property, or with another value, does not count, and a value is compared as the text of what the event stored, so [seats=5] matches a stored 5. One or two whole numbers after the event (and its bracket) state how often and how recently: {{#did <event> <times>}} asks for at least that many sends, {{#did <event> <times> <days>}} counts only the sends of the last that many days — {{#did report.created 3 7}} for three reports this week, {{#didnt login 1 14}} for no login in two weeks, {{#did plan.changed[plan=pro] 1 30}} for a move to pro this month; without numbers one send ever is enough. The recipient is known by their contact email: the web and mobile events whose email or user_email property is that address in lower case give their user and anonymous ids, the identity edges add every id linked to those, and every event of those ids, each counted once, is their usage; a recipient no event names has done nothing. The worker decides the blocks the same way, from stored events as of the send, on every send, before filling {{name}} and {{handle}} and before an AI-marked brief is crafted. --step names a sequence step's template and --variant one of the campaign's A/B variants; with neither, the first message's template is the contact's A/B variant when they are already a recipient holding one, else the campaign's. A template starting with the AI marker is crafted through Brama, as a send would craft it. Nothing is sent or stored.

Refusals#

  • A wrong invocation is refused before anything is sent: "email preview needs <flag>", "email preview does not take <flag>; it takes --campaign, --contact, --step, --variant" and "--step must be a sequence step's whole number; got <value>".
  • Echo Web answers a bad request with "contact_id is required: the contact to compose the message for", "step must be a sequence step's whole number, or absent for the first message; got <value>" or "step and variant_id name two different templates; a variant is the first message, so give one of them"; not found with "no campaign has id <id>; echo-cli outreach lists the campaigns", "no contact has id <id>", "campaign <id> has no variant <variant-id>; echo-cli email ab list --campaign <id> lists them" or "campaign <id> has no message template for <the campaign|step <n>>"; and a composition that cannot finish with "contact <id> has no email address, so the template's usage blocks cannot be decided" or "contact <id> has no value for {{<placeholder>}}", the same sentences a send records as compose_failed. The command prints Echo Web's sentence and exits 1.