About Feeds

Managing your contacts in org-mode and syncing them to your phone (Android, iOS, whatever)

I store my contacts in an org file called The file has the following structure:

* John Doe
:ID: some-generated-uuid
:GROUP:    Work
:PHONE:    +1234567890
:ADDRESS_HOME: Foo bar street, no 5
* Dohn Joe
:GROUP:    High school
:PHONE:    +1334567890
- Some notes about this person.

The nice part is, it's just plain org-mode. I only use top-level headings in this file, instead of creating header hierarchies. I utilize :GROUP: property to categorize people, this way a person may belong to multiple categories. I use org-ql if I need to find people related to one group or if I want to filter them based on some specific property.

However the main use case is that I reference these headers in my other org files. For example, I also keep my diary in org-mode and I may write about some event that I participated with John Doe from above. I simply reference (using org links) to that person. The benefit of this is being able to recollect all of your notes about a particular person using one simple search.

Anyway, lets jump how I synchronize these contact information with my phone.


I simply create .vcf file, a format that most of the contacts apps that are aware of, based on my file. Then I synchronize this .vcf file to my phone, using Syncthing. The following snippet creates the .vcf file.

(defun isamert/build-contact-item (template-string contact-property)
  (if-let ((stuff (org-entry-get nil contact-property)))
      (concat (format template-string stuff) "\n")

(defun isamert/vcard ()
  "Create a .vcf file containing all contact information."
     (lambda ()
          ,(format "UID:urn:uuid:%s\n" (org-id-get nil t))
          ,(isamert/build-contact-item "FN:%s" "ITEM")
          ,(isamert/build-contact-item "TEL;CELL:%s" "PHONE")
          ,(isamert/build-contact-item "EMAIL:%s" "EMAIL")
          ,(isamert/build-contact-item "ORG:%s" "GROUP")
          ,(isamert/build-contact-item "ADR;HOME:;;%s" "ADDRESS_HOME")
          ,(isamert/build-contact-item "ADR;WORK:;;%s" "ADDRESS_WORK")
          ,(format "REV:%s\n" (format-time-string "%Y-%m-%dT%T"))
    "Where to save the .vcf file?"

Simply call the isamert/vcard function in your file and you get a .vcf file. By default, it creates the file under ~/Documents/sync. This folder is automatically synced with my phone using Syncthing. Then I open my contacts app and import the file. That's it.

I used to earliest possible .vcf format that is available so that every contacts app can import them. You can add/remove fields to your .vcf export quite easily, just take a look at this wikipedia page for vCard and the relevant line to your function.

Appendix: Interactively copy email of a contact from anywhere in Emacs

Here is an example, just to demonstrate how you obtain/copy email of one of your contacts interactively. A use case might be:

  • You open your mail client to send an email to John Doe.
  • You call isamert/contacts-select-email which presents you all of your contact's names.
  • You select one of your contacts, and their email gets copied into your kill-ring.
  • You paste that email into To: field of your email client.

Don't forget to point find-file-noselect to your file.

(defun isamert/contacts-email-alist ()
  "Get an alist of contact name and emails."
   (lambda (it) it)
    (lambda ()
      (when-let ((email (org-entry-get nil "EMAIL")))
        `(,(org-entry-get nil "ITEM") . ,email)))

(defun isamert/contacts-select-email ()
  "Search through your contacts interactively and copy their email."
  (with-current-buffer (find-file-noselect "~/Documents/notes/")
    (let ((email-alist (isamert/contacts-email-alist)))
         (completing-read "Copy email of: " email-alist)


  • Reddit discussion
  • [2022-01-29 Sat] Added UID section to entries so that when you re-import your contacts after an update to the vcf file, already-existing contacts won't get duplicated.