ESP: Customer.io / Courier7 min read

Push delivered. SMS delivered. Email in Junk.

Customer.io and Courier ship push, SMS and email from one workflow. Push and SMS either arrive or they do not. Email has a third state that neither platform detects: delivered-but-filed-in-spam. Seeds find it.

Customer.io and Courier are the two leading multi-channel orchestration tools. You design a workflow once and it fans out to push, SMS, in-app, Slack and email. Observability on push and SMS is binary: either the carrier accepted the message or it rejected it. Email has a third, nastier state: accepted by the provider, silently filed into Junk or Promotions. Your multi-channel dashboard says “delivered” and the user never sees the message.

TL;DR

Add seed addresses as contacts in Customer.io or Courier, target a filter that delivers only the email leg to seeds, and run that alongside your real multi-channel workflow. Push/SMS/in-app stay real-user-only; email placement gets continuous per-provider monitoring.

Why multi-channel platforms hide email problems

A multi-channel workflow is typically designed as “reach-the-user-on-any-channel”. The UI celebrates reach: 100% of your users got something. The problem is that for a user who has push disabled and ignores SMS, the email is the channel that actually had to work — and that user has no idea they are missing your email because it landed in Junk.

Customer.io's metrics and Courier's logs both show email as “delivered” if the SMTP 250 came back. They cannot see folder. Push and SMS have delivery receipts with finer granularity — and that creates a false sense that the whole workflow is instrumented. It is not. Email is the unlit room.

Design pattern: email-only seed branch

The anti-pattern is sending push + SMS + email to seed addresses — seeds are email mailboxes, they cannot receive push or SMS and the workflow will error or silently drop those legs. The clean pattern is a branch in the workflow that filters channels per audience.

  1. Tag seeds clearly. Add an attribute is_seed (or a segment membership) on every seed contact. In Customer.io use traits; in Courier use recipient profile fields.
  2. Branch the workflow. Add a conditional split on is_seed == true. The seed branch delivers only the email channel. The real-user branch delivers the full multi-channel experience.
  3. Share the email content. Both branches point at the same email template. The seed's placement reflects exactly what a real user sees.
  4. Read per-provider placement. The placement-check tool shows you per-provider folder within minutes of the workflow firing.

Customer.io: gating channels with Liquid

Customer.io uses Liquid for conditions. Gating push and SMS so seeds only receive email:

{%- comment -%}
  Only deliver Push if this is NOT a seed contact.
  Seeds are email-only; attempting push will error.
{%- endcomment -%}

{% if customer.is_seed %}
  {% abort_message "Skipping Push for seed contact" %}
{% endif %}

Drop that into the push channel's pre-send Liquid (or the “Stop Sending” condition). Repeat for SMS. The email channel has no filter and delivers normally. Seeds traverse the workflow end-to-end, but only the email leg actually sends.

Courier: channel routing per profile

Courier's routing lets you express the same rule via channel selection:

{
  "message": {
    "to": { "user_id": "seed_gmail_01" },
    "template": "onboarding-day-1",
    "routing": {
      "method": "all",
      "channels": ["email"]
    },
    "data": { "is_seed": true }
  }
}

Seeds get sent with routing.channels: ["email"]; real users get the default multi-channel routing. Same template, same substitution data, same delivery pipeline.

Per-campaign seed monitoring at multi-channel scale

Multi-channel campaigns fire at high volume with many entry points. Putting seeds on every single message will flood your inbox; the right model is sampling plus pre-flight.

  • Pre-flight seed before launching a new workflow. Before turning the workflow on for real users, run it with only the seed segment as the audience. Read email placement. Fix any Spam results before green-lighting.
  • Sampled seed on running workflows. Add seeds to 1–5% of triggers on long-running lifecycle workflows. Low enough to be invisible in cost, high enough to catch drift within a day.
  • Incident seed. When customer support flags “I never got the email”, fire the workflow manually against the seed segment and check placement now, not two days later when Customer.io logs finally surface.
Get 20+ seed addresses free

The free Inbox Check tool generates 20+ fresh seed addresses per test across Gmail, Outlook, Yahoo, Mail.ru, Yandex, ProtonMail and more. No signup, no credit card.

→ Run a free test now

What multi-channel dashboards miss

Customer.io's Delivery report and Courier's Logs view are excellent at what they track. What they do not track:

  • Folder placement. Both platforms see SMTP 250 as “delivered”. Gmail Promotions, Spam and Primary all look identical from the platform's view.
  • Per-provider asymmetry. A campaign may land Primary on Gmail and Junk on Outlook. Neither platform surfaces this unless you add seeds that span both.
  • Deliverability drift over time. Yesterday's onboarding email was Primary; today it slid to Promotions. Only a seed monitor watching day-over-day placement will detect the drift early.
  • Authentication alignment. A DKIM signature that passes verification but does not align with the From: domain will still show as “delivered”. Seeds in an authentication-aware provider (like SendForensics-style headers view) expose it.

Common mistakes multi-channel teams make

  • Adding seeds to push/SMS audiences. Seeds are email addresses. Pushing to a seed contact will either error or silently drop, polluting your delivery metrics.
  • Forgetting to branch at workflow level. Seeding at the audience level without a channel filter means seeds trigger push and SMS nodes too — and those nodes error. Always split on is_seed at the workflow entry.
  • Treating a push delivery receipt as workflow success. Your push partner returns “delivered”, so the workflow looks healthy. Meanwhile 30% of your email leg is in Junk and your re-engagement curve is quietly dying.
  • One-off pre-flight only. Running a seed before the launch is table stakes. The interesting signal is drift over weeks — keep sampled seeds on continuously.

Frequently asked questions

Will adding seed contacts to Customer.io affect my audience size billing?

Yes. Customer.io bills on audience size. 20 seeds is negligible on most plans; on a tight tier, verify before importing. You can keep seeds in a segment that is excluded from billable audience counts via the dashboard filters.

Do Courier seed messages count against my monthly message quota?

Yes. Each seeded email is one Courier message. Sampling (1% of triggers include seeds) is the right control lever for cost at high volume.

Can I branch on is_seed inside a Customer.io Campaign vs Broadcast?

Yes in both. Campaigns support conditional sends based on attributes; Broadcasts support audience filters that can include or exclude the seed segment. For deliverability testing, include seeds in broadcasts and branch per channel.

What about in-app / Slack channels in the workflow?

Same principle as push/SMS: seeds cannot receive them, so gate those channels on is_seed == false. Seeds travel the workflow to deliver only the email leg. In-app placement is not a concept, so there is nothing to test there.
Related reading

Check your deliverability across 20+ providers

Gmail, Outlook, Yahoo, Mail.ru, Yandex, GMX, ProtonMail and more. Real inbox screenshots, SPF/DKIM/DMARC, spam engine verdicts. Free, no signup.

Run Free Test →

Unlimited tests · 20+ seed mailboxes · Live results · No account required