From 5f450c69452613ff865e710e2b80e19c28215ff9 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Wed, 4 Nov 2026 11:40:09 +0100 Subject: [PATCH] fix: keep the work or home mark of a second address in Google's older contacts CSV --- lib/contacts/__tests__/csv-import.test.ts | 12 ++++++++++++ lib/contacts/csv-import.ts | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/contacts/__tests__/csv-import.test.ts b/lib/contacts/__tests__/csv-import.test.ts index 0b0a3463b..12e544af6 100644 --- a/lib/contacts/__tests__/csv-import.test.ts +++ b/lib/contacts/__tests__/csv-import.test.ts @@ -330,6 +330,18 @@ describe('Google Contacts', () => { expect(tom.keywords).toEqual({ Club: true }); expect(lea.name?.components).toEqual([{ kind: 'given', value: 'Lea' }, { kind: 'surname', value: 'van Probe' }]); }); + + // "E-mail 2 - Type" reads like Outlook's "E-mail 2 Type" (always SMTP) and + // was left out, so a second address lost its work or home mark. + it("keeps the type of the second and third address in Google's older format", () => { + const text = csv(GOOGLE_OLD_HEADERS, [{ + Name: 'Tom Testperson', 'E-mail 1 - Type': '* Home', 'E-mail 1 - Value': 'tom@example.org', + 'E-mail 2 - Type': 'Work', 'E-mail 2 - Value': 'tom@work.example.org', + }]); + const { columns, cards } = importText(text); + expect(target(columns, 'E-mail 2 - Type')).toBe('type'); + expect(Object.values(cards[0].emails ?? {})).toContainEqual({ address: 'tom@work.example.org', contexts: { work: true } }); + }); }); describe('column choices', () => { diff --git a/lib/contacts/csv-import.ts b/lib/contacts/csv-import.ts index b50baf339..156d4f073 100644 --- a/lib/contacts/csv-import.ts +++ b/lib/contacts/csv-import.ts @@ -263,10 +263,14 @@ function googleColumn(normalized: string): { family: CsvFamily; slot: string; fi /** Each column with a sample value and the field it goes to: known headers matched, the rest "Don't import". */ export function matchColumns(table: CsvTable): CsvColumn[] { + // Outlook's "E-mail 2 Type" and Google's older "E-mail 2 - Type" read the + // same once normalised; a "… - Value" column says the file is Google's. + const googleFile = table.headers.some((h) => /^(e mail|email|phone) \d+ value$/.test(normalizeHeader(h))); return table.headers.map((header, index) => { const sample = table.rows.map((r) => (r[index] ?? '').trim()).find((v) => v !== '') ?? ''; const normalized = normalizeHeader(header); - if (normalized in HEADER_TARGETS) return { index, header, sample, slot: '', target: HEADER_TARGETS[normalized] }; + const outlookSkip = HEADER_TARGETS[normalized] === 'skip' && googleFile && googleColumn(normalized); + if (normalized in HEADER_TARGETS && !outlookSkip) return { index, header, sample, slot: '', target: HEADER_TARGETS[normalized] }; const google = googleColumn(normalized); if (google) { return { index, header, sample, slot: google.slot, family: google.family, target: GOOGLE_FIELDS[google.family][google.field] ?? 'skip' };