4 min

Teams

Daily Lemlist Task Reminders in 1:1 Teams Chats with n8n

At Dolist, Lemlist prospecting sequences generate manual tasks (call, LinkedIn message, profile visit) that nobody sees, because nobody lives in Lemlist. I built a small n8n workflow that sends each rep, every morning, a 1:1 Teams message listing their tasks for today and tomorrow.

The problem

The reps’ real work tool is Teams. The result: Lemlist tasks piling up over several days and only surfacing at the weekly meeting, well past their due date. It’s not a discipline problem, it’s a channel problem.

Lemlist’s native options didn’t cover the need:

  • Emails are about campaign health (disconnected mailbox, bounces, campaign end), not tasks.
  • The Slack integration is the only task-related channel, but the team is on Teams, it only covers tasks triggered by lead activity (reply, click), not “Manual task” or “Call” tasks set in a sequence, and it notifies task by task instead of sending a morning summary.

What I built

flowchart TD
    A["Schedule Trigger\n0 7 * * 1-5 (weekdays, 7am Paris)"] --> B["HTTP Request\nGET api.lemlist.com/api/tasks\nfilter dueDate = today -> tomorrow"]
    B --> C["Code: group by rep\nfilter + group + format the message"]
    C --> D{"Switch on Lemlist userId"}
    D --> E["Teams 1:1 Rep A"]
    D --> F["Teams 1:1 Rep B"]
    D --> G["Teams 1:1 Rep C"]
    D --> H["Teams 1:1 Rep D"]
  • Trigger: cron 0 7 * * 1-5, timezone Europe/Paris. The reminder lands before the workday starts, never on weekends.
  • API call: GET https://api.lemlist.com/api/tasks with a dueDate filter from today to tomorrow. The two-day window avoids missing a task that straddles the date change. The API only filters by date, so everything else happens in the next node.
  • Code node: the heart of the workflow. It normalizes the response, keeps tasks with an empty or pending status, excludes the system task "Out of office detected", groups by userId and builds the message: one icon per type (📞 call, 💬 LinkedIn message, 👀 profile visit…), the first ten tasks marked “today” or “tomorrow”, then ...and N more.
  • Switch + Teams: one hardcoded rule per Lemlist userId, each wired to a Microsoft Teams node (chatMessage) targeting the 1:1 chat between the rep and the workflow’s technical account.

Since the shape of the Lemlist response (raw array or a results/tasks/data/items object) isn’t guaranteed, a small defensive function prevents a silent failure:

function toArray(x) {
  if (Array.isArray(x)) return x;
  if (x && typeof x === 'object') {
    for (const key of ['results', 'tasks', 'data', 'items']) {
      if (Array.isArray(x[key])) return x[key];
    }
  }
  return [];
}

The "Out of office detected" filter was added after seeing these tasks clutter the first test message.

The limits

Unmapped reps fall into the void

The Switch only knows four userIds. A task belonging to a fifth rep, or with no userId (key 'non_assigne' in the code), matches no rule and has no output: the message is lost with no visible error. Adding a rep means editing the Switch and creating a Teams node.

  • No link to the task. The rep has to reopen Lemlist to act.
  • No follow-up on overdue tasks. An unhandled task simply drops out of the window once its date has passed.
  • An inconsistency between branches. Three Teams nodes read $('Grouper par commercial').item.json.message, the fourth reads $json.message and also sets contentType: html. Same result today, but a real bug waiting to happen if branches are ever merged.

To redo: replace the Switch with a lookup table (n8n Data Table) plus a fallback branch for unknown userIds, add a link to each task if the API exposes it, and harmonize the Teams node expressions.

Takeaways

This workflow does nothing spectacular: it moves information that already existed to the channel where it gets seen. In RevOps, that’s often where the value is, in choosing the channel more than in the technique. The hardcoded mapping is fine for four people, it needs rethinking before scaling.

The same routing pattern (one Switch per recipient, one Teams node per branch) was later reused elsewhere: see Generating LinkedIn Posts with AI via n8n.

Read next

n8nAutomatically Enriching Lemlist Contacts with Apollo via n8nCRM + ERPFrom Weekly Recap to Sales Reporting: Requests, Quotes and Revenue Linked to CRM and ERP4AI Detection of Business Signals: Building a Useful RevOps System