Skip to main content

csv2vcard

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 (--max-vcard-file-size) or contact count (--max-vcards-per-file)
  • Multi-type fields - Multiple phones (phone_cell, phone_home, phone_work, phone_fax), emails (email_home, email_work), and addresses (work + home)
  • 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 (--strip-accents)
  • 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
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
    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)

Requirements

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

License

MIT License - see LICENSE.txt

Release files for csv2vcard 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for csv2vcard 0.6.0
File Size Uploaded
csv2vcard-0.6.0.tar.gz 54.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for csv2vcard 0.6.0
File Interpreter ABI Platform
csv2vcard-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 90.4 kB

Release files / csv2vcard-0.6.0.tar.gz

Download URL csv2vcard-0.6.0.tar.gz
Size 54.4 kB
Tags Source
SHA-256 checksum
How to use checksums
2d18f40a51f61a3aa648ec9647b28dd46d48cc5faeed14147807ff66ff583981
BLAKE2b-256 checksum
How to use checksums
a7dd5e4364721af35d99a255774bf76e70cc0f5470d3e6e3d2a61b1465fc7143
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release files / csv2vcard-0.6.0-py3-none-any.whl

Download URL csv2vcard-0.6.0-py3-none-any.whl
Size 36.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9050621d1508e740291cec0a85f7e966da0ad8a84e29257df05b86c120f455e1
BLAKE2b-256 checksum
How to use checksums
8b84cc30bd97a306cd5c5b26cfb688148e48554af6a4e1492448326cad4f4d89
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

1 release file

0.2.1

1 release file

0.2

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page