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.
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.
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.
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.
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.
"Loops" are Loops's word for drip campaigns. Loops → New loop → pick a trigger:
plan becomes "churned" → win-back sequenceDrag 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",
});
Pricing page: loops.so/pricing.