How to Sync Resend Email Engagement into a Monday CRM Board

Build a Spojit workflow that runs on a schedule, pulls recent Resend email and contact activity, and updates or creates matching items on a Monday CRM board.

What This Integration Does

If you send transactional or lifecycle email through Resend but track your relationships in a Monday board, the two systems drift apart fast. A contact bounces, complains, or simply has not heard from you in weeks, and nobody on the team sees it because the signal lives in Resend while the work lives in Monday. This workflow closes that gap: on a fixed schedule it reads the latest emails and contacts from your Resend account and writes the engagement state (last delivery status, last send date, contact name) onto the matching item in a Monday CRM board, creating a new item when no match exists.

The workflow is driven by a Schedule trigger, so it runs unattended at whatever cadence you set (for example every weekday morning). Each run fetches a window of recent Resend emails, looks up the board's existing items to find a match by email address, and then either calls update-item on the Monday connector for matches or create-item for new contacts. The board is the durable state: each run is idempotent against it because you match on email before deciding to update or create, so re-running the workflow refreshes the same items rather than duplicating them.

Prerequisites

  • A Resend connection added in Spojit (API key). See the Resend connector article and Setting Up an API Key Connection.
  • A Monday.com connection added in Spojit (API token). See the Monday.com connector article.
  • A Monday CRM board with at least: a text or email column for the contact email, a status column for engagement state, and a date column for the last send. Note the board's ID and the column IDs (not the column titles) you want to write to.
  • The contact name fields in Resend (first_name, last_name) populated where you want names to flow through to Monday.

Step 1: Add a Schedule trigger

Create a new workflow and set its trigger to Schedule. A Schedule trigger uses a 5-field Unix cron expression plus an IANA timezone. For weekday mornings, use the expression 0 9 * * 1-5 with a timezone such as Australia/Sydney. The trigger output is { scheduledAt }, which you can reference downstream as {{ scheduledAt }} if you want to stamp the run time onto items. A single trigger can hold multiple schedules if you want more than one cadence.

Step 2: Fetch recent Resend emails

Add a Connector node in Direct mode, choose the Resend connector, and select the list-emails tool. This returns the most recent emails as a data array, where each email carries fields such as to, from, subject, created_at, and last_event (for example delivered, sent, bounced, or complained). Set the node's output variable to emails so later steps can read {{ emails.data }}.

If you also want the contact's name, add a second Connector node in Direct mode on the Resend connector with the list-contacts tool (it takes an audience_id), and store its result as contacts. You will match these to emails by address in the Transform step.

Step 3: Shape an engagement record per contact

Add a Transform node to reduce the raw Resend output into a clean list of one record per email address. Each record should hold the email address, a display name, the last engagement status, and the last send date. A compact target shape:

[
  {
    "email": "jordan@example.com",
    "name": "Jordan Lee",
    "status": "delivered",
    "lastSentAt": "2026-06-19T09:00:00.000Z"
  }
]

Read from {{ emails.data }}, take the recipient from each email's to field, map last_event into your status value, and use created_at as lastSentAt. If you fetched contacts, join on email address to fill name from first_name and last_name. Save the result as records.

Step 4: Load the board's existing items for matching

Add a Connector node in Direct mode on the Monday connector and select the list-items tool. Set boardId to your CRM board's ID and limit to a sensible page size (the default is 25). The response includes each item's id, name, and column_values (each with id, text, and value), plus a cursor for paging through larger boards. Store this as boardItems. You will scan {{ boardItems }} for an item whose email column text equals the record's email to decide update versus create.

Step 5: Loop over records and branch on match

Add a Loop node in ForEach mode over {{ records }} so each engagement record is handled one at a time as {{ record }}. Inside the loop, add a Condition node that checks whether the current {{ record.email }} already exists among the board items you loaded in Step 4. Route the true branch (a match was found, capture its item ID) to the update step, and the false branch (no match) to the create step.

Step 6: Update matched items on Monday

On the Condition's true branch, add a Connector node in Direct mode on the Monday connector with the update-item tool. Provide boardId, the matched itemId, and a columnValues object keyed by your board's column IDs. Monday expects column values as JSON keyed by column ID, for example:

{
  "status": { "label": "{{ record.status }}" },
  "date4": { "date": "{{ record.lastSentAt }}" }
}

Replace status and date4 with the real column IDs from your board. This refreshes the engagement status and last-send date on the existing CRM item without creating a duplicate.

Step 7: Create items for new contacts

On the Condition's false branch, add a Connector node in Direct mode on the Monday connector with the create-item tool. Set boardId, the item name (use {{ record.name }}, falling back to {{ record.email }}), an optional groupId to drop new contacts into a specific group, and a columnValues object that includes the email column plus the same status and date columns:

{
  "email_col": { "email": "{{ record.email }}", "text": "{{ record.email }}" },
  "status": { "label": "{{ record.status }}" },
  "date4": { "date": "{{ record.lastSentAt }}" }
}

Again, swap in your real column IDs. After this branch, the loop continues to the next record, so a single scheduled run updates everyone it can match and onboards everyone it cannot.

Tips

  • Keep the schedule window and your Resend fetch in sync: if you run daily, only act on emails whose created_at is within the last day so each run does focused, predictable work.
  • For boards with more items than one page, use the cursor returned by list-items to page through them before matching, so an unmatched record is genuinely new and not just on a later page.
  • Match email addresses case-insensitively in your Transform and Condition logic, since Resend and Monday may store the same address with different casing.
  • You can ask Miraxa, the intelligent layer across your automation, to scaffold this on the canvas with a prompt like "Add a Loop over {{ records }} with a Condition that checks if the email exists in {{ boardItems }}, then connect the true branch to a Monday update-item node," then fine-tune the column IDs in the properties panel.

Common Pitfalls

  • Column titles are not column IDs. The columnValues object for create-item and update-item must be keyed by each column's ID, not its display title. Read the IDs from list-items or get-board first.
  • Duplicate items from skipped matching. If you create items without first loading boardItems and checking for an existing email, every run inserts new rows. The match-then-branch design in Steps 4 to 7 is what keeps runs idempotent.
  • Status label drift. Monday status columns only accept labels that already exist on the board. Map Resend's last_event values onto labels your board defines, or new values will be rejected.
  • Timezone confusion. The Schedule cron runs in the IANA timezone you set, while Resend timestamps are in UTC. Format dates consistently before writing them to a Monday date column.

Testing

Before turning on the schedule, validate on a small scope. Temporarily cap the Resend fetch to a handful of recent emails and point the workflow at a test board or a test group on your real board. Use the Run button to trigger it manually, then open the execution log to confirm the Transform produced clean records, the Condition routed known contacts to update-item and new ones to create-item, and the resulting Monday items show the expected status and date. Run it a second time and confirm the same items are updated in place rather than duplicated, then enable the Schedule trigger.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.