Skip to content

Latest commit

ย 

History

43 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

csv2vcard

Downloads PyPI codecov Python Typed Typer Ruff License

A Python library for converting CSV files to vCard format (2.1, 3.0 and 4.0).

Create vCards from a spreadsheet of contacts - useful for business cards, QR codes, CRM imports, or transferring contacts between systems.

Features

  • vCard 2.1, 3.0 and 4.0 - Standards-compliant output (CRLF line endings, line folding, escaping); 4.0 includes RFC 9554 properties such as pronouns and social profiles, 2.1 targets legacy Outlook, car kits and feature phones
  • Stable UIDs - Converting the same CSV again produces the same UIDs, so re-imports update contacts instead of duplicating them
  • Custom CSV mapping - Map any CSV column names to vCard fields
  • Batch processing - Convert entire directories of CSV files
  • Single-file output - Combine all contacts into one .vcf file
  • File splitting - Split output by size or contact count
  • Multi-type fields - Multiple phone numbers, emails, and addresses per contact
  • Multiple values per field - Extra emails, phones, websites and social profiles via numbered columns (email_2, Phone 3, ...)
  • Keep extra columns - --keep-unmapped writes columns that match no field as X- properties instead of dropping them
  • Media embedding - Embed photos, logos, and keys (base64 or URL)
  • Accent stripping - Remove diacritics for compatibility
  • Auto-detect encoding - Handles various file encodings, including Excel's UTF-8 with BOM
  • Command-line interface - Convert files directly from terminal
  • Library API - Use programmatically in your Python code
  • Type hints - Full typing support for IDE autocomplete
  • Security - Input validation and path traversal protection
  • Zero dependencies - Core library uses only Python stdlib

Installation

# Basic installation (library only)
pip install csv2vcard

# With CLI support
pip install csv2vcard[cli]

# With encoding detection
pip install csv2vcard[encoding]

# Full installation
pip install csv2vcard[all]

Quick Start

Command Line

# Convert a CSV file to vCards
csv2vcard convert contacts.csv

# Specify output directory and vCard version
csv2vcard convert contacts.csv -o ./vcards -V 4.0

# vCard 2.1 for legacy Outlook, car kits and feature phones
csv2vcard convert contacts.csv -V 2.1

# Keep columns that match no vCard field as X- properties
csv2vcard convert contacts.csv --keep-unmapped

# Convert all CSVs in a directory
csv2vcard convert ./csv_folder/

# Export all contacts to a single file
csv2vcard convert contacts.csv --single-vcard

# Split output into multiple files (max 100 contacts per file)
csv2vcard convert contacts.csv --max-vcards-per-file 100

# Split output by file size (max 1MB per file)
csv2vcard convert contacts.csv --max-vcard-file-size 1048576

# Strip accents for compatibility (รฉโ†’e, รผโ†’u)
csv2vcard convert contacts.csv --strip-accents

# Use custom column mapping
csv2vcard convert data.csv -m mapping.json

# Show example mapping file
csv2vcard mapping

# Create a test vCard (Forrest Gump)
csv2vcard test

Python Library

from csv2vcard import csv2vcard, test_csv2vcard

# Basic usage - creates vCards in ./export/
csv2vcard("contacts.csv", ",")

# With options
from csv2vcard.models import VCardVersion

csv2vcard(
    "contacts.csv",
    ",",
    output_dir="./vcards",
    version=VCardVersion.V4_0,
    single_file=True,  # All contacts in one file
    mapping_file="mapping.json",  # Custom column names
    strip_accents=True,  # Remove diacritics
    max_vcards_per_file=100,  # Split into multiple files
    keep_unmapped=True,  # Keep unknown columns as X- properties
)

# Convert entire directory
csv2vcard("./csv_folder/", ",", output_dir="./vcards")

# Test with sample contact
test_csv2vcard()

CSV Format

Your CSV file should have column headers that match vCard fields. Use the default names or create a custom mapping.

