Guide

Export Email Data to HubSpot

Your inbox already contains the contacts, companies, and engagement history that HubSpot needs. This guide shows how to extract that data with Nylas CLI and push it into HubSpot CRM — via CSV import for one-time loads or the API v3 for continuous sync.

Why sync email data to HubSpot

Most HubSpot CRM instances suffer from stale data. Sales reps forget to log emails, contacts are created manually with typos, and engagement history is incomplete. Your inbox already has the ground truth — every email is timestamped, every sender has a verified address, and reply patterns reveal actual engagement.

Syncing email data to HubSpot solves three problems at once. First, auto-logged emails eliminate the “did you log that call?” problem — every email interaction is captured as an Engagement object in HubSpot. Second, enriched contacts get real names, email addresses, and company associations from actual email headers instead of manual entry. Third, engagement tracking gives you reply frequency, last-contact dates, and thread counts that power HubSpot lead scoring and workflow triggers.

The Nylas CLI makes the export side trivial. One command gives you structured JSON with sender names, email addresses, timestamps, subject lines, and message bodies. The rest of this guide shows you how to map that data to HubSpot's object model and push it in via CSV or API.

Export data from Nylas CLI

Start by exporting your recent emails and contacts as JSON. These two commands give you everything you need for HubSpot import:

# Export recent emails (sender, subject, date, body snippet)
nylas email list --json --limit 500 > emails.json

# Export contacts (names, emails, phone numbers, companies)
nylas contacts list --json --limit 500 > contacts.json

To export a specific email with its full body and headers:

# Read a single email by ID
nylas email read abc123def --json > email-detail.json

Inspect the structure of your exported data to understand what fields are available:

# Preview email fields
cat emails.json | jq '.[0] | keys'
# Typical output: ["bcc","body","cc","date","from","id","labels","snippet","subject","thread_id","to","unread"]

# Preview contact fields
cat contacts.json | jq '.[0] | keys'
# Typical output: ["company_name","email","given_name","id","job_title","phone_numbers","surname"]

HubSpot object model mapping

HubSpot organizes CRM data into four core objects: Contacts, Companies, Deals, and Engagements. Here is how your Nylas CLI export maps to each:

Nylas fieldHubSpot objectHubSpot property
from[0].emailContactemail
from[0].name (first part)Contactfirstname
from[0].name (last part)Contactlastname
from[0].email (domain part)Companydomain
phone_numbers[0]Contactphone
subject + bodyEngagementtype: EMAIL
company_nameCompanyname

HubSpot uses email as the unique identifier for Contacts and domain as the unique identifier for Companies. This means you can safely upsert — if a contact already exists, HubSpot updates the existing record instead of creating a duplicate.

CSV import via HubSpot Import tool

For a one-time or occasional import, HubSpot's built-in Import tool accepts CSV files. Use jq to transform your Nylas CLI export into the exact CSV headers HubSpot expects:

