I’ve also tried using other contact identifiers such as:
contact.id
contact.hs_object_id
contact.vid
Even using personalization_token(...)
But none of them seem to work inside an email context — either the ID is not recognized, or crm_associations returns nothing.
What’s even more confusing is that {{ contact.hs_object_id }}does render properly if inserted using the personalization token button, which suggests the data is there.
So my question is:
Why isn’t it possible to use crm_associations in an email even when the contact’s ID is technically available? And why it's so (so so) complex to get associated properties of a contact?
Is there a workaround I’m missing?
Thanks in advance for any insights or recommendations!
Why is it impossible to use crm_associations in an email with the contact’s ID?
SOLVE
Hi @panchitofrancia I read your thread and totally get the issue.
It’s frustrating that crm_associations doesn’t work with the current contact in emails. The workaround of copying values into contact properties isn’t ideal when there are many association labels.
If you have access to custom code actions (like with Operations Hub), there’s another option. You can use a small script in a workflow to pull data from associated records and save it into one contact property. Here’s a basic example
const hubspot = require('@hubspot/api-client');
exports.main = async (event, callback) => {
const hubspotClient = new hubspot.Client({ accessToken: process.env.HAPIKEY });
const contactId = event.object.objectId;
// Replace 2 with your object type ID (like deals, custom objects, etc.)
const ASSOCIATION_TYPE_ID = 2;
try {
const associations = await hubspotClient.crm.contacts.associationsApi.getAll(contactId, 'deals');
const dealIds = associations.results.map(a => a.id);
let emails = [];
for (const id of dealIds) {
const deal = await hubspotClient.crm.deals.basicApi.getById(id, ['dealname', 'hubspot_owner_id']);
emails.push(deal.body.properties.dealname); // or replace with the field you need
}
const summary = emails.join(', ');
// Save to contact property
await hubspotClient.crm.contacts.basicApi.update(contactId, {
properties: {
associated_summary: summary,
},
});
callback({ outputFields: {} });
} catch (e) {
console.error(e);
callback({ error: e });
}
};
This will grab the associated deals (or other object) and store the info into one field like associated_summary, which you can then use in your email like this:
I understand how frustrating it can be to try and access associated CRM records in HubSpot emails—especially when it seems like all the data is technically available.
Unfortunately, the reason your crm_associations function isn’t working inside the email context is because HubSpot doesn’t support dynamic CRM queries (like crm_associations, crm_property, etc.) in marketing emails. These functions are only available in HubSpot’s CMS templates or custom modules, where server-side rendering is possible. Emails, on the other hand, are pre-rendered for each contact before send-out, and therefore can’t perform real-time lookups like these.
Suggested Workaround: Copy Associated Data to the Contact Record via Workflow
A good workaround is to use a HubSpot workflow to copy the properties you need from the associated object (like a Deal, Company, or Custom Object) directly into a custom property on the contact record.
Here’s how you can do it:
Create a custom property on the Contact object to store the value you need (e.g., associated deal owner email).
In a contact-based workflow, use the "Copy property value" action:
Once that’s done, you’ll be able to access the value in your marketing email using a simple personalization token like {{ contact.custom_property_name }}.
Why is it impossible to use crm_associations in an email with the contact’s ID?
SOLVE
Hi @panchitofrancia I read your thread and totally get the issue.
It’s frustrating that crm_associations doesn’t work with the current contact in emails. The workaround of copying values into contact properties isn’t ideal when there are many association labels.
If you have access to custom code actions (like with Operations Hub), there’s another option. You can use a small script in a workflow to pull data from associated records and save it into one contact property. Here’s a basic example
const hubspot = require('@hubspot/api-client');
exports.main = async (event, callback) => {
const hubspotClient = new hubspot.Client({ accessToken: process.env.HAPIKEY });
const contactId = event.object.objectId;
// Replace 2 with your object type ID (like deals, custom objects, etc.)
const ASSOCIATION_TYPE_ID = 2;
try {
const associations = await hubspotClient.crm.contacts.associationsApi.getAll(contactId, 'deals');
const dealIds = associations.results.map(a => a.id);
let emails = [];
for (const id of dealIds) {
const deal = await hubspotClient.crm.deals.basicApi.getById(id, ['dealname', 'hubspot_owner_id']);
emails.push(deal.body.properties.dealname); // or replace with the field you need
}
const summary = emails.join(', ');
// Save to contact property
await hubspotClient.crm.contacts.basicApi.update(contactId, {
properties: {
associated_summary: summary,
},
});
callback({ outputFields: {} });
} catch (e) {
console.error(e);
callback({ error: e });
}
};
This will grab the associated deals (or other object) and store the info into one field like associated_summary, which you can then use in your email like this: