Email Templates
Every automated email the CRM sends — onboarding invoices, estimates, nurture sequences, review requests, invoice reminders — is driven by an editable template. Contractors own the look and voice of every message. System templates ship pre-built; contractors clone and customize them or build new ones from scratch.
System templates are read-only originals. Clone any system template to get an editable copy. The original stays intact — if the platform ships an update to a template, your clone is unaffected. You can always diff your version against the latest system version and pull changes selectively.
Template Library
Templates are organized by category. System templates are included with the platform. Custom templates are contractor-created. Both types are available in workflows, the AI agent, and the manual send dialog.
| Category | Template Name | Subject Line | Description | Type |
|---|---|---|---|---|
| Onboarding | Onboarding Invoice | Your project agreement from {{company.name}} | Sent at the start of the onboarding flow. Includes the project scope summary and a link to review the initial invoice. | System |
| Estimates | Estimate Delivery | Your estimate for {{project.name}} — {{estimate.total}} | Delivers the estimate with a personal intro from the AI (based on the inspection findings) and a direct link to view and approve online. | System |
| Estimates | Estimate Follow-Up #1 | Checking in on your estimate — {{contact.first_name}} | Sent 24h after estimate delivery if not yet approved. Gentle reminder with a one-click link back to the estimate. | System |
| Estimates | Estimate Follow-Up #3 (Final) | A few project examples that might help — {{contact.first_name}} | Sent 7 days after delivery. AI selects 2–3 relevant portfolio videos based on the contact's situation and embeds them inline. | System |
| Invoices | Invoice Sent | Invoice #{{invoice.number}} from {{company.name}} — due {{invoice.due_date}} | Primary invoice delivery email. Includes line items summary, total due, and a Pay Now button linked to the customer portal. | System |
| Invoices | Invoice Overdue — Day 3 | Friendly reminder — invoice {{invoice.number}} is past due | Polite first overdue reminder. Shows amount due and a Pay Now link. Tone: helpful, not aggressive. | System |
| Review & Testimonial | Review Request | How did we do, {{contact.first_name}}? | Post-completion review request. Warm, personal tone. Includes the project name and a survey link. Part of the review funnel workflow. | System |
| Nurture | Annual Check-In | It's been a year — how's the {{project.service_type}} holding up? | AI-written check-in one year after project completion. References the specific job, asks about follow-up needs, mentions referrals naturally. | System |
| Marketing | Project Showcase Newsletter | See what we just finished in your neighborhood | Monthly newsletter template. AI populates it with the top 2–3 completed projects from the past 30 days including photos and project video embeds. | System |
| Custom | + Create New Template | — | Start from a blank canvas or clone any system template as a starting point. | Custom |
Template Editor
The editor uses a block-based layout — text blocks, image blocks, button blocks, divider blocks, and video embed blocks. Drag to reorder. Click any block to edit it inline. Variables auto-complete with a {{ keystroke.
Toolbar actions: Edit · Preview · Mobile · + Text · + Image · + Button · + Divider · + Video · Send Test
Subject line supports variables. Example: Your estimate for {{project.name}} — {{estimate.total}}
Example body block structure (Estimate Delivery template):
[ Header block ] Company logo · centered
[ Text block ] Hi {{contact.first_name}},
Thank you for letting us take a look at your {{project.service_type}}.
Based on what we found during the inspection, I've put together an estimate
that covers everything we discussed.
{{ai.estimate_intro}} ← AI-generated personalized paragraph
[ Button block ] Review & Approve Your Estimate →
Links to: {{estimate.portal_link}}
[ Text block ] Questions? Just reply to this email or call us at {{company.phone}}.
We're happy to walk through anything before you decide.
— {{user.first_name}}, {{company.name}}
Footer actions: Discard · Save Draft · Save & Publish
Template Variables
Insert variables anywhere in a template with {{variable_name}} syntax. The CRM resolves them at send time using the record associated with the email — the contact, project, invoice, or estimate it's being sent for.
Quick reference chips:
{{contact.first_name}} · {{contact.last_name}} · {{contact.email}} · {{contact.phone}} · {{project.name}} · {{project.service_type}} · {{project.address}} · {{estimate.total}} · {{estimate.portal_link}} · {{invoice.number}} · {{invoice.total}} · {{invoice.due_date}} · {{invoice.pay_link}} · {{appointment.date}} · {{appointment.window}} · {{company.name}} · {{company.phone}} · {{company.logo_url}} · {{user.first_name}} · {{ai.estimate_intro}} · {{ai.personalized_paragraph}} · {{portal.link}}
AI Variables
Variables prefixed with ai. are generated at send time by Claude. The AI reads the full context (contact record, project, inspection report, conversation history) and writes fresh copy for that specific recipient. The template defines what the AI should generate — the AI fills it in.
| Variable | What the AI Generates |
|---|---|
{{ai.estimate_intro}} | 1–2 paragraph personalized intro referencing the specific damage found in the inspection and the homeowner's situation |
{{ai.personalized_paragraph}} | General-purpose paragraph personalized to the contact — references prior conversations, project type, or any personal details in the relationship history |
{{ai.portfolio_picks}} | 2–3 embedded portfolio video cards selected by the AI based on what's most relevant to this contact's situation and objections |
{{ai.followup_reason}} | A sentence explaining why the contractor is reaching out — generated from the workflow context (estimate age, prior replies, job type) |
SMS Templates
SMS templates work the same way as email templates but are plain text only. Character count is shown (160-char limit per segment). Variables are resolved the same way. The template library has separate SMS and Email tabs — both use the same editor framework.
Full Variable Reference
All available template variables by category. Variables resolve at send time from the record the email is being sent for. If a variable has no value for that record (e.g. the project has no estimate yet), the variable renders as an empty string unless you provide a fallback with {{variable | "fallback text"}}.
Contact
| Variable | Resolves To |
|---|---|
{{contact.first_name}} | Contact's first name |
{{contact.last_name}} | Contact's last name |
{{contact.email}} | Contact's email address |
{{contact.phone}} | Contact's phone number (formatted) |
Project
| Variable | Resolves To |
|---|---|
{{project.name}} | Project name (e.g. "Roof Replacement — 4821 Maple Ave") |
{{project.service_type}} | Service category (e.g. "Roof Replacement", "Deck Build") |
{{project.address}} | Full job site address |
{{project.status}} | Current project status (e.g. "In Progress", "Complete") |
Contractor / Company
| Variable | Resolves To |
|---|---|
{{contractor.business_name}} | Contractor's registered business name |
{{contractor.phone}} | Contractor's primary phone number |
{{contractor.email}} | Contractor's primary email |
{{contractor.website}} | Contractor's website URL |
Estimate
| Variable | Resolves To |
|---|---|
{{estimate.total}} | Formatted total amount (e.g. "$4,200.00") |
{{estimate.line_items}} | Rendered HTML table of line items |
{{estimate.expires_at}} | Estimate expiry date (formatted) |
{{estimate.portal_link}} | Direct URL to approve the estimate in the customer portal |
Invoice
| Variable | Resolves To |
|---|---|
{{invoice.amount_due}} | Amount currently due on the invoice |
{{invoice.due_date}} | Payment due date |
{{invoice.pay_link}} | Direct pay URL in the customer portal |
Appointment
| Variable | Resolves To |
|---|---|
{{appointment.date}} | Scheduled date (e.g. "Thursday, May 22") |
{{appointment.time_window}} | Arrival window (e.g. "9am – 11am") |
{{appointment.crew_name}} | Name of the assigned technician or crew lead |
Links
| Variable | Resolves To |
|---|---|
{{review.link}} | URL to the review funnel for this contact |
{{portal.link}} | URL to the contact's customer portal homepage |
AI-Generated (resolved at send time by Claude)
| Variable | Resolves To |
|---|---|
{{ai.estimate_intro}} | Personalized 1–2 paragraph intro referencing the inspection findings and homeowner's situation |
{{ai.personalized_paragraph}} | General-purpose paragraph personalized to this contact using their conversation history and relationship details |
{{ai.portfolio_picks}} | 2–3 embedded portfolio video cards selected by the AI based on relevance to this contact |
{{ai.followup_reason}} | A sentence explaining why the contractor is following up — generated from workflow context |
How Workflows Use Templates
Workflows reference templates by name using the template: key on a crm/send_email tool call node. Variables for the template are passed in the variables map — these merge with the global send context (contact, project, etc.) at send time.
Changing the template content in the Template Library updates all future sends from every workflow that references it — no need to update workflow YAML. Only the template name matters in the workflow definition.
Example — Send Estimate Email Node:
- id: send-estimate-email
data:
subtype: tool-call
label: Send Estimate Email
config:
toolName: crm/send_email
defaults:
to: "{{trigger.contact.email}}"
template: estimate-delivery
variables:
estimate_id: "{{trigger.estimate.id}}"
Example — Onboarding Invoice Node:
- id: send-onboarding-invoice
data:
subtype: tool-call
label: Email Onboarding Invoice
config:
toolName: crm/send_email
defaults:
to: "{{trigger.contact.email}}"
template: onboarding-invoice
variables:
project_id: "{{trigger.project.id}}"
invoice_id: "{{trigger.invoice.id}}"
Template Name Resolution
The template: value is a slug — the lowercase, hyphenated form of the template name. "Estimate Delivery" becomes estimate-delivery. "Invoice Overdue — Day 3" becomes invoice-overdue-day-3. The system resolves the slug to the currently published version of that template at send time.
Template Versioning
Every time you save a template, a new version is created automatically. The currently published version is what all workflows use. You can view the full version history and restore any prior version at any time.
| Version Action | What It Does |
|---|---|
| Save & Publish | Creates a new version and immediately makes it the active version — all future sends from any workflow referencing this template now use this version |
| Save Draft | Creates a new version but does not publish it — existing active version remains in use; draft is visible in version history with "Draft" badge |
| View History | Opens the version history panel — shows each version with timestamp, who saved it, and a preview button |
| Restore Version | Makes any prior version the new active version — same as publishing it again; prior active version moves to history |
| Compare Versions | Side-by-side diff of any two versions — highlights changed subject lines, added/removed blocks, and variable changes |
Workflows in-flight (e.g. a drip sequence already running for a contact) use the version of the template that was active when the workflow step executed — they are not retroactively affected by a new publish. Only new sends pick up the updated template. This prevents mid-sequence visual inconsistencies.