Welcome e-mail for a new HubSpot contact
When a contact is created in HubSpot, read it back and send a personalised welcome e-mail.
Drag to pan, pinch to zoom. This is the real graph the template installs.
Purpose
When a contact is created in HubSpot, read it back and send a personalised welcome e-mail.
How it works
What it does
- Subscribes to HubSpot's
contact.creationevent. - Reads the new contact back so the e-mail has real properties rather than just an id.
- Sends a personalised welcome.
Validation
This template is contract-validated: the unit suite checks every node type, every config key and the whole graph against the same rules a saved workflow passes. It has not been run against the live provider — the ids, names and columns below are placeholders to replace with your own.
Nodes 3
- 01Contact createdtrigger.hubspot_eventTrigger
- 02Read the contacthubspot.get_contactApp
- 03Send the welcomemail.sendDestination
View template JSON
{
"format": "mantle-workflow/v1",
"id": "hubspot-new-contact-welcome",
"name": "Welcome e-mail for a new HubSpot contact",
"graph": {
"nodes": [
{
"id": "event",
"type": "trigger.hubspot_event",
"label": "Contact created",
"config": {
"app_id": "0000000",
"subscription_types": [
"contact.creation"
],
"max_concurrent_requests": 10
},
"worker_type": "generic-worker",
"position": {
"x": 60,
"y": 220
}
},
{
"id": "contact",
"type": "hubspot.get_contact",
"label": "Read the contact",
"config": {
"contact_id": "{{ $json.objectId }}",
"properties": "email,firstname,lastname,company"
},
"worker_type": "generic-worker",
"position": {
"x": 380,
"y": 220
}
},
{
"id": "welcome",
"type": "mail.send",
"label": "Send the welcome",
"config": {
"to": "{{ steps.contact.properties.email }}",
"subject": "Welcome, {{ steps.contact.properties.firstname }}",
"body_text": "Hi {{ steps.contact.properties.firstname }},\n\nThanks for getting in touch. Someone from the team will follow up shortly.\n"
},
"worker_type": "generic-worker",
"position": {
"x": 700,
"y": 220
}
}
],
"edges": [
{
"from": "event",
"to": "contact"
},
{
"from": "contact",
"to": "welcome"
}
]
}
}Requirements
The connections and permissions each step needs, from the node contracts in the catalog.
- HubSpotBearer token
Used by Contact created, Read the contact.
Credential: {"token", "developer_api_key", "client_secret"} · the HubSpot private-app token, or {"token": "…"}
- The webhooks API authenticates with the developer API key of the account that owns the app, and signatures are verified with the app's client secret. The private-app token alone cannot do either.
- HubSpot's webhook target URL is a single app-level setting, so one HubSpot app backs one published workflow. Publishing a second workflow against the same app_id fails rather than stealing the first one's events.
- One app serves every HubSpot account that installed it: branch on portalId when more than one portal is in play.
- Filtering is done by HubSpot — subscription_types and property_name decide what is ever sent, so nothing arrives here to be discarded.
- Runs are deduplicated per portal, subscription, object, occurredAt and eventId together — HubSpot does not guarantee eventId is unique — so a delivery retried up to ten times over twenty-four hours starts one run.
- Deliveries must be answered within five seconds, which is why the run is accepted and executed asynchronously.
- SendGridAPI key
Used by Send the welcome.
Credential: {"api_key"} or {"username", "password"}
Setup
app_idis your HubSpot developer app id — the webhooks API belongs to the app, not the portal.- The HubSpot connection needs
developer_api_keyandclient_secretas well as the private-app token: the key creates the subscription and the secret verifies the signature. - Pick a mail connection on Send the welcome and edit the copy.
Sample input and output
Synthetic examples: node-contract samples or placeholders, never customer data.
Input
What the Contact created trigger receives, as its node contract samples it.
{
"appId": "",
"attemptNumber": 0,
"changeSource": "",
"eventAction": "propertyChange",
"eventId": "1",
"objectId": "12345",
"objectType": "contact",
"occurredAt": 0,
"occurredAtIso": "",
"portalId": "62515",
"propertyName": "email",
"propertyValue": "ada@example.com",
"subscriptionId": "",
"subscriptionType": "contact.propertyChange"
}Output
Send the welcome mail.send
{
"body": null,
"message_id": "",
"provider": "",
"sent": true,
"status_code": 0,
"thread_id": ""
}Failure handling
What the graph does when a step fails, read from its retry settings, error branches and error policies.
- A step that fails, after any retries, fails the run. The failed step is kept with its input and error.
See it run, then make it yours.
Templates install as drafts. Edit any step, and Workflow Health re-checks the graph on every save.