Thursday, September 27, 2012

Cleaner Export of Mac Address Book Contacts to Google Contacts

For years I've been trying to keep my contacts in sync on a million devices. If you ONLY use Apple products, or ONLY use Google products, their solutions probably work.

But I use Apple and Google products, specifically Apple Contacts (formerly Address Book) and Google Mail. Since I'm often sending Google Mail from the Google website, I need my Contacts available there too.

The Mac OS X Contacts app does provide a Google sync option, but it's strange to me. You can only sync from the "On My Mac" Contacts, which means you might have iCloud Contacts, On My Mac Contacts, and Google Contacts.

You can export all of your Contacts into a VCF file, and import into Google pretty easily, except I think there's a bug in that flow somewhere. I use a lot of contacts (in the Contacts app) that are tagged as a "Company", like "Jack's Pizza". In general, I don't have a name (first or last) associated with Jack's Pizza (I don't know Jack!), and I'd like the entry to show up under the J's. This works fine in Apple's app, but when you export the VCF file, you get this:

PRODID:-//Apple Inc.//Mac OS X 10.8.2//EN
FN:Jack's Pizza
ORG:Jack's Pizza;
CATEGORIES:Business (home)

When you import that into Google, you get this:

Since the VCF has a single entry for "FN" (First Name), Google decides that it really should split it into a First and Last name, and it doesn't sort correctly (for me).  I think Apple's bug is putting an FN entry in the VCF when it wasn't in the Contact to start with, and Google's bug is splitting the FN into First and Last.

Well, I could ask Apple and/or Google to change... or I could just cleanup the VCF file!

Here's a simple Perl script to cleanup the VCF file (works with a single entry, or your entire Contacts list).  Your mileage may vary, but it's made exporting my Apple Contacts to Google easy and consistent for the first time in YEARS.


use strict;
use warnings;

if (scalar(@ARGV) < 1) {
    die "USAGE: $0 \n\nThis script cleans up the Apple Contacts VCARD export file,\nmaking it suitable for import to Google Contacts.\n";
my $input = $ARGV[0];
if ($input !~ m/\.vcf$/) {
    die "USAGE: $0 \n\nThis script cleans up the Apple Contacts VCARD export file,\nmaking it suitable for import to Google Contacts.\n";

my $output = $input;
$output =~ s/.vcf$/_new.vcf/;

    local $/ = "END:VCARD\r\n";
    open(IN, "$input") or die "$!\n";
    open(OUT, ">$output") or die "$!\n";
    while() {
        my $card = $_;
        my $isCompany = 0;
        if (grep(/X-ABShowAs:COMPANY/, $card)) {
            $isCompany = 1;
        my @card = split(/\r\n/, $card);
        foreach my $line (@card) {
            if ($isCompany && ($line =~ m/^FN:/)) {
                # skip this line!
            else {
                # print out this line
                print OUT "$line\r\n";

print "Done!\n";

Let me know if that helps anyone else!