Developers · Transactional
Email over MCP — a template and a call
The defining call is send_transactional: one recipient, now, through a template marketers own. Compose from a brief, preview with send_test, enrol sequences from your own events. Same craft as genieos.pro/dev/product/email.
// Marketers own the template. Your agent targets it by ID.await send_transactional({ template: "trial-ending", to: "user_8291", variables: { daysLeft: 3, planName: "Glow", },}); // Idempotent — safe to retry from your job queue.// Brief in → rendered, on-brand email outconst draft = await compose_template({ brief: "Trial ending in 3 days — warm, one CTA to upgrade", audience: "trialists, day 11 of 14",}); await send_test({ template: draft.key, to: "[email protected]" });// Your event, your predicate, one enrolmentconst run = await enroll_in_sequence({ sequence: "activation-nudge", contact: "[email protected]", reason: "users.activated_at still null after 7 days",}); await read_sequence_run({ run: run.id });// Pull them out the moment your data says stopawait cancel_sequence_run({ run: run.id });The surface
Tools your agent actually calls
compose_template
Brief in → on-brand draft template out
send_test
Sandbox inbox — never hits real recipients
send_transactional
One recipient, now — idempotent
render_template
HTML back for preview pipelines
list_sends · read_send
What went, to whom, what happened
enroll_in_sequence
Lifecycle from your own events
Two doors
The library is theirs. The ID is yours.
Templates live in a library split into marketing and transactional. The transactional shelf comes stocked — trial ending, payment failed, subscription cancelled, sign-in from new device. Your agent targets any of them by ID, so the send in your codebase never contains a line of design.
In the app, every template carries an API details button beside Send and Edit — the whole two-door argument shipped as product: marketers design and own the artefact; the exact call your agent needs is printed on it.
propose_template_change
The call that cannot ship alone
Every other tool does what it says immediately. This one files a suggestion against a template the marketing team owns — then stops. The change ships when a marketer acknowledges it. That boundary is why you can give agents real authority over sends while templates stay owned by the people accountable for them.
await propose_template_change({ template: "trial-ending", change: "Lead with the streak they would lose", evidence: "42% of expiring trials hold a 7-day streak",});// lands in the marketer's queue — ships on ackWhen this happens
Your product already knows when to send
When · You tag a release v*
Then · A changelog email to everyone still on the previous version
When · A feature flag reaches 100%
Then · An announcement to the cohort that did not have it
When · A Sentry issue crosses your user threshold
Then · A transactional email to affected users — status and ETA
REST · one shot
# The defining call — one recipient, nowcurl -X POST https://api.genieos.pro/v1/templates/trial-ending/send \ -H "Authorization: Bearer $GENIEOS_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: trial-$(uuidgen)" \ -d '{ "to": "[email protected]", "variables": { "daysLeft": 3 } }'