# Transform emails.json into HubSpot Contacts CSV
cat emails.json | jq -r '
  [.[] | .from[0] | select(.email != null)] | unique_by(.email) |
  ["Email","First Name","Last Name"] as $header |
  ($header | @csv),
  (.[] | [
    .email,
    (.name // "" | split(" ")[0] // ""),
    (.name // "" | split(" ")[1:] | join(" ") // "")
  ] | @csv)
' > hubspot-contacts.csv

echo "Created hubspot-contacts.csv with $(wc -l < hubspot-contacts.csv) rows"

For Companies, extract unique domains from your email data:

# Transform emails.json into HubSpot Companies CSV
cat emails.json | jq -r '
  [.[] | .from[0].email | select(. != null) | split("@")[1]] |
  unique |
  [.[] | select(. | IN("gmail.com","yahoo.com","outlook.com","hotmail.com") | not)] |
  ["Company Domain Name"] as $header |
  ($header | @csv),
  (.[] | [.] | @csv)
' > hubspot-companies.csv

echo "Created hubspot-companies.csv with $(wc -l < hubspot-companies.csv) rows"

If you have contact data with phone numbers, create a richer CSV:

# Transform contacts.json into HubSpot Contacts CSV with phone and company
cat contacts.json | jq -r '
  [.[] | select(.email != null)] | unique_by(.email) |
  ["Email","First Name","Last Name","Phone Number","Company Name"] as $header |
  ($header | @csv),
  (.[] | [
    (.email // ""),
    (.given_name // ""),
    (.surname // ""),
    (.phone_numbers[0] // ""),
    (.company_name // "")
  ] | @csv)
' > hubspot-contacts-full.csv

To import in HubSpot: go to Contacts → Import → Start an import → File from computer. Select the object type (Contacts or Companies), upload your CSV, and map the columns. HubSpot will match by email (Contacts) or domain (Companies) and upsert existing records.

HubSpot API v3 import

For automated or recurring imports, use the HubSpot API v3 directly. You need a private app token from your HubSpot account (Settings → Integrations → Private Apps). The token needs crm.objects.contacts.write and crm.objects.companies.write scopes.

Create or update a contact:

# Create a contact via HubSpot API v3
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts" \
  -H "Authorization: Bearer $HUBSPOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "email": "jane@acme.com",
      "firstname": "Jane",
      "lastname": "Smith",
      "phone": "+1-555-0123",
      "company": "Acme Corp"
    }
  }'

Create an email engagement and associate it with a contact:

# Create an email engagement via HubSpot API v3
CONTACT_ID="123456"

curl -s -X POST "https://api.hubapi.com/crm/v3/objects/emails" \
  -H "Authorization: Bearer $HUBSPOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "hs_timestamp": "2026-03-13T10:00:00.000Z",
      "hs_email_direction": "INCOMING_EMAIL",
      "hs_email_subject": "Re: Q1 Proposal",
      "hs_email_text": "Thanks for sending over the proposal. Let us schedule a call to discuss.",
      "hs_email_status": "SENT",
      "hs_email_sender_email": "jane@acme.com",
      "hs_email_to_email": "you@yourcompany.com"
    },
    "associations": [
      {
        "to": { "id": "'"$CONTACT_ID"'" },
        "types": [
          { "associationCategory": "HUBSPOT_DEFINED", "associationTypeId": 198 }
        ]
      }
    ]
  }'

Batch create contacts (up to 100 per request):

# Batch create contacts from Nylas CLI export
cat emails.json | jq '{
  "inputs": [
    .[:100][] | .from[0] | select(.email != null) |
    {
      "properties": {
        "email": .email,
        "firstname": (.name // "" | split(" ")[0] // ""),
        "lastname": (.name // "" | split(" ")[1:] | join(" ") // "")
      }
    }
  ]
}' | curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts/batch/create" \
  -H "Authorization: Bearer $HUBSPOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d @-

Associate contacts with companies

HubSpot Contacts and Companies are separate objects. To link them, use the Associations API. This is important because HubSpot uses associations to show which contacts belong to which company in the CRM sidebar.

# First, create or find the company by domain
COMPANY_ID=$(curl -s -X POST "https://api.hubapi.com/crm/v3/objects/companies/search" \
  -H "Authorization: Bearer $HUBSPOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filterGroups": [{
      "filters": [{
        "propertyName": "domain",
        "operator": "EQ",
        "value": "acme.com"
      }]
    }]
  }' | jq -r '.results[0].id')

# If no company exists, create one
if [ "$COMPANY_ID" = "null" ] || [ -z "$COMPANY_ID" ]; then
  COMPANY_ID=$(curl -s -X POST "https://api.hubapi.com/crm/v3/objects/companies" \
    -H "Authorization: Bearer $HUBSPOT_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "properties": {
        "domain": "acme.com",
        "name": "Acme Corp"
      }
    }' | jq -r '.id')
  echo "Created company: $COMPANY_ID"
fi

# Associate contact with company (association type 1 = Contact to Company)
CONTACT_ID="123456"
curl -s -X PUT \
  "https://api.hubapi.com/crm/v3/objects/contacts/$CONTACT_ID/associations/companies/$COMPANY_ID/1" \
  -H "Authorization: Bearer $HUBSPOT_TOKEN"

echo "Associated contact $CONTACT_ID with company $COMPANY_ID"

Scheduled sync script

Automate the export-and-import cycle with a cron job. The following script exports new emails since the last sync and pushes contacts and engagements to HubSpot:

#!/usr/bin/env bash
set -euo pipefail

# Configuration
HUBSPOT_TOKEN="${HUBSPOT_TOKEN:?Set HUBSPOT_TOKEN env var}"
SYNC_STATE_FILE="${HOME}/.nylas-hubspot-sync-state"
LOG_FILE="${HOME}/.nylas-hubspot-sync.log"

log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" >> "$LOG_FILE"; }

# Read last sync timestamp (default: 7 days ago)
if [ -f "$SYNC_STATE_FILE" ]; then
  LAST_SYNC=$(cat "$SYNC_STATE_FILE")
else
  LAST_SYNC=$(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ)
fi

log "Starting sync. Last sync: $LAST_SYNC"

# Export recent emails
nylas email list --json --limit 200 > /tmp/hubspot-emails.json
EMAIL_COUNT=$(cat /tmp/hubspot-emails.json | jq 'length')
log "Exported $EMAIL_COUNT emails"

# Extract unique contacts
cat /tmp/hubspot-emails.json | jq '[.[] | .from[0] | select(.email != null)] | unique_by(.email)' > /tmp/hubspot-new-contacts.json
CONTACT_COUNT=$(cat /tmp/hubspot-new-contacts.json | jq 'length')
log "Found $CONTACT_COUNT unique contacts"

# Batch upsert contacts (100 at a time)
cat /tmp/hubspot-new-contacts.json | jq -c '[.[] | {
  "properties": {
    "email": .email,
    "firstname": (.name // "" | split(" ")[0] // ""),
    "lastname": (.name // "" | split(" ")[1:] | join(" ") // "")
  }
}]' | jq -c '[_nwise(100)][]' | while read -r BATCH; do
  RESPONSE=$(echo "{\"inputs\": $BATCH}" | curl -s -X POST \
    "https://api.hubapi.com/crm/v3/objects/contacts/batch/create" \
    -H "Authorization: Bearer $HUBSPOT_TOKEN" \
    -H "Content-Type: application/json" \
    -d @-)

  CREATED=$(echo "$RESPONSE" | jq '.results | length // 0')
  ERRORS=$(echo "$RESPONSE" | jq '.errors | length // 0')
  log "Batch: created=$CREATED errors=$ERRORS"
done

# Save sync timestamp
date -u +%Y-%m-%dT%H:%M:%SZ > "$SYNC_STATE_FILE"
log "Sync complete. State saved."
echo "Sync complete. See $LOG_FILE for details."

Schedule with cron to run every hour:

# Run every hour
crontab -e
# Add this line:
0 * * * * HUBSPOT_TOKEN="your-token-here" /path/to/hubspot-sync.sh

Full Python version

The Python version uses the official hubspot-api-client package for type-safe API calls and built-in retry logic. Install it with pip:

pip install hubspot-api-client
#!/usr/bin/env python3
"""Export email data from Nylas CLI and sync to HubSpot CRM."""

import json
import subprocess
import sys
from datetime import datetime, timezone

from hubspot import HubSpot
from hubspot.crm.contacts import SimplePublicObjectInputForCreate
from hubspot.crm.companies import SimplePublicObjectInputForCreate as CompanyInput
from hubspot.crm.objects.emails import SimplePublicObjectInputForCreate as EmailInput
from hubspot.crm.associations.v4 import AssociationSpec


def run_nylas(command: list[str]) -> list[dict]:
    """Run a Nylas CLI command and return parsed JSON."""
    result = subprocess.run(
        ["nylas"] + command + ["--json"],
        capture_output=True,
        text=True,
        check=True,
    )
    return json.loads(result.stdout)


def split_name(full_name: str) -> tuple[str, str]:
    """Split a display name into first and last name."""
    parts = full_name.strip().split(" ", 1) if full_name else ["", ""]
    return parts[0], parts[1] if len(parts) > 1 else ""


def extract_domain(email_address: str) -> str:
    """Extract the domain from an email address."""
    return email_address.split("@")[1] if "@" in email_address else ""


FREEMAIL_DOMAINS = {
    "gmail.com", "yahoo.com", "outlook.com", "hotmail.com",
    "aol.com", "icloud.com", "mail.com", "protonmail.com",
}


def main():
    import os

    token = os.environ.get("HUBSPOT_TOKEN")
    if not token:
        print("Set HUBSPOT_TOKEN environment variable", file=sys.stderr)
        sys.exit(1)

    api = HubSpot(access_token=token)

    # Step 1: Export emails and contacts from Nylas CLI
    print("Exporting emails from Nylas CLI...")
    emails = run_nylas(["email", "list", "--limit", "200"])
    print(f"  Exported {len(emails)} emails")

    print("Exporting contacts from Nylas CLI...")
    contacts = run_nylas(["contacts", "list", "--limit", "200"])
    print(f"  Exported {len(contacts)} contacts")

    # Step 2: Deduplicate senders by email address
    seen_emails: set[str] = set()
    unique_senders: list[dict] = []
    for msg in emails:
        sender = msg.get("from", [{}])[0]
        addr = sender.get("email", "")
        if addr and addr not in seen_emails:
            seen_emails.add(addr)
            unique_senders.append(sender)

    print(f"  {len(unique_senders)} unique senders")

    # Step 3: Create or update contacts in HubSpot
    created, updated, errors = 0, 0, 0
    contact_id_map: dict[str, str] = {}  # email -> HubSpot contact ID

    for sender in unique_senders:
        email_addr = sender["email"]
        first, last = split_name(sender.get("name", ""))

        try:
            # Search for existing contact
            search_response = api.crm.contacts.search_api.do_search(
                public_object_search_request={
                    "filter_groups": [{
                        "filters": [{
                            "property_name": "email",
                            "operator": "EQ",
                            "value": email_addr,
                        }]
                    }],
                    "limit": 1,
                }
            )

            if search_response.total > 0:
                # Update existing contact
                contact_id = search_response.results[0].id
                api.crm.contacts.basic_api.update(
                    contact_id=contact_id,
                    simple_public_object_input={
                        "properties": {
                            "firstname": first,
                            "lastname": last,
                        }
                    },
                )
                contact_id_map[email_addr] = contact_id
                updated += 1
            else:
                # Create new contact
                response = api.crm.contacts.basic_api.create(
                    simple_public_object_input_for_create=SimplePublicObjectInputForCreate(
                        properties={
                            "email": email_addr,
                            "firstname": first,
                            "lastname": last,
                        }
                    )
                )
                contact_id_map[email_addr] = response.id
                created += 1

        except Exception as e:
            print(f"  Error processing {email_addr}: {e}", file=sys.stderr)
            errors += 1

    print(f"  Contacts: {created} created, {updated} updated, {errors} errors")

    # Step 4: Create companies from domains
    domains_seen: set[str] = set()
    company_id_map: dict[str, str] = {}  # domain -> HubSpot company ID

    for sender in unique_senders:
        domain = extract_domain(sender["email"])
        if not domain or domain in FREEMAIL_DOMAINS or domain in domains_seen:
            continue
        domains_seen.add(domain)

        try:
            # Search for existing company
            search_response = api.crm.companies.search_api.do_search(
                public_object_search_request={
                    "filter_groups": [{
                        "filters": [{
                            "property_name": "domain",
                            "operator": "EQ",
                            "value": domain,
                        }]
                    }],
                    "limit": 1,
                }
            )

            if search_response.total > 0:
                company_id_map[domain] = search_response.results[0].id
            else:
                response = api.crm.companies.basic_api.create(
                    simple_public_object_input_for_create=CompanyInput(
                        properties={
                            "domain": domain,
                            "name": domain.split(".")[0].title(),
                        }
                    )
                )
                company_id_map[domain] = response.id
                print(f"  Created company: {domain} (ID: {response.id})")

        except Exception as e:
            print(f"  Error creating company {domain}: {e}", file=sys.stderr)

    print(f"  Companies: {len(company_id_map)} total")

    # Step 5: Associate contacts with companies
    for sender in unique_senders:
        email_addr = sender["email"]
        domain = extract_domain(email_addr)
        contact_id = contact_id_map.get(email_addr)
        company_id = company_id_map.get(domain)

        if contact_id and company_id:
            try:
                api.crm.associations.v4.basic_api.create(
                    object_type="contacts",
                    object_id=contact_id,
                    to_object_type="companies",
                    to_object_id=company_id,
                    association_spec=[
                        AssociationSpec(
                            association_category="HUBSPOT_DEFINED",
                            association_type_id=1,
                        )
                    ],
                )
            except Exception:
                pass  # association may already exist

    print("  Associations created")

    # Step 6: Log email engagements
    engagement_count = 0
    for msg in emails[:100]:  # limit to 100 most recent
        sender = msg.get("from", [{}])[0]
        email_addr = sender.get("email", "")
        contact_id = contact_id_map.get(email_addr)
        if not contact_id:
            continue

        try:
            ts = msg.get("date", "")
            if isinstance(ts, int):
                ts = datetime.fromtimestamp(ts, tz=timezone.utc).isoformat()

            api.crm.objects.emails.basic_api.create(
                simple_public_object_input_for_create=EmailInput(
                    properties={
                        "hs_timestamp": ts,
                        "hs_email_direction": "INCOMING_EMAIL",
                        "hs_email_subject": msg.get("subject", ""),
                        "hs_email_text": msg.get("snippet", ""),
                        "hs_email_status": "SENT",
                        "hs_email_sender_email": email_addr,
                    },
                    associations=[{
                        "to": {"id": contact_id},
                        "types": [{
                            "associationCategory": "HUBSPOT_DEFINED",
                            "associationTypeId": 198,
                        }],
                    }],
                )
            )
            engagement_count += 1

        except Exception as e:
            print(f"  Error logging engagement: {e}", file=sys.stderr)

    print(f"  Engagements logged: {engagement_count}")
    print("Sync complete.")


if __name__ == "__main__":
    main()

Full TypeScript version

The TypeScript version uses the official @hubspot/api-client package. Install dependencies:

npm install @hubspot/api-client
import { Client } from "@hubspot/api-client";
import { execFileSync } from "child_process";

const FREEMAIL_DOMAINS = new Set([
  "gmail.com", "yahoo.com", "outlook.com", "hotmail.com",
  "aol.com", "icloud.com", "mail.com", "protonmail.com",
]);

interface NylasSender {
  email: string;
  name?: string;
}

interface NylasEmail {
  id: string;
  from: NylasSender[];
  to: NylasSender[];
  subject: string;
  snippet: string;
  date: string | number;
  thread_id: string;
}

interface NylasContact {
  id: string;
  email: string;
  given_name?: string;
  surname?: string;
  company_name?: string;
  phone_numbers?: string[];
}

function runNylas(args: string[]): unknown[] {
  const result = execFileSync("nylas", [...args, "--json"], {
    encoding: "utf-8",
    maxBuffer: 50 * 1024 * 1024,
  });
  return JSON.parse(result);
}

function splitName(name: string | undefined): [string, string] {
  if (!name) return ["", ""];
  const parts = name.trim().split(" ");
  return [parts[0] ?? "", parts.slice(1).join(" ")];
}

function extractDomain(email: string): string {
  const at = email.indexOf("@");
  return at > -1 ? email.slice(at + 1) : "";
}

async function main() {
  const token = process.env.HUBSPOT_TOKEN;
  if (!token) {
    console.error("Set HUBSPOT_TOKEN environment variable");
    process.exit(1);
  }

  const hubspot = new Client({ accessToken: token });

  // Step 1: Export from Nylas CLI
  console.log("Exporting emails from Nylas CLI...");
  const emails = runNylas(["email", "list", "--limit", "200"]) as NylasEmail[];
  console.log(`  Exported ${emails.length} emails`);

  console.log("Exporting contacts from Nylas CLI...");
  const contacts = runNylas(["contacts", "list", "--limit", "200"]) as NylasContact[];
  console.log(`  Exported ${contacts.length} contacts`);

  // Step 2: Deduplicate senders
  const seenEmails = new Set<string>();
  const uniqueSenders: NylasSender[] = [];

  for (const msg of emails) {
    const sender = msg.from?.[0];
    if (sender?.email && !seenEmails.has(sender.email)) {
      seenEmails.add(sender.email);
      uniqueSenders.push(sender);
    }
  }
  console.log(`  ${uniqueSenders.length} unique senders`);

  // Step 3: Create or update contacts
  const contactIdMap = new Map<string, string>();
  let created = 0;
  let updated = 0;

  for (const sender of uniqueSenders) {
    const [firstname, lastname] = splitName(sender.name);

    try {
      const search = await hubspot.crm.contacts.searchApi.doSearch({
        filterGroups: [{
          filters: [{
            propertyName: "email",
            operator: "EQ",
            value: sender.email,
          }],
        }],
        limit: 1,
        sorts: [],
        properties: [],
        after: "0",
      });

      if (search.total > 0) {
        const id = search.results[0].id;
        await hubspot.crm.contacts.basicApi.update(id, {
          properties: { firstname, lastname },
        });
        contactIdMap.set(sender.email, id);
        updated++;
      } else {
        const response = await hubspot.crm.contacts.basicApi.create({
          properties: { email: sender.email, firstname, lastname },
          associations: [],
        });
        contactIdMap.set(sender.email, response.id);
        created++;
      }
    } catch (err) {
      console.error(`  Error processing ${sender.email}: ${err}`);
    }
  }
  console.log(`  Contacts: ${created} created, ${updated} updated`);

  // Step 4: Create companies from domains
  const companyIdMap = new Map<string, string>();
  const domainsSeen = new Set<string>();

  for (const sender of uniqueSenders) {
    const domain = extractDomain(sender.email);
    if (!domain || FREEMAIL_DOMAINS.has(domain) || domainsSeen.has(domain)) continue;
    domainsSeen.add(domain);

    try {
      const search = await hubspot.crm.companies.searchApi.doSearch({
        filterGroups: [{
          filters: [{
            propertyName: "domain",
            operator: "EQ",
            value: domain,
          }],
        }],
        limit: 1,
        sorts: [],
        properties: [],
        after: "0",
      });

      if (search.total > 0) {
        companyIdMap.set(domain, search.results[0].id);
      } else {
        const response = await hubspot.crm.companies.basicApi.create({
          properties: {
            domain,
            name: domain.split(".")[0].charAt(0).toUpperCase() +
              domain.split(".")[0].slice(1),
          },
          associations: [],
        });
        companyIdMap.set(domain, response.id);
        console.log(`  Created company: ${domain} (ID: ${response.id})`);
      }
    } catch (err) {
      console.error(`  Error creating company ${domain}: ${err}`);
    }
  }
  console.log(`  Companies: ${companyIdMap.size} total`);

  // Step 5: Associate contacts with companies
  for (const sender of uniqueSenders) {
    const domain = extractDomain(sender.email);
    const contactId = contactIdMap.get(sender.email);
    const companyId = companyIdMap.get(domain);

    if (contactId && companyId) {
      try {
        await hubspot.crm.associations.v4.basicApi.create(
          "contacts",
          contactId,
          "companies",
          companyId,
          [{
            associationCategory: "HUBSPOT_DEFINED",
            associationTypeId: 1,
          }],
        );
      } catch {
        // association may already exist
      }
    }
  }
  console.log("  Associations created");

  // Step 6: Log email engagements
  let engagementCount = 0;
  for (const msg of emails.slice(0, 100)) {
    const sender = msg.from?.[0];
    if (!sender?.email) continue;
    const contactId = contactIdMap.get(sender.email);
    if (!contactId) continue;

    const ts = typeof msg.date === "number"
      ? new Date(msg.date * 1000).toISOString()
      : String(msg.date);

    try {
      await hubspot.crm.objects.emails.basicApi.create({
        properties: {
          hs_timestamp: ts,
          hs_email_direction: "INCOMING_EMAIL",
          hs_email_subject: msg.subject ?? "",
          hs_email_text: msg.snippet ?? "",
          hs_email_status: "SENT",
          hs_email_sender_email: sender.email,
        },
        associations: [{
          to: { id: contactId },
          types: [{
            associationCategory: "HUBSPOT_DEFINED",
            associationTypeId: 198,
          }],
        }],
      });
      engagementCount++;
    } catch (err) {
      console.error(`  Error logging engagement: ${err}`);
    }
  }
  console.log(`  Engagements logged: ${engagementCount}`);
  console.log("Sync complete.");
}

main();

Next steps

Now that your email data flows into HubSpot, explore more ways to extract CRM intelligence from your inbox: