Resend is the modern, developer-focused email API: TypeScript SDK, clean REST endpoints, straightforward webhooks. Paired with React Email it lets you write email templates as React components and preview them in a local dev server. That workflow is a massive quality-of-life upgrade over editing HTML strings in .hbs files — but the preview server only answers one question: does this look right? It does not answer the more important one: will Gmail put this in Primary or Promotions?
Add seed addresses as a bcc array on the Resend emails.send() call. Your React Email template renders identically for real recipients and seeds. The seed results fill the gap the local preview cannot cover — real folder placement per provider.
Why the Resend workflow needs a seed layer
React Email's local preview renders your template with dummy data, inline-styles everything, and gives you a visual diff. What it cannot render is:
- Gmail's classifier. The Promotions vs Primary call is made by Google on receipt, using headers, link density, image-to-text ratio, and sender reputation. No local preview can simulate this.
- Outlook's junk filter. Outlook looks at authentication alignment, sender-domain reputation and content signals. Again, impossible locally.
- Mobile-client rendering quirks. The preview shows desktop Chrome. Gmail iOS, Outlook Android, Apple Mail on a Watch — all render differently. Real seed screenshots catch issues the preview would never surface.
The one-array-entry change
Resend's emails.send() accepts bcc as a string or string array. Your existing React Email send looks like this:
import { Resend } from 'resend';
import { WelcomeEmail } from '@/emails/welcome';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendWelcome(user: { email: string; name: string }) {
const { data, error } = await resend.emails.send({
from: 'Acme <hello@acme.io>',
to: user.email,
subject: `Welcome to Acme, ${user.name}`,
react: <WelcomeEmail name={user.name} />,
});
if (error) throw error;
return data;
}The seeded version adds a single field:
export async function sendWelcome(user: { email: string; name: string }) {
const seeds = process.env.SEED_ADDRESSES?.split(',') ?? [];
const { data, error } = await resend.emails.send({
from: 'Acme <hello@acme.io>',
to: user.email,
bcc: seeds, // <- seed recipients
subject: `Welcome to Acme, ${user.name}`,
react: <WelcomeEmail name={user.name} />,
headers: { 'X-Entity-Ref-ID': 'welcome-v3' }, // optional tag
});
if (error) throw error;
return data;
}Resend fans out the bcc server-side. The React Email component renders once; the resulting HTML goes to both the real recipient and every seed address. Your template props, inlining pipeline and CSS stay identical — the seed just receives the exact same bytes the user does.
Centralise in one helper
Do not sprinkle bcc: seeds through 20 call sites. Wrap every Resend call in a helper that decides per-template whether to seed:
type Template = 'welcome' | 'reset' | 'invoice' | 'digest';
const SEED_TEMPLATES: Record<Template, 'always' | 'sample' | 'never'> = {
welcome: 'always',
reset: 'always',
invoice: 'always',
digest: 'sample',
};
function seedsFor(template: Template): string[] {
const policy = SEED_TEMPLATES[template];
const all = process.env.SEED_ADDRESSES?.split(',') ?? [];
if (policy === 'always') return all;
if (policy === 'sample') return Math.random() < 0.05 ? all : [];
return [];
}
export async function sendTemplate<T extends Template>(
template: T,
to: string,
react: React.ReactElement,
subject: string,
) {
return resend.emails.send({
from: 'Acme <hello@acme.io>',
to,
bcc: seedsFor(template),
subject,
react,
tags: [{ name: 'template', value: template }],
});
}React Email preview vs seed test: they answer different questions
Both tools have their place. Keep them honest:
- Preview server answers: Does the component render without exploding, with the right copy, in the right layout? Use this in dev loop, storybook, PR reviews.
- Seed test answers: When Resend actually sends this through its MTA, which folder does Gmail/Outlook/Yahoo file it in, and what does it look like in iOS Gmail? Use this in staging and in production.
- Resend test mode (onboarding@resend.dev) answers: Does the API call succeed with my API key? It does not answer placement, because the test addresses route through Resend internals, not real providers.
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.
Domain warm-up on Resend with seeds
Resend gives you a fresh sending domain the moment you verify DNS. That domain has zero reputation. Shipping 10,000 welcome emails on day one from a fresh domain is a reliable way to land in Gmail Spam for a month. Seeds let you warm up intelligently:
- Day 1–3. Send only to seeds plus a handful of real internal users. Read placement; verify SPF/DKIM/DMARC align on the headers. Fix anything yellow.
- Day 4–10. Scale to real traffic at 100–500 sends/day. Continue seeding 100% of sends. Watch for drift (Primary rate should stay above 85% at Gmail).
- Day 11+. Ramp 2×/day until target volume. Keep seeds on — drop to sampling only after you have a week of clean placement above target volume.
Common mistakes with Resend seeding
- Using Resend's sandbox address as a seed. It does not measure placement. It only confirms the API call works.
- Seeding from an unverified domain. Resend will reject the send at the API. Verify the domain and wait for SPF/DKIM propagation first.
- Forgetting to gate seeds behind env. A developer cloning your repo does not need to trigger seeds on every local test. Default
SEED_ADDRESSESto empty in dev; set it only in staging/prod. - Treating React Email preview as deliverability proof. The preview confirms rendering, not placement. They are complementary, not a substitute.