Skip to content

Getting Started

Aurghyadip edited this page Aug 3, 2026 · 1 revision

Getting Started with typst-mailmerge

This guide helps you set up typst-mailmerge in your Typst document, import CSV data, and render your first personalized mail merge document.


📦 Installation & Import

Official Package Import (Preview Registry)

#import "@preview/mailmerge:0.1.0": mail-merge, field, fmt-field, join-fields, if-field

Local Development Import

If working within the local repository or a local package setup:

#import "lib.typ": mail-merge, field, fmt-field, join-fields, if-field

📊 Preparing Data

typst-mailmerge accepts data from multiple sources:

1. External CSV Files (Recommended)

Load your CSV file using Typst's built-in csv() function with row-type: dictionary:

let data = csv("clients.csv", row-type: dictionary)

Example CSV (clients.csv):

First Name,Last Name,Company,Address 1,City,State,Zip,Balance,Status
Jane,Doe,Acme Corp,123 Main St,Springfield,IL,62701,150.00,Active
John,Smith,,456 Oak Ave,Columbus,OH,43215,0.00,Active

2. Inline Dictionary Arrays

You can supply an array of dictionaries directly in Typst:

let data = (
  (name: "Alice Smith", city: "New York", amount: "250"),
  (name: "Bob Jones", city: "Chicago", amount: "100"),
)

3. Row Arrays with Headers

You can also pass a 2D array where the first element is the array of field headers:

let data = (
  ("Name", "City", "Amount"),
  ("Alice Smith", "New York", "250"),
  ("Bob Jones", "Chicago", "100"),
)

✉️ Your First Mail Merge Letter

Here is a minimal complete example of generating personalized letters:

#import "@preview/mailmerge:0.1.0": mail-merge, field, fmt-field, join-fields

#mail-merge(
  csv("data/clients.csv", row-type: dictionary),
  reset-page-counter: true,
  record => [
    #align(right)[#datetime.today().display("[Month repr:long] [Day], [Year]")]

    *Dear #field(record, "First Name"),*

    Thank you for being a valued customer.

    #block(
      fill: rgb("#f8fafc"),
      inset: 10pt,
      radius: 4pt,
      [
        *Recipient:* \
        #fmt-field(record, "First Name") #fmt-field(record, "Last Name") \
        #field(record, "Address 1") \
        #join-fields(record, ("City", "State"), separator: ", ") #field(record, "Zip")
      ]
    )

    Your current account balance is *#fmt-field(record, "Balance", fmt: "currency")*.

    Best regards, \
    The Team
  ]
)

⏭️ Next Steps

Clone this wiki locally