Skip to main content

Google Sheets bulk mail merge

Turn a Google Sheet into a mail run: mark rows "send," and paperplane’s Zapier, Make, or n8n action mails one real USPS letter per row from $1.99, writing the order ID back so the sheet stays the source of truth.

All Google Sheets integration options · All integrations

Supported triggers and actions

TriggerAction
New row added to the sheetSend Letter (First-Class, from $1.99)
Row updated where status = "send"Send Letter, mail class from the row (e.g. Certified)
Scheduled/batch trigger over unsent rowsSend Letter for each matching row, one order per row

How to set it up

  1. 1Structure the sheet with one row per letter: recipient name, address fields, letter text (or a pdf_url column), and a "send" status column.
  2. 2In Zapier, Make, or n8n, trigger on new/updated rows where status = send, then add the paperplane Send Letter action.
  3. 3Map the row’s columns into the action fields, with Sandbox on until the mapping looks right — free, instant, nothing mailed.
  4. 4Go live. Write the returned order id and status back to the same row so the sheet stays the audit trail for the whole run.

What each row becomes (the action’s request body)

{
  "mail_class": "first_class",
  "sandbox": true,
  "text": "Dear Ms. Alvarez, ...",
  "to":   { "name": "Maria Alvarez", "line1": "1 Main St",
            "city": "Richmond", "state": "VA", "zip": "23220" },
  "from": { "name": "Alex Rivera", "line1": "12 Grove Ave",
            "city": "Richmond", "state": "VA", "zip": "23221" },
  "email": "alex@example.com"
}

Same call as curl, for testing one row by hand

curl -X POST https://sendpaperplane.com/v1/orders \
  -H 'Content-Type: application/json' \
  -d '{
    "mail_class": "first_class",
    "sandbox": true,
    "text": "Dear Ms. Alvarez, ...",
    "to":   { "name": "Maria Alvarez", "line1": "1 Main St",
              "city": "Richmond", "state": "VA", "zip": "23220" },
    "from": { "name": "Alex Rivera", "line1": "12 Grove Ave",
              "city": "Richmond", "state": "VA", "zip": "23221" },
    "email": "alex@example.com"
  }'

Under the hood

Each row becomes its own independent order with its own receipt and status lifecycle — there’s no batch object to fail as a unit. Every address is USPS-verified before payment; a bad address returns a structured error with the corrected candidate instead of silently mailing to the wrong place, so your automation can write the fix back to the row.

Or skip the automation tool: ask Claude or ChatGPT

Every integration here sits on the same MCP endpoint agents use directly. Instead of wiring a trigger to an action, ask Claude or ChatGPT to draft and mail the letter. Same three tools (quote_letter, send_letter, get_letter_status), same price, same free sandbox.

Send mail from ClaudeSend mail from ChatGPT

Send your first letter from Google Sheets.

Sandbox runs the whole pipeline for free and mails nothing. Live sends start at $1.99, one all-in price.

curl -X POST https://sendpaperplane.com/v1/orders \
  -H 'Content-Type: application/json' \
  -d '{
    "mail_class": "first_class",
    "sandbox": true,
    "text": "Dear Ms. Alvarez, ...",
    "to":   { "name": "Maria Alvarez", "line1": "1 Main St",
              "city": "Richmond", "state": "VA", "zip": "23220" },
    "from": { "name": "Alex Rivera", "line1": "12 Grove Ave",
              "city": "Richmond", "state": "VA", "zip": "23221" },
    "email": "alex@example.com"
  }'

Google Sheets integration options · All integrations

Common questions

Does a bad address in the sheet stop the whole run?

No — each row is its own order. A USPS verification failure on one row returns a structured error (with a corrected-address candidate) without touching any other row.

How do I avoid paying for a mapping mistake?

Leave Sandbox on while you build the Zap/scenario/workflow — the full pipeline runs instantly and free, and nothing is printed or mailed until you turn it off.

Can I mail hundreds of rows at once?

Yes — there’s no per-order API key or account gate, so the automation platform’s own rate limits are the only ceiling. A prepaid credit balance keeps a large run hands-off instead of approving a payment link per letter.