← All packages

@lacspace/mail-merge

v1.0.0Mail Kit0 deps

Mail merge for webmail and email campaigns: turn a CSV or spreadsheet of recipients plus a subject/HTML/text template into one personalised message per recipient, with a validation report before anything is sent. Own RFC 4180 CSV parser (quotes, embedded newlines, BOM, comma/semicolon/tab auto-detect for Excel), built-in column aliases (First Name, e-mail, surname...), {{var|fallback}}, filters (upper, lower, title, capitalize, trim, first), {{#if}}/{{else}}/{{#unless}} blocks with no code execution, HTML escaping, email validation, case-insensitive dedupe, suppression by address or @domain, missing-variable counts, role-address warnings and a max cap. Zero dependencies, isomorphic.

npm i @lacspace/mail-merge

Usage

mail-merge.ts
import { parseCsv, merge } from "@lacspace/mail-merge";

const csv = `E-mail;First Name;Surname;Company
ram@example.com;Ram;Thapa;Himal Tea
sita@example.com;Sita;;
RAM@example.com;Ram;Thapa;Himal Tea
info@example.org;;;`;

const { rows, errors } = parseCsv(csv); // Excel ";" export, BOM stripped

const { messages, report } = merge(
  {
    subject: "Hi {{firstName | there}}, your invite",
    html: "<p>Dear {{first name|friend}},</p>{{#if company}}<p>Team {{company}} is welcome.</p>{{/if}}",
    text: "Dear {{firstName|friend}}",
  },
  rows,
  { suppress: ["@blocked.example"], extra: (row) => ({ unsubscribeUrl: `https://example.com/u?e=${row["E-mail"]}` }) },
);

messages[0];
// { to: { name: "Ram Thapa", address: "ram@example.com" }, subject: "Hi Ram, your invite",
//   html: "<p>Dear Ram,</p><p>Team Himal Tea is welcome.</p>", text: "Dear Ram", row, rowIndex: 0, warnings: [] }

report;
// { total: 4, ok: 3,
//   skipped: [{ row: 2, code: "duplicate", reason: "RAM@example.com already appears in an earlier row" }],
//   missingVars: {} }
// messages[2].warnings → ["info@example.org is a role address (info@); it may not reach a person"]

Exports 13

BUILTIN_ALIASESFILTERSROLE_LOCAL_PARTScompileTemplateescapeHtmlfindVariablesisValidEmailmergemergeAllnormalizeKeyparseCsvparseRowsrender

Keywords

mail-mergemailmergeemailcsvcsv-parsertemplate

More in Mail Kit

@lacspace/email-templates

Compose bulletproof, responsive, dark-mode HTML emails from simple blocks, plus 13 ready-made transactional templates (OTP, verify, password-reset, magic-link, receipt, order, shipping, invitation, digest, announcement). Ships plaintext generation, preheaders and {{var}} i18n interpolation. Zero-dependency, isomorphic.

@lacspace/email-validate

Smart, network-free email validation — RFC-5322 syntax (incl. quoted local parts & IP-literal domains), disposable/temp-mail & role-account detection, free-provider flags, Gmail normalization and 'did you mean?' typo suggestions. Zero-dependency, isomorphic.

@lacspace/email-verify

Best-effort email deliverability for Node — syntax + disposable/role, MX lookup with priority ranking, an optional SMTP RCPT probe (no mail sent), catch-all detection, a 0-100 confidence score, and de-duped batch verification. All DNS/SMTP injectable; zero npm dependencies.

@lacspace/mailer

A tiny zero-dependency SMTP client for Node — send email over raw net/tls with STARTTLS & AUTH, plus a fluent MIME builder (inline images, attachments, alternatives), RFC 5322 address + RFC 2047 helpers, batch send with retry, and no-network test transports. Provider presets (Hostinger, Gmail, Outlook, Zoho…) make setup one line.

@lacspace/imap

Zero-dependency IMAP4rev1 client for Node (RFC 3501 + IDLE, MOVE, UIDPLUS, CONDSTORE, SPECIAL-USE, LIST-EXTENDED, LITERAL+, SASL-IR, QUOTA, ID). Implicit TLS and STARTTLS with verification on, LOGIN / PLAIN / XOAUTH2 / OAUTHBEARER, streaming byte-accurate parser, async-iterable FETCH, envelopes with RFC 2047 decoding, BODYSTRUCTURE trees shared with @lacspace/mime, modified UTF-7 mailbox names, special-use detection (incl. Gmail XLIST and localised names), IDLE with NOOP fallback. Works with Hostinger (Dovecot), Gmail, Outlook/Exchange, GoDaddy.

@lacspace/mime

Isomorphic RFC 5322 / RFC 2045-2049 MIME parser and builder for webmail. parseMime() turns raw mail (string or bytes) into from/to/cc/subject/date/text/html/attachments/inline cid images/priority/List-Unsubscribe one-click and the part tree; handles nested multipart (mixed, alternative, related, report, signed), message/rfc822 forwards, base64 and quoted-printable (tolerant), RFC 2047 encoded words (split multibyte, adjacent whitespace), RFC 2231 parameters, 30+ charsets and malformed input without ever throwing. parseBodyStructure() parses IMAP BODYSTRUCTURE (literals, extension data) into the same tree with IMAP partIds, plus findTextParts / listAttachments / decodePart for lazy fetching. buildMime() writes CRLF messages with encoded-word headers, QP/base64 bodies, mixed/alternative/related nesting, Message-ID generation and header-injection guards; replyHeaders() / forwardSubject() for threading. Pairs with @lacspace/imap and @lacspace/mailer. Zero dependencies; Node 18+, edge runtimes and browsers.