Salesforce to Zoho Migration: How GetOnCRM Extracted Classic Attachments, Modern Files and Notes

When the client decided to move its CRM from Salesforce to Zoho, the biggest risk was not the records. It was everything attached to them: years of Classic attachments, modern Salesforce Files, Chatter uploads and Notes with image links. With more than 20 lakh (2 million) records in scope and Zoho accepting only 4 GB of data per import, a single bulk export was never an option. GetOnCRM, a Salesforce consulting partner, built a purpose-made Salesforce attachment migration toolkit that extracts all three content types and splits them into 4 GB chunks, in the exact folder structure, CSV layouts and ZIP format Zoho’s importer expects. The result is a repeatable, auditable, resumable extraction process that tells the team precisely what was delivered, what was held back and why, before anything is sent for import.
architecture_walkthrough

Client Background

The client is a global medical device company focused on musculoskeletal care, with a portfolio spanning spine, orthopedic trauma, joint reconstruction, regenerative biologics and surgical navigation and imaging technology. Its mission is to improve the quality of life of patients with musculoskeletal disorders, and its commercial teams work closely with surgeons and healthcare providers around the world. For a business like this, the relationships and history captured in the CRM are a working asset, not an archive.

After years on Salesforce, the client made a strategic decision to consolidate onto Zoho. Its Salesforce org held content in three generations of storage: Classic Attachments, the modern ContentDocument and ContentVersion file model, and Notes, each with its own object model, its own limits and its own quirks.

A CRM migration is judged by how much of the business history survives it. For a medical technology company, the documents and notes tied to accounts and customer records had to arrive in Zoho linked to the right parent records, with ownership and timestamps intact. That made a dependable Salesforce data extraction process a precondition for the whole programme, not an afterthought.

Challenges Faced

Salesforce stores files in ways that do not export cleanly. The client and the Zoho import team faced several specific obstacles:

Three storage models, three behaviours

Classic attachments, modern Files and Notes are queried differently, packaged differently and linked to records differently. A single generic export would have missed or mangled at least one.

Salesforce query restrictions

A ContentDocumentLink cannot be queried on its own, and it carries no created date. “Give me every file in this date range” is not a question Salesforce will answer directly.

Files that belong to more than one place

One file can be linked to several records, or posted to Chatter as well. Without careful de-duplication, files are delivered twice or lose their relationships.

Scale against a hard import limit

The migration involved more than 20 lakh (2 million) records, yet Zoho accepts only 4 GB of data at a time. The full data set had to be broken into import-sized chunks without separating a file from its metadata or its parent record.

Strict target requirements

he Zoho import expects defined CSV headers, a specific folder naming convention, ZIP archives up to a set size, and Deflate-compressed ZIP members. Anything else is rejected.

Notes with inline images

Images pasted into Notes are not files that travel with the note; they are stored in Salesforce and referenced by link. The team had to decide how to handle them without losing the reference, and to know exactly which notes were affected.

Volume, limits and interruptions

Large extractions run into API call allowances, disk space and timeouts. A multi-day run that cannot resume is a run nobody trusts.

Failures that must be traceable

When Zoho reports a file that failed to import, the team needed a fast, targeted way to re-extract only that file.

Solution & Key Components

GetOnCRM designed a Salesforce-to-Zoho extraction toolkit around three clearly separated workstreams, one each for Classic, Modern and SNotes, sharing a common core for packaging, validation and reporting. Every open client decision was built as a configuration switch rather than hard-coded, so decisions could be made late without rewriting code.
Solution & Key Components
Classic Attachment Extraction
Classic attachments are extracted object by object, preserving the established folder convention (__, with numbered buckets for normal files and a separate large-file bucket). Each bucket contains a compressed Attachments.zip and a matching Attachment.csv. Because this path was already in use, the design deliberately left its behaviour unchanged, so the customer’s existing expectations held.

Modern extraction runs across all objects in a single pass and also captures files posted to Chatter, so the customer no longer has to run object-by-object or manage a separate feed export. To work within Salesforce’s query restrictions, the tool starts from the documents, applies the date filter there, and then reads links, feed attachments, posts, comments and latest versions by Id in safe batches. The key behaviours:

  • One file, delivered once. A file linked to many records appears once in the ZIP, with one metadata row per record.
  • Chatter handled natively. A file posted to a feed carries the post or comment Id as its parent, so the relationship is preserved rather than flattened.
  • Configurable scope. Share types, excluded objects, date field and treatment of files linked only to users are all switches, with an unlinked-files report so nothing quietly disappears.
  • Large files separated. Files above a configurable threshold go to dedicated buckets, and ZIP size is a parameter, never splitting a file across archives.