Headers are matched case-insensitively and treat spaces, hyphens and underscores alike, so First Name, first-name and first_name are equivalent. Exports from Excel (including "CSV UTF-8" with a byte order mark) and Outlook-style headers such as Business Street or Mobile Phone work out of the box.

Default Column Names

Required: last_name, first_name (rows with only org become organization cards)

Basic fields:

last_name, first_name, middle_name, name_prefix, name_suffix, nickname, gender, birthday, anniversary, pronouns, language, org, title, role, note, uid

Contact fields (single):

phone, email, website

Multi-type phone:

phone_cell, phone_home, phone_work, phone_fax

Multi-type email:

email_home, email_work

Work address:

street, city, region, p_code, country

Home address:

home_street, home_city, home_region, home_p_code, home_country

Media:

photo, logo, key

Additional fields:

categories, geo, tz, social_profile

Multiple values: phone*, email*, website and social_profile accept numbered columns for extra values, e.g. email, email_2, email_3 or Phone 1, Phone 2.

Dates: birthday and anniversary accept YYYY-MM-DD, YYYYMMDD, DD.MM.YYYY, --MM-DD (no year) and slashed dates when day and month can be told apart. Ambiguous dates such as 06/07/1990 are reported and kept as text in vCard 4.0.

UIDs: each vCard gets a UID derived from the name, organization and email, or from the uid column (uid, contact_id, external_id) when present.

Example CSV

last_name,first_name,title,org,phone,email,street,city,p_code,country,birthday,note
Gump,Forrest,Shrimp Man,Bubba Gump Shrimp Co.,+1234567890,forrest@example.com,42 Plantation St.,Baytown,30314,USA,1944-06-06,Life is like a box of chocolates
Doe,Jane,Developer,Tech Corp,+0987654321,jane@example.com,123 Main St.,New York,10001,USA,,

Custom Column Mapping

Create a JSON file to map your CSV column names to vCard fields:

{
  "first_name": ["Given Name", "FirstName", "First"],
  "last_name": ["Surname", "FamilyName", "Last"],
  "email": ["Email Address", "E-Mail"],
  "phone": ["Phone Number", "Mobile", "Tel"]
}

Then use it:

csv2vcard convert data.csv -m mapping.json

CLI Reference

csv2vcard convert [OPTIONS] SOURCE

Arguments:
  SOURCE  Path to CSV file or directory containing CSV files

Options:
  -d, --delimiter TEXT          CSV field delimiter (default: ",")
  -o, --output PATH             Output directory (default: ./export/)
  -V, --vcard-version TEXT      vCard version: 2.1, 3.0 or 4.0 (default: 3.0)
  -1, --single-vcard            Export all contacts to a single .vcf file
  -m, --mapping PATH            Path to JSON mapping file
  -e, --encoding TEXT           CSV file encoding (auto-detected if not set)
  -a, --strip-accents           Remove accents/diacritics from contact fields
  --max-vcard-file-size INT     Split output by file size (bytes)
  --max-vcards-per-file INT     Split output by contact count
  --keep-unmapped               Keep unmapped columns as X- properties
  --strict                      Fail on validation errors, malformed rows
                                and undecodable bytes
  -v, --verbose                 Enable verbose output
  --version                     Show version and exit (also: csv2vcard --version)
  --help                        Show help message

API Reference

Main Functions

from csv2vcard import csv2vcard, test_csv2vcard
from csv2vcard.models import VCardVersion

# Convert CSV to vCards
files = csv2vcard(
    csv_filename,           # Path to CSV file or directory
    csv_delimiter=",",      # Field delimiter
    output_dir=None,        # Output directory (default: ./export/)
    version=VCardVersion.V3_0,  # vCard version
    strict=False,           # Raise on validation errors
    single_file=False,      # Combine all contacts into one file
    encoding=None,          # File encoding (auto-detected)
    mapping_file=None,      # Path to JSON mapping file
    strip_accents=False,    # Remove diacritics (รฉโ†’e, รผโ†’u)
    max_file_size=None,     # Split by file size (bytes)
    max_vcards_per_file=None,  # Split by contact count
    keep_unmapped=False,    # Keep unknown columns as X- properties
)
# Returns: List[Path] of created vCard files

