The vCard format has been the standard way to exchange contact information since the 1990s. Email clients attach vCards to messages, phones export contact databases as vCard files, and nearly every contact management system can import and export the format. Despite this ubiquity, Emacs has lacked a proper programmatic interface for working with vCard data as structured objects rather than opaque text files.
I have been working on ecard, a complete implementation of vCard 4.0 (RFC 6350) that provides both parsing and serialization through a clean EIEIO-based API. The library handles the full specification: all standard properties, proper UTF-8 support, correct line folding at octet boundaries, and extended properties. It is written in pure Emacs…
The vCard format has been the standard way to exchange contact information since the 1990s. Email clients attach vCards to messages, phones export contact databases as vCard files, and nearly every contact management system can import and export the format. Despite this ubiquity, Emacs has lacked a proper programmatic interface for working with vCard data as structured objects rather than opaque text files.
I have been working on ecard, a complete implementation of vCard 4.0 (RFC 6350) that provides both parsing and serialization through a clean EIEIO-based API. The library handles the full specification: all standard properties, proper UTF-8 support, correct line folding at octet boundaries, and extended properties. It is written in pure Emacs Lisp with no external dependencies.
Design and Implementation
The library uses EIEIO to represent vCards as objects with slots for each property type defined in RFC 6350. Properties themselves are also objects, carrying their group prefix, parameters, and values. This object-oriented approach makes it straightforward to work with contact data programmatically rather than manipulating strings.
One aspect worth noting is the handling of line folding. RFC 6350 specifies that lines must be folded at 75 octets, not 75 characters. This matters for UTF-8 text where a single character may occupy multiple bytes. The implementation counts octets correctly and folds at character boundaries to avoid splitting multi-byte sequences.
Basic Usage
Parsing a vCard file returns an ecard object:
(let ((contact (ecard-parse-file "~/contacts/john.vcf")))
;; Get the formatted name
(ecard-get-property-value contact 'fn)
;; Get all email addresses
(ecard-get-property-values contact 'email)
;; Get first phone number
(ecard-get-property-value contact 'tel))
Creating a new vCard is equally direct:
(let ((contact (ecard-create
:fn "Jane Smith"
:email '("[email protected]" "[email protected]")
:tel "+1-555-1234"
:org "Acme Corporation")))
(ecard-write-file contact "~/contacts/jane.vcf"))
Properties can be modified using the standard API:
;; Replace all email addresses
(ecard-set-property contact 'email "[email protected]")
;; Add an additional phone number
(ecard-add-property contact 'tel "+1-555-9999")
Practical Applications
The immediate use case that motivated this work was handling vCard attachments in email. With ecard, it becomes possible to parse an attached contact file, extract relevant information, and integrate it into existing workflows without manual copying.
Beyond email integration, the library enables building custom contact management tools, converting between vCard and other formats like org-contacts or BBDB, performing bulk operations on contact databases, and automating contact data migration. The bidirectional nature of the implementation means you can parse existing vCards, modify them programmatically, and serialize them back out with full fidelity.
Testing and Quality
The library includes comprehensive test coverage with over 390 tests spanning RFC compliance, edge cases, and real-world scenarios. The test suite verifies correct handling of line folding and unfolding, proper escaping and unescaping of special characters, validation of required properties, support for all standard vCard 4.0 properties, and round-trip fidelity between parsing and serialization.
The tests also cover CardDAV protocol support (RFC 6352), compatibility with org-contacts, and integration with BBDB for users of that contact management system. The tests were constructed based on the following RFCs:
RFC-2425 A MIME Content-Type for Directory Information RFC-2426 vCard MIME Directory Profile (vCard 3.0) RFC-6350 vCard Format Specification (vCard 4.0) RFC-6352 CardDAV: vCard Extensions
Backwards compatibility
The implementation also supports vCard 2.1 and 3.0, and CardDAV servers may be declared using a `:version` parameter to specify which version the server, or even a specific addressbook, expects to receive. The library also does not currently handle MIME encoding for binary properties like photos; these are stored as strings.