Skip to main content

Engagement Hub — Outbound email (technical)

Technical reference for informational outbound email via the Hub POST /start API, email templates, placeholders, and branding.

Audience: Integrators, bulk workers, CRM custom apps, automation engineers.

Canonical client guide: ENGAGEMENT_HUB_START_API.md — share with clients; includes /integration/start, /start, and full email_body_html documentation. Update that file when email start fields change.

Related user guide: AVENTORA_USER_MANUAL.md — §3.11 Account Settings (Outbound Email tab).


Overview

LayerResponsibility
aventora-adminSMTP settings, header/footer/logo branding, template library (account + optional per-user)
Aventora-Assistant (Hub)POST /start with channel: "email", template resolution, placeholder fill, SMTP send
domain-chatbotDomain logo asset (GET /stats/logo/{domain_name}) when “Include domain logo” is enabled

Email channel supports type: "informational" only. The call is marked Done after a successful one-shot SMTP send (no voice/SMS session).


Prerequisites

  1. Outbound SMTP configured in Admin → Engagement Hub → Account SettingsOutbound Email.
  2. domain_name on the /start request must match the tenant domain.
  3. Hub API key with permission to initiate calls (/start).
  4. Engagement hub not paused (engagement_hub_paused).

Optional: per-user SMTP/branding/templates when outbound_email_user_overrides_enabled is true and user_id is sent.


POST /start — email + informational

Authentication: Authorization: Bearer <hub_api_key>

Required fields

FieldDescription
channel"email"
type"informational"
domain_nameTenant slug (e.g. aventora)
email_address or client_emailRecipient (validated format)

Common optional fields

FieldDescription
user_idHub user id — per-user SMTP/templates/branding when overrides enabled
client_name{{CUSTOMER_NAME}} (fallback: recipient email)
email_subjectSubject line and {{SUBJECT}} value
instructionSee Send paths below
email_body_htmlInline HTML body with {{PLACEHOLDER}} tags (mutually exclusive with email_template_id / email_template_name)
email_template_idUUID of a saved template (Admin or API)
email_template_nameTemplate name if id omitted
email_template_paramsObject of extra placeholder values (this document)
languageISO-ish code; used only when no template (LLM body), default en

Fields may be top-level or nested under body (Hub accepts both).

Legacy alias

template_params is accepted as an alias for email_template_params.


Placeholders

Built-in (always set by Hub)

PlaceholderSource
{{SUBJECT}}email_subject, else instruction, else "Message from your provider"
{{CUSTOMER_NAME}}client_name, else recipient email, else "Customer"
{{ORGANIZATION_NAME}}Account setting organization_name for the domain

Built-in keys cannot be overridden via email_template_params.

Optional extra parameters (email_template_params)

Pass a JSON object on /start. Each key becomes an uppercase placeholder:

Request keyPlaceholder in template
policy_number{{POLICY_NUMBER}}
renewal_date{{RENEWAL_DATE}}
agent_name{{AGENT_NAME}}

Rules:

  • Keys must match ^[A-Za-z][A-Za-z0-9_]*$ (letters, digits, underscore; must start with a letter).
  • Values are converted to strings; empty strings are skipped.
  • Reserved keys SUBJECT, CUSTOMER_NAME, ORGANIZATION_NAME in email_template_params are ignored.
  • Substitution runs in template subject, template body, and branding header/footer HTML.

Example request

{
"channel": "email",
"type": "informational",
"domain_name": "aventora",
"email_address": "customer@example.com",
"client_name": "Alex Morgan",
"email_subject": "Your policy renewal",
"email_template_id": "550e8400-e29b-41d4-a716-446655440000",
"email_template_params": {
"policy_number": "POL-2026-8842",
"renewal_date": "June 15, 2026",
"agent_name": "Jamie Lee"
}
}

Example template body snippet:

<p>Dear {{CUSTOMER_NAME}},</p>
<p>Policy <strong>{{POLICY_NUMBER}}</strong> renews on {{RENEWAL_DATE}}.</p>
<p>Your advisor {{AGENT_NAME}} can answer any questions.</p>
<p>Best regards,<br/>{{ORGANIZATION_NAME}}</p>

Send paths

Conflict rule: do not send email_body_html together with email_template_id or email_template_name — Hub returns 400.

A — Inline HTML (email_body_html)

  1. fill_email_template replaces placeholders in email_body_html and email_subject (subject defaults to {{SUBJECT}} when omitted).
  2. instruction is not used for body generation (may still affect {{SUBJECT}} fallback when email_subject is omitted).
  3. Wrap with branding (header, footer, CID inline logo).
  4. SMTP send.

B — Template selected (email_template_id or email_template_name)

  1. Load template from data/email_templates/{domain}.json (or per-user file if applicable).
  2. fill_email_template replaces all placeholders (built-in + email_template_params).
  3. instruction does not generate the body; it only affects {{SUBJECT}} when email_subject is omitted.
  4. Wrap with branding (header, footer, CID inline logo).
  5. SMTP send.

If the template is not found, Hub falls through to path C.

