Wed, 21 Jul 2004

Exporting Your Evolution Address Book for Gmail

When logging onto my Gmail account today, I noticed a new, highlighted link near the top of the screen titled “New Features!”. After investigating these new features, I discovered that Gmail now allows you to import contact information via an uploaded CSV (comma seperated value) file. Great!

I use Evolution on my Gnome Linux desktop to manage my email and contacts. Looking through the various menus, I realized that there is no way (which I could see) to export my contacts file to a CSV file. Ug! However, since Evolution is Open Source software, that meant that the file format for the address database was not proprietary, and hence that someone else out there had probably already solved this problem. So, doing a Google search for exporting evolution contacts to CSV files, and I stumble upon this page which provides a python and perl script to accomplish the task. I downloaded the scripts and crossed my fingers...

Hmmmm. No joy. It was time to get my hands a bit dirty and mingle with the code, to try and figure out what was going on. The python script worked fine once I made sure that /usr/env/python2 pointed to the latest version of python installed on my system (version 2.3) instead of version 2.0, which it was stuck on. It turns out that Evolution stores the contact information using the Berkely DB (version 7) format. The python script opens up the evolution contact database (addressbook.db), and then outputs the contact information in VCARD format to standard output.

Here is the python script, named exportevolution.py:

#!/usr/bin/python2

import bsddb, os, re

home = os.getenv('HOME')

# This is the only variable you should change.  If you do not know the
# location of your evloution address book, use `locate addressbook.db`
# to find it

dbname = '%s/evolution/local/Contacts/addressbook.db' % home

db = bsddb.hashopen(dbname)

for k in db.keys():
    for line in db[k].split('\n'):
        print line

db.close()

Once I had the python script working, the perl script was next on software TO-DO list. The perl script takes input from standard input, and parses the lines fed to it looking for specific VCARD tags which evolution uses. It then interprets these tags, and output them in a CSV format. Sort of. After quickly acquainting myself with basic Perl, I dove into the script, generalizing it by adding constants to specify the separator for each field, and adding quotes around each field. I cleaned up a few other small problems so that it would work in Perl's strict mode, and tested it out. Success!

Here is the perl script, named vcard2csv.pl:

#!/usr/bin/perl

use strict;
my $begin;
my $end;
my $quo;
my $sep;
my $line;
my $name;
my $tel_work_voice;
my $tel_work_fax;
my $tel_home;
my $tel_pager;
my $tel_cell;
my $tel_voice;
my $email;

# initialize constants
$begin = "BEGIN:VCARD";
$end   = "END:VCARD";
$quo   = '"';
$sep   = ",";

# print out the header for the CSV file
print $quo . "Name" . $quo . $sep;
print $quo . "Work - Voice".$quo . $sep;
print $quo . "Work - Fax".$quo . $sep;
print $quo . "Home".$quo . $sep;
print $quo . "Pager".$quo . $sep;
print $quo . "Cell".$quo . $sep;
print $quo . "Voice".$quo . $sep;
print $quo . "E-mail".$quo;
print "\n";

while ( $line = <STDIN> ) {
    chomp ($line);
    chop ($line) ; # trailing ^M

#BEGIN:VCARD
    if  ( $line eq $begin ) {

        $name = "";
        $tel_work_voice = "";   
        $tel_work_fax = "";
        $tel_home = "";
        $tel_pager = "";
        $tel_cell = "";
        $tel_voice = "";
        $email = "";

    }

#X-EVOLUTION-FILE-AS:
    if ( $line =~ /^X-EVOLUTION-FILE-AS\:.*/ ) {

        $line =~ s/^X-EVOLUTION-FILE-AS://g;       
        $name = $line;
        print $quo . $name . $quo . $sep;

    }

#TEL;WORK;VOICE;
    if ( $line =~ /^TEL;WORK;VOICE:.*/ ) {

        $line =~ s/^TEL;WORK;VOICE://g;
        $tel_work_voice = $line;

    }

#TEL;WORK;FAX;
    if ( $line =~ /^TEL;WORK;FAX:.*/ ) {

        $line =~ s/^TEL;WORK;FAX://g;
        $tel_work_fax = $line;

    }

#TEL;HOME;
    if ( $line =~ /^TEL;HOME:.*/ ) {

        $line =~ s/^TEL;HOME://g;
        $tel_home = $line;

    }

#TEL;PAGER;
    if ( $line =~ /^TEL;PAGER:.*/ ) {

        $line =~ s/^TEL;PAGER://g;
        $tel_pager = $line;

    }

#TEL;CELL;
    if ( $line =~ /^TEL;CELL:.*/ ) {

        $line =~ s/^TEL;CELL://g;
        $tel_cell = $line;

    }

#TEL;VOICE;
    if ( $line =~ /^TEL;VOICE:.*/ ) {

        $line =~ s/^TEL;VOICE://g;
        $tel_voice = $line;

    }

#EMAIL;INTERNET;
    if ( $line =~ /^EMAIL;INTERNET:.*/ ) {

        $line =~ s/^EMAIL;INTERNET://g;
        $email = $email . $line;

    }

#EMAIL;QUOTED-PRINTABLE;INTERNET;
    if ( $line =~ /^EMAIL;QUOTED-PRINTABLE;INTERNET:.*/ ) {

        $line =~ s/^EMAIL;QUOTED-PRINTABLE;INTERNET://g;
        $line =~ s/=0A/ /g; #=0A make it a space
        $email = $email . $line;

    }

#END:VCARD   
    if ( $line eq $end ) {

        if ( $tel_work_voice eq "" )
        { print $sep;}
        else
        { print $quo . $tel_work_voice . $quo . $sep; }
        if ( $tel_work_fax eq "" )
        { print $sep; }
        else
        {print $quo . $tel_work_fax . $quo . $sep; }
        if ( $tel_home eq "" )
        { print $sep; }
        else
        {  print $quo . $tel_home . $quo . $sep; }
        if ( $tel_pager eq "" )
        { print $sep; }
        else {  print $quo . $tel_pager . $quo . $sep; }
        if ( $tel_cell eq "" )
        { print $sep; }
        else { print $quo . $tel_cell . $quo . $sep; }
        if ( $tel_voice eq "" )
        { print $sep; }
        else
        { print $quo . $tel_voice . $quo . $sep; }
        if ( $email eq "" )
        {print $sep;}
        else { print $quo . $email . $quo; }
        print "\n";

    } # end if "END:VCARD"
    
} # end while STDIN

Note that I also added a header line for the CSV file, which Gmail seems to expect.

To use the above two scripts, copy and paste each of them into their own file, named exportevolution.py and vcard2csv.pl. Make sure the executable bit is set so that your Linux / BSD / Unix OS will allow you to treat them as executable scripts via:

chmod a+x exportevolution.py vcard2csv.pl

Next, pipe the output from out evolution exporter to the vcard to csv converter, and save it to a suitably named file:

./exportevolution.py | ./vcard2csv.ple > mycontacts.csv

Finally, log into your Gmail account, click on the Contacts link at the upper right hand side of the page, and then import the mycontacts.csv file using the import link Gmail provides. Enjoy!

posted at: 14:15 | path: /computers | permanent link to this entry