diff --git a/apps/api/src/controllers/Actions.ts b/apps/api/src/controllers/Actions.ts index a124eef..b6dd680 100644 --- a/apps/api/src/controllers/Actions.ts +++ b/apps/api/src/controllers/Actions.ts @@ -275,6 +275,7 @@ export class Actions { // These are always available for template rendering const dataWithSystemVars = { ...mergedData, + id: contact.id, email: contact.email, data: mergedData, // Also available as nested data for {{data.fieldName}} syntax unsubscribeUrl: `${DASHBOARD_URI}/unsubscribe/${contact.id}`, diff --git a/apps/api/src/services/CampaignService.ts b/apps/api/src/services/CampaignService.ts index 75a1e03..8c4de37 100644 --- a/apps/api/src/services/CampaignService.ts +++ b/apps/api/src/services/CampaignService.ts @@ -451,6 +451,7 @@ export class CampaignService { const contactData = contact.data && typeof contact.data === 'object' && !Array.isArray(contact.data) ? contact.data : {}; const variables = { + id: contact.id, email: contact.email, ...contactData, data: contactData, diff --git a/apps/api/src/services/ContactService.ts b/apps/api/src/services/ContactService.ts index 7535326..e7f0b1d 100644 --- a/apps/api/src/services/ContactService.ts +++ b/apps/api/src/services/ContactService.ts @@ -221,7 +221,15 @@ export class ContactService { for (const [key, value] of Object.entries(data)) { // Skip reserved system-generated fields // These fields are dynamically added during template rendering and cannot be overridden - const reservedFields = ['plunk_id', 'plunk_email', 'email', 'unsubscribeUrl', 'subscribeUrl', 'manageUrl']; + const reservedFields = [ + 'plunk_id', + 'plunk_email', + 'id', + 'email', + 'unsubscribeUrl', + 'subscribeUrl', + 'manageUrl', + ]; if (reservedFields.includes(key)) { continue; } diff --git a/apps/api/src/services/EmailService.ts b/apps/api/src/services/EmailService.ts index 486d854..3ecc28b 100644 --- a/apps/api/src/services/EmailService.ts +++ b/apps/api/src/services/EmailService.ts @@ -333,6 +333,7 @@ export class EmailService { subject: email.subject, body: email.body, data: { + id: email.contact.id, email: email.contact.email, ...contactData, data: contactData, diff --git a/apps/api/src/services/WorkflowExecutionService.ts b/apps/api/src/services/WorkflowExecutionService.ts index 0d85483..1b90b6c 100644 --- a/apps/api/src/services/WorkflowExecutionService.ts +++ b/apps/api/src/services/WorkflowExecutionService.ts @@ -545,6 +545,7 @@ export class WorkflowExecutionService { : {}; const variables = { + id: contact.id, email: contact.email, ...contactData, ...executionContext, diff --git a/apps/web/src/components/EmailEditor/EmailEditor.tsx b/apps/web/src/components/EmailEditor/EmailEditor.tsx index afc76ec..4447200 100644 --- a/apps/web/src/components/EmailEditor/EmailEditor.tsx +++ b/apps/web/src/components/EmailEditor/EmailEditor.tsx @@ -44,6 +44,7 @@ interface EmailEditorProps { } const commonVariables = [ + {name: 'id', description: 'Contact ID'}, {name: 'email', description: 'Recipient email address'}, {name: 'unsubscribeUrl', description: 'Unsubscribe link'}, {name: 'subscribeUrl', description: 'Subscribe link'}, diff --git a/apps/web/src/components/EmailEditor/VariableMention.ts b/apps/web/src/components/EmailEditor/VariableMention.ts index d64e523..b409bd9 100644 --- a/apps/web/src/components/EmailEditor/VariableMention.ts +++ b/apps/web/src/components/EmailEditor/VariableMention.ts @@ -117,7 +117,7 @@ export const VariableMention = Mention.configure({ items: ({query}) => { const safeVariables = Array.isArray(availableVariables) ? availableVariables : []; - const allVariables = ['email', 'unsubscribeUrl', 'subscribeUrl', 'manageUrl', 'locale', ...safeVariables]; + const allVariables = ['id', 'email', 'unsubscribeUrl', 'subscribeUrl', 'manageUrl', 'locale', ...safeVariables]; const uniqueVariables = Array.from(new Set(allVariables)).filter(v => typeof v === 'string'); if (!query) {