C — No inline HTML or template (or template not found)

  1. instruction is treated as a brief.
  2. LLM (expand_instruction_to_email_body) writes a short plain-text paragraph.
  3. Wrapped in <p>…</p>, subject from email_subject or default.
  4. Branding wrap still applies; email_template_params still fill header/footer placeholders only.

Example — inline HTML

{
"channel": "email",
"type": "informational",
"domain_name": "aventora",
"email_address": "customer@example.com",
"client_name": "Alex Morgan",
"email_subject": "Your policy renewal",
"email_body_html": "<p>Dear {{CUSTOMER_NAME}},</p><p>Policy <strong>{{POLICY_NUMBER}}</strong> renews on {{RENEWAL_DATE}}.</p><p>Regards,<br/>{{ORGANIZATION_NAME}}</p>",
"email_template_params": {
"policy_number": "POL-2026-8842",
"renewal_date": "June 15, 2026"
}
}

Bulk CSV uploads may include an email_body_html column for channel=email rows (no instruction required when inline HTML or a template reference is present).

Priority when sources are present: email_body_html → saved template → instruction (LLM). Only one body source per request; inline HTML and template id/name cannot be combined.


Branding

Configured in Admin → Outbound Email (account or per-user):

  • Custom header HTML
  • Custom footer HTML
  • Domain logo and/or custom logo URL

Templates store body content only; branding wraps every outbound send.

Logo is attached as an inline CID image for email client compatibility.


Template storage API (Hub)

Proxied via aventora-admin for browser users; integrators may call Hub directly with the account API key.

MethodHub pathPurpose
GET/account-settings/email-templatesList templates
POST/account-settings/email-templatesCreate
PUT/account-settings/email-templatesUpdate
DELETE/account-settings/email-templatesDelete
GET/account-settings/email-template-catalogSystem library
POST/account-settings/send-test-emailSMTP + template test

Query/body may include external_user_id when using user-scoped templates.


Call log behavior

  • phone_number is stored as n/a for email channel.
  • Status moves to Done with outcome delivered after successful SMTP.
  • Failed SMTP → Failed with reason.

Errors (common)

HTTPMeaning
400Missing email, invalid type/channel combo, missing domain_name, unknown template (if strictly required by caller)
400SMTP not configured
403DNC / auth
503Engagement hub paused

CRM (Twenty / Quick Aventora)

User guide: AVENTORA_USER_MANUAL.md §2.5, §3.11.1. CRM integration detail: CRM_OUTBOUND_EMAIL_TEMPLATES.md.

CRM does not store Hub templates. It lists layouts from Hub and passes selections on start.

UI flow

  1. Person → Engage by Aventora → informational quick template.
  2. Channel = email.
  3. CRM calls GET /rest/aventora/email-templates (workspace JWT).
  4. User picks Email layout, subject, and dynamic template fields.
  5. CRM calls POST /rest/aventora/start-engagement → Hub POST /integration/start → internal POST /start.

CRM REST — list templates

Authentication: CRM workspace JWT (Authorization: Bearer …).

MethodPathResponse
GET/rest/aventora/email-templates{ templates: [{ id, name, subjectTemplate, customPlaceholderKeys }] }

Server proxies Hub GET /account-settings/email-templates?domain_name=… using the workspace application variable AVENTORA_API_KEY (account-scoped Hub key). Requires outbound email configured for the domain (SMTP); otherwise Hub may return 400 and CRM returns an empty list.

CRM REST — start with layout

Authentication: CRM workspace JWT.

CRM JSON fieldHub /integration/start/start
clientNameclient_name{{CUSTOMER_NAME}}
emailSubjectemail_subject{{SUBJECT}}
emailBodyHtmlemail_body_html (mutually exclusive with template id/name)
emailTemplateIdemail_template_id
emailTemplateNameemail_template_name
emailTemplateParamsemail_template_params (keys → {{KEY}})

personId, channel, type, instruction, contactIdentifier behave as for phone/SMS. For email, contactIdentifier is the recipient address. If clientName is omitted, twenty-server derives it from the person name fields when present.

CRM server environment

VariableWherePurpose
AVENTORA_BASE_URLtwenty-server .envHub root URL for /integration/start and template proxy
AVENTORA_API_KEYCRM workspace application settingsBearer token for Hub (per account)
Assigned domainCRM workspace application settingsdomain_name for Hub

CRM frontend environment (optional)

VariableDefault
REACT_APP_AVENTORA_EMAIL_TEMPLATES_ENDPOINT{REACT_APP_SERVER_BASE_URL}/rest/aventora/email-templates

Usually unset when CRM UI and API share one host. Override only for split-domain deployments.

Workflows

Use POST /rest/aventora/start-engagement with the same JSON body and workflow-appropriate auth. Map workflow variables into emailTemplateParams. No dedicated Aventora workflow action ships in the repo today.


Version note

  • email_template_params — custom placeholders on informational email sends.
  • CRM UI + GET /rest/aventora/email-templates — Quick Aventora email layout picker (aventora-crm main).

Documented in ENGAGEMENT_HUB_START_API.md (canonical), this file, AVENTORA_USER_MANUAL.md §2.5 / §3.11.1, and CRM_OUTBOUND_EMAIL_TEMPLATES.md.