Lemlist → Attio: outbound that actually shows up in the CRM

Most outbound teams run Lemlist as a parallel universe. Sequences fire, replies come in, the SDR copies the hot ones into the CRM (or doesn't). The CRM has a "contacted" field that's lying half the time. Leadership has no idea which segments work. We wire Lemlist directly into Attio via n8n. You build the list in Attio with all the filtering power that gives you — industry, stage, last activity, company size, any custom attribute. Enrollment into the right Lemlist campaign is automatic. Replies, opens, bounces, opt-outs: all mirrored back onto the Attio Person record with enough metadata that your reporting is actually trustworthy. The result is outbound that belongs to your CRM, not to a sidebar tool your next SDR will forget to check.

Direction

Attio ↔ Lemlist (bidirectional enrollment + reply sync)

Stack

Lemlist API, Attio API, n8n, Slack

The what

What this integration actually does

An Attio list membership change triggers enrollment in the corresponding Lemlist campaign via the Lemlist /api/campaigns/{id}/leads endpoint. Lemlist fires webhooks back on EMAIL_SENT, EMAIL_OPENED, EMAIL_CLICKED, EMAIL_REPLIED, EMAIL_BOUNCED, and OPT_OUT. Each event becomes a dated Activity on the Attio Person record. Positive replies (detected by thread continuation, not keyword matching) generate a Slack alert to the owner. Opt-outs set a permanent suppression field on the Person so no future workflow can re-enroll them. Bounces update the email validity field so you know which addresses are dead.

The how

How we build it

  1. 1

    Design the Attio lists that map to Lemlist campaigns — by ICP segment, by pain, by source, by company size. One list per campaign keeps the mapping clean.

  2. 2

    Build the enrollment workflow in n8n: Attio webhook fires on list membership change → n8n calls POST /api/campaigns/{id}/leads with the email and any custom variables. Removal from the list triggers DELETE /api/campaigns/{id}/leads/{email}.

  3. 3

    Register Lemlist webhooks on EMAIL_REPLIED, EMAIL_BOUNCED, OPT_OUT, and INTERESTED. Each event maps to an Attio Activity type and a field update (in_lemlist, last_reply_at, lemlist_status).

  4. 4

    Add a sentiment layer: thread length and continuation signals distinguish real positive replies from auto-replies. Hot replies ping the Attio record owner in Slack.

  5. 5

    Build the reporting view in Attio: reply rate by list segment, opt-out rate by campaign, meetings booked per 1000 sent. All data lives on the Person record so cross-object reports work.

  6. 6

    Wire the 90-day recycle: contacts that reached sequence end without a reply move to a nurture list automatically. No manual triage.

Under the hood

What lives inside the pipeline

  • Enrollment workflow: Attio list membership → n8n → Lemlist campaign API. Handles both add and remove.
  • Reply sync: Lemlist webhook → n8n → Attio Activity (reply text, date, sentiment tag, thread length).
  • Opt-out suppression: permanent flag on the Person record, checked by every future enrollment workflow before touching the contact.
  • Bounce handling: email validity field update on the Person so you know which addresses are dead before the next campaign.
  • Hot reply Slack alert: fires to the record owner with a direct link to the Attio Person and a one-line reply summary.
  • Recycle workflow: cold leads re-enter a nurture list 90 days after sequence end, with a "re-engagement" tag so reporting stays clean.

Hard-earned lessons

What we learned the hard way

  • Lemlist's campaign status UI lies. A campaign that looks "active" via the toggle can still be in draft state — the API returns status: "draft" and silently swallows leads you POST. Always check GET /api/campaigns/{id} before assuming enrollment worked.
  • The attioOwner field in Lemlist only accepts usr_xxx IDs, not display names. If you pass a name, Lemlist silently drops the assignment. Resolve the Lemlist user ID at setup time and store it on the Attio workspace member record.
  • Email casing: Lemlist and Attio occasionally disagree on canonical case (john@co.com vs John@Co.com). Normalize to lowercase on the n8n side before every API call or your duplicate detection will miss matches.
  • Keyword-based positive reply detection misses half the real replies and fires on 40% of auto-replies. Thread continuation length is a far better signal: if the reply is longer than the original email, it's almost always a real response.
  • Never re-enroll someone who opted out, even in a different campaign. The suppression field must be checked globally, not per-campaign. One missed check and you're a GDPR incident.
  • n8n is the right architecture here. We tried building this in native Attio Automations but enrichment chains that hop through record references render empty at runtime — the values exist in the UI but the automation receives null. Any logic that needs to traverse Company → Team → Owner belongs in n8n.

Case study

Gym SaaS (B2B)

Problem

The SDR ran outbound from spreadsheets, copying hot replies into the CRM manually. Reporting showed zero visibility into which segments converted. Hot replies sat unread over weekends.

Solution

Four n8n workflows: outbound enrollment (Attio list → Lemlist), reply sync (Lemlist webhook → Attio Activity), opt-out suppression, and 90-day recycle. All triggered by Attio list membership with Slack alerts on positive replies.

Outcome

Outbound operates end-to-end from Attio. Leadership sees real reply-rate numbers by ICP segment. The SDR responds to hot replies and nothing else. Zero spreadsheet-juggling.

FAQ

Questions we get

Yes, the n8n architecture is identical. The webhook events and API endpoints differ slightly, but the pattern — Attio list drives enrollment, tool fires webhooks, n8n writes Activities — ports directly. Lemlist is the reference build because it's what we've shipped in production.

We set a permanent suppression field on the Attio Person (opt_out: true) that every enrollment workflow checks before calling the Lemlist API. It applies across all campaigns globally, not per-sequence.

Both. Nurture is a campaign with a longer cadence. We've seen clients run cold outbound, warm follow-up, and customer onboarding sequences all through the same Attio → Lemlist pipeline, with different list filters driving each one.

We typically write: in_lemlist (boolean), lemlist_status (enrolled / replied / bounced / opted_out / completed), last_contacted_at (date), last_reply_at (date), and a reply_sentiment tag. The Activity log captures the full reply thread. The exact field set depends on what your reporting needs.

Respond to hot replies. That's it. List building runs in Attio, enrollment is automatic, replies and opt-outs update the CRM without any manual action, and the recycle workflow re-engages cold leads on schedule.

Want this running on your Attio?

Book a free 30-min call. We'll map your use case to what we've already shipped and tell you whether this fits - honestly.

Book a 30-min call