Guide

Turn Emails into Trello Cards (CLI)

Trello boards run support queues, bug triage, and content calendars, and the work usually starts as an email. Paid connectors meter every card they create. The Nylas CLI hands you each message as JSON, jq reshapes it, and one POST to the Trello cards API turns it into a card on the list you choose. This guide builds an email-to-Trello pipeline you own, mapping subject to the card name and the body to the description, with de-duplication so a re-run never doubles a card.

Written by Aaron de Mello Senior Engineering Manager

Reviewed by Qasim Muhammad

VerifiedCLI 3.1.17 · Gmail, Outlook · last tested June 9, 2026

Command references used in this guide: nylas email search, nylas email list, and nylas email read.

How do I turn an email into a Trello card?

You turn an email into a Trello card by pulling the message as JSON and POSTing one card per message to the Trello REST API. The nylas email search command returns structured messages, and a single request to the /1/cards endpoint creates a card on the list you name. The card-creation contract is documented in the Trello REST API reference.

Two values come first. Every Trello write needs a key and a token passed as query parameters, plus an idList naming the target list. The token-based scheme is described in the Trello authorization guide. Install the tool first with one Homebrew command, or see getting started for the other methods.

brew install nylas/nylas-cli/nylas

# Pull the messages you want as cards (last 20 by default)
nylas email search "bug report" --json --limit 50 > items.json

How do I shape the email JSON with jq?

You shape the email JSON with jq, mapping each message to the three fields the Trello cards endpoint expects: name, desc, and idList. The subject becomes the card name; the sender and snippet become the description. The CLI returns subject, from, and snippet on every message.

Card names are capped at 16,384 characters by Trello, so a subject never overflows, but an empty subject would create a nameless card. Fall back to a placeholder with the // alternative operator, documented in the jq manual. The sender field is an array, so index the first entry. This step transforms the raw inbox dump into a flat array of card-ready objects, one per message.

LIST_ID="your-list-id"

# Reshape each message into Trello's card fields
jq -c --arg list "$LIST_ID" '.[] | {
  name: (.subject // "(no subject)"),
  desc: ("From: " + (.from[0].email // "unknown") + "\n\n" + (.snippet // "")),
  idList: $list
}' items.json > cards.json

How do I POST the card to the Trello API?

You create the card with one POST to https://api.trello.com/1/cards, passing your key and token as query parameters and the reshaped object as a JSON body. Trello replies with the new card's ID and short URL. The endpoint accepts a single card per request, so loop over the array from the previous step.

Trello's default API rate limit is 300 requests per 10 seconds per key and 100 per 10 seconds per token, per the Trello rate-limit docs. A batch of 50 messages stays well under that, but add a short sleep if you import thousands. Each loop iteration reads one card object, sends it, and prints the returned URL so you can confirm the write landed on the right list.

KEY="your-trello-key"
TOKEN="your-trello-token"

# Create one card per reshaped object
jq -c '.' cards.json | while read -r card; do
  curl -s -X POST "https://api.trello.com/1/cards?key=$KEY&token=$TOKEN" \
    -H "Content-Type: application/json" \
    -d "$card" | jq -r '"Created: " + .shortUrl'
done

How do I stop duplicate cards on a re-run?

You stop duplicate cards by de-duplicating on a stable field before the POST. The cleanest key is the Nylas message ID, which never changes for a given message. Write each processed ID to a local file, then skip any message whose ID is already there. A daily cron scoped to --after yesterday only ever sees the last day's mail, so the seen-file stays small.

This guards against the common failure mode: a cron runs every 6 hours, the same unread email matches each time, and the board fills with four copies of one card. Carry the message ID through the jq step, check it with grep -qF against the seen-file, and append it only after a successful create. The ID-based check is exact, so it survives subject edits and resends.

SEEN="seen-ids.txt"; touch "$SEEN"

nylas email search "bug report" --json --after 2026-06-08 \
  | jq -c '.[] | {id, name: (.subject // "(no subject)"), idList: $ENV.LIST_ID}' \
  | while read -r card; do
      id=$(echo "$card" | jq -r '.id')
      grep -qF "$id" "$SEEN" && continue
      curl -s -X POST "https://api.trello.com/1/cards?key=$KEY&token=$TOKEN" \
        -H "Content-Type: application/json" \
        -d "$(echo "$card" | jq 'del(.id)')" > /dev/null \
        && echo "$id" >> "$SEEN"
    done

Why use the CLI instead of a paid connector?

Use the CLI because it gives you the email as raw JSON with no per-card fee, where hosted connectors meter every record. A typical no-code automation plan caps free runs at a few hundred tasks per month, then bills per task above that. The nylas email search --json path runs on your own cron with zero marginal cost per card.

The CLI also reaches across providers without per-mailbox setup. One grant covers Gmail, Outlook, and four other backends, and OAuth tokens stored in your system keyring refresh automatically every 3,600 seconds. You keep the filtering logic in version control instead of a vendor's visual editor, so a search query like --from support@example.com is reviewable in a pull request. Gmail's own query operators are documented in the Gmail API filtering guide, and message address formats follow RFC 5322.

Next steps