Skip to main content

Scenario

Your winning email copy is locked inside HubSpot engagement records. You extract emails from Closed Won deals, distill a Brand Voice from the highest-converting messaging, then generate new variations that carry the same tone and persuasion.

Architecture

Code

import os, requests
from openai import OpenAI

HS = os.environ["HUBSPOT_ACCESS_TOKEN"]
MV = os.environ["MAVERA_API_KEY"]
HB = "https://api.hubapi.com/crm/v3"
MB = "https://app.mavera.io/api/v1"

# 1. Closed Won deals
deals = requests.post(f"{HB}/objects/deals/search",
    headers={"Authorization": f"Bearer {HS}"},
    json={
        "filterGroups": [{"filters": [{"propertyName": "dealstage", "operator": "EQ", "value": "closedwon"}]}],
        "properties": ["dealname", "amount", "closedate"],
        "sorts": [{"propertyName": "closedate", "direction": "DESCENDING"}],
        "limit": 15,
    },
).json().get("results", [])

# 2. Collect winning email copy
winning_emails = []
for deal in deals:
    assocs = requests.get(f"{HB}/objects/deals/{deal['id']}/associations/emails",
        headers={"Authorization": f"Bearer {HS}"}).json().get("results", [])
    for a in assocs[:5]:
        email = requests.get(f"{HB}/objects/emails/{a['id']}",
            headers={"Authorization": f"Bearer {HS}"},
            params={"properties": "hs_email_subject,hs_email_text,hs_email_direction"},
        ).json().get("properties", {})
        if email.get("hs_email_subject") and email.get("hs_email_direction") == "EMAIL":
            winning_emails.append(f"Subject: {email['hs_email_subject']}\n{email.get('hs_email_text','')[:800]}")

# 3. Create Brand Voice
samples = "\n\n---\n\n".join(winning_emails[:10])
bv = requests.post(f"{MB}/brand-voices",
    headers={"Authorization": f"Bearer {MV}", "Content-Type": "application/json"},
    json={"name": "HubSpot Won Email Voice", "samples": [samples]},
).json()
print(f"Brand Voice: {bv['id']}")

# 4. Generate variations
gen = requests.post(f"{MB}/generations",
    headers={"Authorization": f"Bearer {MV}", "Content-Type": "application/json"},
    json={
        "brand_voice_id": bv["id"],
        "prompt": "Write 3 sales email variants for a mid-market SaaS prospect. Subject line + 150-word body each. Match the winning tone.",
        "count": 3,
    },
).json()
for i, g in enumerate(gen.get("results", [gen]), 1):
    print(f"\nVariant {i}:\n{g.get('content', g.get('text',''))[:300]}")

Example Output

Brand Voice: bv_won_email_9f3a

Variant 1: Subject: Quick question about your Q3 pipeline
Hey [Name], I noticed [Company] is scaling — congrats. We helped [Similar Co]
cut pipeline review time by 40%. Worth a 15-min call?

Variant 2: Subject: [Company] + [Product] — a thought
Your growth caught my eye. We work with companies at your stage to solve
[specific pain]. I put together a quick brief — want it?

Error Handling

Not all deals have associated emails. Confirm your team logs emails to deals in HubSpot Settings.
Under ~200 words total produces a generic voice. Aim for 5–10 emails, 100+ words each.

HubSpot Integration

Brand Voice API