Tutorials / Backend integrations / Marketing email with Loops
📝 Written ● Beginner Updated 2026-05-13

Marketing email with Loops

Newsletters, onboarding sequences, product announcements, "we miss you" win-backs. Loops is built for SaaS lifecycle email — different problem from transactional senders like Resend or Postmark.

Pick Loops when

0
  • Pick Loops when — you want a marketing email tool that doesn't look like Mailchimp from 2008. Drag-and-drop sequences, an audience filter you can actually understand, a visual editor that produces clean HTML.
  • AlternativesCustomer.io (more powerful, more complex), Intercom (CRM + chat + email bundle), Userlist (similar shape to Loops, cheaper), Buttondown (newsletter-only, markdown-first).
  • Don't use Loops for — password resets, magic links, receipts, OTP codes. Those go through a transactional sender (Postmark / Resend / SES). Mixing them tanks deliverability on both.
  • Sign upapp.loops.so/register. Free tier: 1,000 contacts, unlimited emails. No credit card.

Add and verify your sending domain

1

In Loops dashboard → Settings → Sending domain. Type the domain you want emails to come from (e.g. mail.yourapp.com — use a subdomain so marketing email doesn't tank your root domain's reputation).

Loops shows you 3 DNS records to add: an MX, a TXT (SPF), and a CNAME (DKIM). Paste them into your DNS provider — Cloudflare, Namecheap, general DNS guide.

Click Verify. Loops checks every minute — should turn green within 5–30 minutes. If it's stuck after an hour, your DNS provider is slow; check with dig CNAME loops._domainkey.mail.yourapp.com.

Tip: Pre-warm. Send a few campaigns to real engaged subscribers before blasting your full list. Cold domains get filtered to spam.

Get your API key

2

Settings → API → click Generate API key. Copy it once — Loops won't show it again. Store in .env as LOOPS_API_KEY.

API docs: loops.so/docs/api-reference.

Sync contacts from your app

3

Every signup, every plan change, every cancellation — push the event to Loops. That's the only way segments stay accurate.

Install the SDK:

npm install loops

On signup:

import { LoopsClient } from "loops";
const loops = new LoopsClient(process.env.LOOPS_API_KEY);

await loops.contacts.create({
  email: user.email,
  firstName: user.firstName,
  userGroup: "trial",            // for segmentation
  source: "website",
  signupDate: new Date().toISOString(),
});

On plan upgrade:

await loops.contacts.update({
  email: user.email,
  userGroup: "pro",
  plan: "pro_monthly",
});

On cancellation:

await loops.contacts.update({
  email: user.email,
  userGroup: "churned",
  churnedAt: new Date().toISOString(),
});

Full schema: Create contact, Update contact.

Send a one-off campaign (newsletter)

4

Dashboard → Campaigns → New campaign. Drag blocks: text, image, button, divider. Loops generates email-client-safe HTML — no escape-into-iframe nonsense.

Audience: filter by any property you've synced. userGroup = "pro". signupDate > 30 days ago. plan = "free" AND lastLogin < 14 days ago.

Preview in 6 email clients (Gmail, Outlook, iOS Mail, dark mode, etc) before sending. Loops bundles Litmus-style previews into the editor.

Hit Send or schedule for later. Tracking opens/clicks is on by default.

Build a lifecycle sequence (loop)

5

"Loops" are Loops's word for drip campaigns. Loops → New loop → pick a trigger:

  • Contact added — onboarding sequence
  • Property changed — e.g. plan becomes "churned" → win-back sequence
  • Event sent — your app fires a custom event via the SDK

Drag email blocks onto the canvas. Add wait steps ("wait 2 days"). Add conditional branches ("if hasShipped = true, skip"). Save → activate.

Trigger from your app code:

// Loops loops can also be triggered via event
await loops.events.send({
  email: user.email,
  eventName: "completedOnboarding",
});

Common failures

6
  • Emails land in Gmail Promotions tab — that's actually correct for marketing email. Promotions ≠ spam. Don't try to escape it with workarounds; Gmail will eventually re-classify if users engage.
  • Spam folder — check mail-tester.com. Below 8/10 = fix SPF/DKIM/DMARC + content. If your DMARC isn't set, Loops won't even use the domain.
  • Sync drift — your DB has a user but Loops doesn't. Cause: signup call to Loops API failed and you didn't retry. Wrap in try/catch + log; add a daily reconcile job pulling new users from DB and upserting to Loops.
  • "Unsubscribe" not honored — Loops adds a footer link automatically. If users complain they still get email, check whether they unsubscribed from marketing only — your transactional sender (Postmark/Resend) is separate. Some users want only one.

Pricing reality

7
  • Free — 1,000 contacts, unlimited sends. Loops branding in footer.
  • Pro — $49/mo for 2,500 contacts, removes branding, A/B testing, advanced analytics. Each tier above adds contacts.
  • API rate limit — 10 req/sec on free, higher on paid. Batch your sync if you have a large user list to backfill.
  • Why pay vs. Mailchimp — UI is dramatically better (Mailchimp last redesigned in 2017). Audience filters use plain English. Sequences (Loops) are the headline feature; Mailchimp's "Customer Journeys" feel like 2014.

Pricing page: loops.so/pricing.

Official references

8
Don't mix marketing and transactional. Sending a "we miss you" win-back through your Postmark account flags Postmark's IP reputation. Sending a password reset through Loops gets it filtered. Two senders, two domains (or subdomains), zero crossover.