Daily
Draft personal outreach emails for a HubSpot list
Each contact in your HubSpot outreach list gets a tailored email waiting in your Gmail drafts, ready for you to check and send.
- Runs
- Daily
- Apps
- Gmail, HubSpot
- AI
- Yes, uses the built-in AI allowance
- Access
- HubSpot crm.lists.read, contacts read+write; Gmail gmail.compose
Send this to your assistant
Create a ClickRuntime automation: every day, take the contacts in my HubSpot 'Q4 outreach' list, write a personal email for each using what's in their CRM record, and put it in my Gmail drafts.
First time? Adding ClickRuntime to your assistant takes about two minutes.
Why use it
Why teams use this automation
A founder or account executive builds a list of fifty prospects in HubSpot for a quarterly push. Writing fifty genuinely personal emails takes a full day, so the list sits there, or everyone gets the same template and the reply rate shows it.
This writes a first draft for each person using their job title, company, industry and any notes in HubSpot, and leaves it in your Gmail drafts. You spend your time reading and adjusting, not starting from a blank page, and nothing goes out without you.
What you get out of it
A personal first draft for every contact
Each email refers to the person's role, company and what you already know about them from HubSpot.
You keep control of what is sent
Everything waits in Gmail drafts, so you can edit, skip or send each one yourself.
The list is worked through daily
New members added to the list get a draft the next morning, so outreach keeps pace with list building.
No one gets two drafts
Contacts already drafted are marked in HubSpot, so the same person isn't written to twice.
How it works
What happens, step by step
Each morning, ClickRuntime reads the contacts in the HubSpot list you choose.
It skips anyone already marked as drafted, so each person gets one email.
AI writes a short, personal email for each contact using their CRM details and your offer.
Each email is saved as a draft in your Gmail, and the contact is marked as drafted in HubSpot.
Before it runs live
- Connect Google through your own Google app (a one-time, 10-minute setup), so it works with your own Gmail
- Connect HubSpot
What you get
Build your own
Need it to work differently?
Your own rules
Conditions, thresholds, filters and exceptions, written the way you'd explain them to a colleague.
Any number of apps
One automation can read from one app and update several others. Over 248 apps are ready, and anything with an API works too.
AI where it helps
Summaries, classification, extraction and drafts use ClickRuntime's built-in AI, with no extra key.
On a schedule or on each event
Runs as often as every 5 minutes, or the moment an app sends an event, and keeps track of what it already handled.
Changes you can ask for
- Run it at a different time, more or less often, or only on weekdays
- Change what the AI looks for, or how it writes the result
- Add another app, for example also send it to Slack
- Combine it with other Gmail and HubSpot steps into one automation
Under the hood
The code that runs this automation
import base64
from email.message import EmailMessage
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from clickruntime import on_trigger, credentials, http, ai
LIST_ID = "123"
OFFER = "We help retail teams cut stock-outs with weekly demand forecasts."
def hs(method, path, **kw):
r = http.request(method, f"https://api.hubapi.com{path}", headers={"Authorization": f"Bearer {credentials.connection('hubspot', 'work')}"}, **kw)
return r.raise_for_status() or (r.json() if r.content else {})
@on_trigger
def run(event):
ids = [m["recordId"] for m in hs("GET", f"/crm/v3/lists/{LIST_ID}/memberships", params={"limit": 100})["results"]]
contacts = hs("POST", "/crm/v3/objects/contacts/batch/read", json={"inputs": [{"id": i} for i in ids],
"properties": ["email", "firstname", "jobtitle", "company", "industry", "outreach_drafted"]})["results"]
todo = [c for c in contacts if not c["properties"].get("outreach_drafted")][:25]
g = build("gmail", "v1", credentials=Credentials(credentials.connection("google", "work")), cache_discovery=False)
for c in todo:
p = c["properties"]
body = ai.generate(f"Offer: {OFFER}\nWrite a 100-word personal cold email to {p.get('firstname')}, "
f"{p.get('jobtitle')} at {p.get('company')} ({p.get('industry')}). End with a question.",
max_output_tokens=300).text
msg = EmailMessage(); msg["To"] = p["email"]; msg["Subject"] = f"Idea for {p.get('company')}"; msg.set_content(body)
g.users().drafts().create(userId="me", body={"message": {"raw": base64.urlsafe_b64encode(msg.as_bytes()).decode()}}).execute()
hs("PATCH", f"/crm/v3/objects/contacts/{c['id']}", json={"properties": {"outreach_drafted": "true"}})
return {"drafted": len(todo)}FAQ
Common questions
What information does the AI use?
How many drafts does it create each day?
Can I give it my own tone and examples?
What permissions does it need?
Does it need AI?
How many runs does it use?
Can I change how it works?
Related
You might also like
Email new HubSpot contacts nobody has contacted yet
New contacts who haven't heard from you get an introduction email from your Gmail each day, and HubSpot records that they've been contacted.
See how it worksFollow up with HubSpot contacts who haven't replied
Contacts who didn't answer your first email get a polite follow-up from Gmail a few days later, and HubSpot shows it was sent.
See how it worksGet a weekly revenue forecast from HubSpot by email
Every Monday you get an email with your weighted pipeline forecast and the deals most at risk.
See how it worksKeep exploring
Set up “Draft personal outreach emails for a HubSpot list” from your assistant
Copy the prompt above, or connect your assistant first. Free plan, no credit card.