# Test with sample contact
test_csv2vcard(
    output_dir=None,
    version=VCardVersion.V3_0,
)

Models

from csv2vcard.models import Contact, VCardVersion, VCardOutput

# Create a contact programmatically
contact = Contact(
    last_name="Doe",
    first_name="John",
    middle_name="William",
    email="john@example.com",
    phone="+1234567890",
    birthday="1990-01-15",
    nickname="Johnny",
)

# Or from a dictionary
contact = Contact.from_dict({"last_name": "Doe", "first_name": "John"})

# vCard versions
VCardVersion.V2_1  # vCard 2.1 (legacy)
VCardVersion.V3_0  # vCard 3.0 (RFC 2426)
VCardVersion.V4_0  # vCard 4.0 (RFC 6350 + RFC 9554)

Supported vCard Fields

Name & Basic Info

Field Description Example
last_name Family name (required) Doe
first_name Given name (required) John
middle_name Middle name William
name_prefix Honorific prefix Dr.
name_suffix Honorific suffix Jr.
nickname Nickname Johnny
gender Gender (M/F/O/N/U) M
birthday Birth date (YYYY-MM-DD) 1990-01-15
anniversary Anniversary date 2015-06-20
pronouns Pronouns (vCard 4.0) they/them
language Preferred language (vCard 4.0) en
org Organization Acme Corp
title Job title Developer
role Role/function Team Lead
note Notes Any additional info
uid Stable ID from the source system crm-42

Contact Fields

Field Description vCard Type
phone Default phone TEL;TYPE=WORK
phone_cell Mobile phone (also mobile, cell) TEL;TYPE=CELL
phone_home Home phone TEL;TYPE=HOME
phone_work Work phone TEL;TYPE=WORK
phone_fax Fax number TEL;TYPE=FAX
email Default email EMAIL;TYPE=WORK
email_home Personal email EMAIL;TYPE=HOME
email_work Work email EMAIL;TYPE=WORK
website Website URL URL
social_profile Social profile URL SOCIALPROFILE (4.0), X-SOCIALPROFILE (2.1/3.0)

Address Fields

Field Description vCard Type
street Work street address ADR;TYPE=WORK
city Work city ADR;TYPE=WORK
region Work state/province ADR;TYPE=WORK
p_code Work postal code ADR;TYPE=WORK
country Work country ADR;TYPE=WORK
home_street Home street address ADR;TYPE=HOME
home_city Home city ADR;TYPE=HOME
home_region Home state/province ADR;TYPE=HOME
home_p_code Home postal code ADR;TYPE=HOME
home_country Home country ADR;TYPE=HOME

Media Fields

Field Description Format
photo Contact photo URL, data: URI or base64
logo Company logo URL, data: URI or base64
key Public key URL, data: URI, base64 or ASCII-armored PGP

Additional Fields

Field Description Example
categories Tags/groups (comma-separated) Work,Friends
geo Geographic coordinates 37.386,-122.082
tz Timezone America/New_York

Requirements

  • Python 3.10 or higher
  • For CLI: typer (installed with csv2vcard[cli])
  • For encoding detection: charset-normalizer (installed with csv2vcard[encoding])

Development

# Clone the repository
git clone https://github.com/tech4242/csv2vcard.git
cd csv2vcard

# Install dev dependencies
pip install -e .[dev]

# Run tests
pytest

# Run tests with coverage
pytest --cov=csv2vcard --cov-report=term-missing

# Type checking
mypy csv2vcard

# Linting
ruff check .

License

MIT License - see LICENSE.txt

About

๐Ÿ“  A pip package that parses a .csv file of contacts and automatically creates vCards

Resources

Stars

11 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages