# Mail Merge, From the Command Line ![banner](https://articles.aux4.blog/data/posts/aux4/mail-merge-from-the-command-line/banner.png) ## Introduction You have a list of people and one message that should read as if it were written for each of them — a welcome note, a plan activation, an event invite. That's mail merge, and it usually means a marketing SaaS or a fragile spreadsheet macro. This post does it from the command line: `aux4/template` personalizes the body per recipient, `aux4/json` fans it out over the list, and `aux4/email` sends — with a full preview before anything leaves your outbox. ## Install the packages ```bash aux4 aux4 pkger install aux4/template aux4/json aux4/email ``` ## Step 1: the list Your recipients live in one file — `contacts.json`, with an address and whatever fields you want to personalize on: ```json [ { "name": "Sally", "email": "sally@example.com", "plan": "Pro", "trial": false }, { "name": "Marco", "email": "marco@example.com", "plan": "Free", "trial": true }, { "name": "Priya", "email": "priya@example.com", "plan": "Team", "trial": false } ] ``` ## Step 2: the message, once Write the body one time as a [Handlebars](https://handlebarsjs.com) template. Fields fill in per recipient, and `{{#if}}` adds a line only when it applies. Create `body.hbs` — note `(bool trial)`, which turns the flag value into a real boolean: ```handlebars Hi {{name}}, Your {{plan}} plan is now active.{{#if (bool trial)}} You're on a 14-day free trial — nothing is charged until it ends.{{/if}} Thanks for joining, The Acme Team ``` Render it for one person to check the shape: ```bash aux4 template --file body.hbs --name Sally --plan Pro --trial false ``` ```text Hi Sally, Your Pro plan is now active. Thanks for joining, The Acme Team ``` ## Step 3: preview every email before sending This is the step that saves you. Fan the template out over the whole list with `aux4 json exec` — `${item.field}` is the current recipient — and print each message with its recipient. Nothing is sent; you're just reading what *would* go out: ```bash cat contacts.json | aux4 json exec 'echo "--- To: ${item.email} ---"; aux4 template --file body.hbs --name "${item.name}" --plan "${item.plan}" --trial "${item.trial}"' ``` ```text --- To: sally@example.com --- Hi Sally, Your Pro plan is now active. Thanks for joining, The Acme Team --- To: marco@example.com --- Hi Marco, Your Free plan is now active. You're on a 14-day free trial — nothing is charged until it ends. Thanks for joining, The Acme Team --- To: priya@example.com --- Hi Priya, Your Team plan is now active. Thanks for joining, The Acme Team ``` Each message is personalized, and Marco — the only one on a trial — is the only one who gets the trial line. Read the whole batch, catch the awkward wording now, *then* send. ## Step 4: send the batch Same fan-out, but the per-recipient command is now `aux4 email send`. The body is rendered by `template` for each person and handed to `--body`: ```bash cat contacts.json | aux4 json exec 'aux4 email send --to "${item.email}" --subject "Your ${item.plan} plan is ready" --body "$(aux4 template --file body.hbs --name "${item.name}" --plan "${item.plan}" --trial "${item.trial}")"' ``` `aux4 email send` requires `--to`, `--subject`, and `--body`; it also takes `--cc`, `--bcc`, and `--attachment`. The sender and SMTP settings come from your `~/.config/aux4/email.yaml`, so the address people see is the `user` configured there. This one actually sends, once per recipient — which is exactly why Step 3 exists. Preview the batch, and only run this when the output reads the way you want. ## Conclusion Mail merge, without the marketing stack: `aux4/template` writes the message once and personalizes it per recipient, `aux4/json` runs it across your whole list, and `aux4/email` delivers — with a dry-run preview so you see every message before one is sent. Swap the template and the list and you have welcome emails, renewal notices, or event invites, all from a single command. ## See Also - [aux4/template](https://hub.aux4.io/r/public/packages/aux4/template) - [aux4/json](https://hub.aux4.io/r/public/packages/aux4/json) - [aux4/email](https://hub.aux4.io/r/public/packages/aux4/email)