Notes are delivered as Notes.csv using Zoho’s own note-import headers, with owner, creator and modifier email addresses resolved from Salesforce users. Note content retains Salesforce’s original markup, so inline images were not migrated as files. They remain directly linked through their image links within the note content. Alongside it, Notes_Images.csv lists every inline image, classifies where it is hosted and whether it will display in Zoho, and states the recommended follow-up action. The client can see exactly which notes carry image links and which need attention, with no surprises after go-live.

Zoho can take only 4 GB at a time, so the toolkit packages everything into numbered buckets capped at 4 GB each (the cap is a parameter, set to 4,096 MB). Each bucket holds one Attachments.zip and a matching Attachment.csv listing only the files inside that ZIP, so every chunk can be imported on its own. Files are never split across archives, and files of 100 MB or more go into their own large-file buckets. With more than 20 lakh records, this meant the migration ran as a sequence of manageable, independently verifiable import batches instead of one unmanageable transfer.

Built for long-running extractions, the toolkit estimates API usage and disk needs before it starts, monitors both while running, and stops cleanly rather than failing mid-file. Downloads are atomic and logged, so an interrupted run resumes without re-downloading what it already has. A dry-run mode provides counts, size estimates and projected API usage before a single file moves.
Every run is checked before it is called finished. A two-part count check confirms that every file found is accounted for as delivered, not delivered, held or failed, and that the files named in the CSVs match the files in the ZIPs and the files downloaded. Each run produces its own report folder, including a query trail, packaging summary, unlinked-file and failure lists, and a plain-language read-me. A run ends in a clear status of SUCCESS, PARTIAL, FAILED or DRY_RUN, each with a defined next step. Only SUCCESS output is cleared for sending to Zoho.

When Zoho flags files that failed to import, an error file can be fed straight back into a dedicated re-extraction tool. It checks the input before touching Salesforce, re-fetches only the affected files with all their current parents, and produces a status for each file. A fetch-sample report documents every step, including queries, downloads and checksums, without exposing credentials.

Results & Outcomes

Complete, Traceable Coverage

Classic attachments, modern Files, Chatter uploads and Notes are all covered by one toolkit with one operating model. Nothing is silently dropped: every file is either delivered or listed with the reason it was not.

20 Lakh+ Records Migrated in Import-Sized Chunks

More than 20 lakh (2 million) records were extracted and delivered as a series of 4 GB packages that respect Zoho's import limit, each self-contained and each reconciled before it was sent.

Output Zoho Can Ingest First Time

Folder names, CSV headers, ZIP size limits and compression method are all aligned to Zoho's import specification and enforced by validation, which removes a common source of rejected batches.

Confidence Before Cut-over

Dry runs, preflight API and disk checks, a built-in count check and per-run reports mean the team can judge readiness from evidence rather than assumption. Keeping images as direct links, backed by an image register for Notes, kept the transfer light and turned an unknown risk into a managed list.

Lower Operational Risk

Resumable downloads, clean stops at API and disk limits, and targeted re-extraction mean an interruption or a rejected file becomes a short, scoped task instead of a restart.

Flexible by Design

Decisions on naming, scope, user-linked files and date logic were handled through configuration and recorded in a decision log, so the customer's choices could change without code changes and every run records the rules it ran under.

Why Salesforce Data Expertise Matters for CRM Migration

Moving off a CRM is only as successful as the history that travels with it. Files and notes are where much of the commercial context lives, and they are the hardest data in Salesforce to extract faithfully. A few themes stand out for any organization planning a similar move:

Know the data model, not just the export button. Salesforce stores content across multiple generations of objects with real constraints on how they can be queried. Experience with those internals is what makes a complete extraction possible.

Scale demands engineering. Large attachment volumes call for batching, resumability and limit-awareness, not manual downloads.

Auditability builds trust. Stakeholders signing off a migration need proof of completeness. Reconciled counts and run reports provide it.

The target system sets the rules. A good extraction is shaped by what the destination can import, which is why close coordination between source and target teams matters.

Whether you are leaving Salesforce, consolidating orgs or planning a large-scale Salesforce data migration, GetOnCRM brings the platform depth and the tooling to protect your data on the way through. Talk to our team about your migration.

Salesforce Data Expertise Matters for CRM Migration

Recent Case Studies